|
1 | | -# using ubuntu LTS version |
2 | | -FROM ubuntu:22.04 AS builder-image |
| 1 | +# SOURCE: https://github.com/alexdmoss/distroless-python |
| 2 | + |
| 3 | +# several optimisations in python-slim images already, benefit from these |
| 4 | +FROM python:3.10.7-slim-bullseye AS builder-image |
3 | 5 |
|
4 | 6 | # avoid stuck build due to user prompt |
5 | 7 | ARG DEBIAN_FRONTEND=noninteractive |
6 | 8 |
|
7 | | -RUN apt-get -qq update \ |
8 | | - && apt-get -qq install \ |
9 | | - --no-install-recommends -y \ |
10 | | - aptitude \ |
11 | | - autoconf \ |
12 | | - automake \ |
13 | | - build-essential \ |
14 | | - ca-certificates \ |
15 | | - curl \ |
16 | | - git \ |
17 | | - locales \ |
18 | | - libbz2-dev \ |
19 | | - libffi-dev \ |
20 | | - libncurses-dev \ |
21 | | - libreadline-dev \ |
22 | | - libsqlite3-dev \ |
23 | | - libssl-dev \ |
24 | | - libtool \ |
25 | | - libxslt-dev \ |
26 | | - libyaml-dev \ |
27 | | - python3 \ |
28 | | - python3-dev \ |
29 | | - python3-pip \ |
30 | | - sqlite3 \ |
31 | | - unixodbc-dev \ |
32 | | - unzip \ |
33 | | - && rm -rf /var/lib/apt/lists/* |
| 9 | +# setup standard non-root user for use downstream |
| 10 | +ARG USERNAME="appuser" |
| 11 | +ARG USER_GROUP=${USERNAME} |
| 12 | + |
| 13 | +RUN groupadd ${USER_GROUP} |
| 14 | +RUN useradd -m ${USERNAME} -g ${USER_GROUP} |
| 15 | + |
| 16 | +USER ${USERNAME} |
| 17 | +ENV HOME="/home/${USERNAME}" |
| 18 | + |
| 19 | +ENV PATH="$HOME/.local/bin:$PATH" |
| 20 | + |
| 21 | +# setup user environment with good python practices |
| 22 | +USER ${USERNAME} |
| 23 | +WORKDIR /home/${USERNAME} |
34 | 24 |
|
35 | 25 | # Set locale |
36 | | -RUN locale-gen en_US.UTF-8 |
37 | 26 | ENV LANG=en_US.UTF-8 |
38 | 27 | ENV LANGUAGE=en_US:en |
39 | 28 | ENV LC_ALL=en_US.UTF-8 |
40 | 29 |
|
41 | | -ARG USERNAME=appuser |
| 30 | +# poetry for use elsewhere as builder image |
| 31 | +RUN pip install --upgrade pip \ |
| 32 | + && pip install --no-cache-dir --upgrade virtualenv poetry |
| 33 | + |
| 34 | +COPY pyproject.toml poetry.lock ./ |
| 35 | +RUN poetry config virtualenvs.in-project true \ |
| 36 | + && poetry install |
| 37 | + |
| 38 | +# build from distroless C or cc:debug, because lots of Python depends on C |
| 39 | +FROM gcr.io/distroless/cc AS distroless |
| 40 | + |
| 41 | +# # arch: x86_64-linux-gnu / aarch64-linux-gnu |
| 42 | +# ARG CHIPSET_ARCH=aarch64-linux-gnu |
| 43 | + |
| 44 | +# # this carries more risk than installing it fully, but makes the image a lot smaller |
| 45 | +# COPY --from=builder-image /usr/local/lib/ /usr/local/lib/ |
| 46 | +# COPY --from=builder-image /usr/local/bin/python /usr/local/bin/python |
| 47 | +# COPY --from=builder-image /etc/ld.so.cache /etc/ld.so.cache |
| 48 | + |
| 49 | +# # required by lots of packages - e.g. six, numpy, wsgi |
| 50 | +# COPY --from=builder-image /lib/${CHIPSET_ARCH}/libz.so.1 /lib/${CHIPSET_ARCH}/ |
| 51 | + |
| 52 | +# non-root user setup |
| 53 | +ARG USERNAME="appuser" |
| 54 | +ARG ${PYTHON_VERSION:-3.10} |
42 | 55 | ENV HOME="/home/${USERNAME}" |
43 | | -ENV PATH="$HOME/.asdf/bin:$HOME/.asdf/shims:$PATH" |
44 | 56 |
|
45 | | -RUN useradd --create-home $USERNAME |
| 57 | +COPY --from=builder-image /bin/echo /bin/echo |
| 58 | +COPY --from=builder-image /bin/rm /bin/rm |
| 59 | +COPY --from=builder-image /bin/sh /bin/sh |
46 | 60 |
|
47 | | -# install asdf then python latest |
48 | | -RUN bash -c "git clone --depth 1 https://github.com/asdf-vm/asdf.git $HOME/.asdf \ |
49 | | - && echo '. $HOME/.asdf/asdf.sh' >> $HOME/.bashrc \ |
50 | | - && echo '. $HOME/.asdf/asdf.sh' >> $HOME/.profile" |
51 | | -RUN asdf plugin-add python \ |
52 | | - && asdf install python 3.10.7 \ |
53 | | - && asdf global python 3.10.7 |
| 61 | +RUN echo "${USERNAME}:x:1000:${USERNAME}" >> /etc/group |
| 62 | +RUN echo "${USERNAME}:x:1001:" >> /etc/group |
| 63 | +RUN echo "${USERNAME}:x:1000:1001::/home/${USERNAME}:" >> /etc/passwd |
54 | 64 |
|
55 | | -# TODO: test poetry via asdf |
56 | | -ENV POETRY_HOME="$HOME/.poetry" |
57 | | -RUN curl -sSL https://install.python-poetry.org | python3.10 - |
58 | | -ENV PATH "${POETRY_HOME}/bin:$PATH" |
| 65 | +ENV VENV="/opt/venv" |
| 66 | +COPY . /app |
| 67 | +COPY --from=builder-image "${HOME}/.venv" "$VENV" |
59 | 68 |
|
60 | | -WORKDIR $$HOME/app |
61 | | -COPY pyproject.toml poetry.lock ./ |
62 | | -RUN python3.10 -m venv /opt/venv |
| 69 | +ENV PATH="/app/.venv/bin:/app/.venv/lib/python${PYTHON_VERSION}/site-packages:$PATH" |
63 | 70 |
|
64 | | -# Install pip requirements |
65 | | -RUN . /opt/venv/bin/activate && poetry install |
| 71 | +# TODO: QA runner-image before removing shell |
| 72 | +# RUN rm /bin/sh /bin/echo /bin/rm |
66 | 73 |
|
67 | | -# TODO: dive + docker-slim |
68 | | -FROM ubuntu:22.04 AS runner-image |
| 74 | +# default to running as non-root, uid=1000 |
| 75 | +ARG USERNAME="appuser" |
| 76 | +USER ${USERNAME} |
69 | 77 |
|
70 | | -ARG USERNAME=appuser |
| 78 | +ARG PYTHON_VERSION=3.10 |
71 | 79 | ENV HOME="/home/${USERNAME}" |
72 | | -ENV VIRTUAL_ENV="/opt/venv" |
73 | | -ENV PATH="${VIRTUAL_ENV}/bin:$HOME/.asdf/bin:$HOME/.asdf/shims:$PATH" |
| 80 | +ENV VENV="/opt/venv" |
| 81 | +ENV PATH="$HOME/.local/bin:${VENV}/bin:${VENV}/lib/python${PYTHON_VERSION}/site-packages" |
74 | 82 |
|
75 | | -RUN useradd --create-home $USERNAME \ |
76 | | - && mkdir -p ${HOME}/app |
| 83 | +# TODO: not finding python |
| 84 | +# quick validation that python still works whilst we have a shell |
| 85 | +RUN python --version |
77 | 86 |
|
78 | | -COPY --chown=${USERNAME}:${USERNAME} . $HOME/app |
79 | | -COPY --from=builder-image --chown=${USERNAME}:${USERNAME} /opt/venv /opt/venv |
80 | | -COPY --from=builder-image --chown=${USERNAME}:${USERNAME} $HOME/.asdf $HOME/.asdf |
| 87 | +# standardise on locale, don't generate .pyc, enable tracebacks on seg faults |
| 88 | +ENV LANG C.UTF-8 |
| 89 | +ENV LC_ALL C.UTF-8 |
| 90 | +ENV PYTHONDONTWRITEBYTECODE 1 |
| 91 | +ENV PYTHONFAULTHANDLER 1 |
81 | 92 |
|
82 | | -# avoid stuck build due to user prompt |
83 | | -ARG DEBIAN_FRONTEND=noninteractive |
| 93 | +# ENTRYPOINT ["/usr/local/bin/python"] |
| 94 | + |
| 95 | +FROM distroless AS runner-image |
84 | 96 |
|
85 | | -RUN apt-get -qq update \ |
86 | | - && apt-get -qq install \ |
87 | | - --no-install-recommends -y \ |
88 | | - ca-certificates \ |
89 | | - curl \ |
90 | | - git \ |
91 | | - libsqlite3-dev \ |
92 | | - sqlite3 \ |
93 | | - && rm -rf /var/lib/apt/lists/* |
94 | | - |
95 | | -# Keeps Python from generating .pyc files in the container |
| 97 | +ARG ${PYTHON_VERSION:-3.10} |
| 98 | +ARG USERNAME=appuser |
| 99 | +ENV HOME="/home/${USERNAME}" |
| 100 | + |
| 101 | +COPY . /app |
| 102 | +COPY --from=distroless "${HOME}/.venv" "${HOME}/.venv" |
| 103 | + |
| 104 | +ENV PATH="$HOME/.local/bin:${HOME}/.venv/lib/python${PYTHON_VERSION}/site-packages" |
| 105 | + |
| 106 | +# keeps Python from generating .pyc files in the container |
96 | 107 | ENV PYTHONDONTWRITEBYTECODE=1 |
97 | 108 |
|
98 | | -# Turns off buffering for easier container logging |
| 109 | +# turns off buffering for easier container logging |
99 | 110 | ENV PYTHONUNBUFFERED=1 |
100 | 111 |
|
101 | | -# activate virtual environment |
102 | | -RUN python -m venv $VIRTUAL_ENV |
103 | | - |
104 | | -USER appuser |
| 112 | +# workers per core (https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker/blob/master/README.md#web_concurrency) |
| 113 | +ENV WEB_CONCURRENCY=1 |
105 | 114 |
|
106 | | -WORKDIR $HOME/app |
| 115 | +WORKDIR /app |
107 | 116 |
|
108 | 117 | # ENTRYPOINT ["python", "main.py"] |
109 | 118 | # CMD ["gunicorn", "-c", "config/gunicorn.conf.py", "main:app"] |
110 | | -CMD ["/bin/bash", "startup.sh"] |
111 | | -# CMD ["/bin/bash"] |
| 119 | +# CMD ["/bin/sh", "startup.sh"] |
| 120 | +CMD ["/bin/sh"] |
0 commit comments