|
1 | | -# using ubuntu LTS version |
2 | | -FROM ubuntu:22.04 AS builder-image |
| 1 | +# SOURCES |
| 2 | +# https://github.com/alexdmoss/distroless-python |
| 3 | +# https://gitlab.com/n.ragav/python-images/-/tree/master/distroless |
| 4 | + |
| 5 | +# full semver just for python base image |
| 6 | +ARG PYTHON_VERSION=3.10.7 |
| 7 | + |
| 8 | +# several optimisations in python-slim images already, benefit from these |
| 9 | +FROM python:${PYTHON_VERSION}-slim-bullseye AS builder-image |
3 | 10 |
|
4 | 11 | # avoid stuck build due to user prompt |
5 | 12 | ARG DEBIAN_FRONTEND=noninteractive |
6 | 13 |
|
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/* |
| 14 | +# setup standard non-root user for use downstream |
| 15 | +ARG USERNAME="appuser" |
| 16 | +ARG USER_GROUP=${USERNAME} |
| 17 | +ARG HOME="/home/${USERNAME}" |
| 18 | + |
| 19 | +RUN groupadd ${USER_GROUP} |
| 20 | +RUN useradd -m ${USERNAME} -g ${USER_GROUP} |
| 21 | + |
| 22 | +# setup user environment with good python practices |
| 23 | +USER ${USERNAME} |
| 24 | +WORKDIR ${HOME} |
| 25 | +ENV PATH="$HOME/.local/bin:$PATH" |
34 | 26 |
|
35 | 27 | # Set locale |
36 | | -RUN locale-gen en_US.UTF-8 |
37 | 28 | ENV LANG=en_US.UTF-8 |
38 | 29 | ENV LANGUAGE=en_US:en |
39 | 30 | ENV LC_ALL=en_US.UTF-8 |
40 | 31 |
|
41 | | -ARG USERNAME=appuser |
| 32 | +# poetry for use elsewhere as builder image |
| 33 | +RUN pip install --upgrade pip \ |
| 34 | + && pip install --no-cache-dir --upgrade virtualenv poetry |
| 35 | + |
| 36 | +COPY pyproject.toml poetry.lock ./ |
| 37 | +RUN poetry config virtualenvs.in-project true \ |
| 38 | + && poetry install |
| 39 | + |
| 40 | +# build from distroless C or cc:debug, because lots of Python depends on C |
| 41 | +FROM gcr.io/distroless/cc AS distroless |
| 42 | + |
| 43 | +# # arch: x86_64-linux-gnu / aarch64-linux-gnu |
| 44 | +# ARG CHIPSET_ARCH=aarch64-linux-gnu |
| 45 | + |
| 46 | +# # required by lots of packages - e.g. six, numpy, wsgi |
| 47 | +# COPY --from=builder-image /lib/${CHIPSET_ARCH}/libz.so.1 /lib/${CHIPSET_ARCH}/ |
| 48 | + |
| 49 | +# non-root user setup |
| 50 | +ARG USERNAME="appuser" |
| 51 | +ARG PYTHON_VERSION=3.10 |
42 | 52 | ENV HOME="/home/${USERNAME}" |
43 | | -ENV PATH="$HOME/.asdf/bin:$HOME/.asdf/shims:$PATH" |
44 | 53 |
|
45 | | -RUN useradd --create-home $USERNAME |
| 54 | +# import useful bins from busybox image |
| 55 | +COPY --from=busybox:uclibc /bin/ls /bin/ls |
| 56 | +COPY --from=busybox:uclibc /bin/rm /bin/rm |
| 57 | +COPY --from=busybox:uclibc /bin/sh /bin/sh |
| 58 | +COPY --from=busybox:uclibc /bin/find /bin/find |
| 59 | +COPY --from=busybox:uclibc /bin/which /bin/which |
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 | +ENV VENV="/opt/venv" |
| 62 | +COPY --chown=${USERNAME} . /app |
| 63 | +COPY --from=builder-image --chown=${USERNAME} "${HOME}/.venv" "$VENV" |
| 64 | +COPY --from=builder-image /usr/local/lib/ /usr/local/lib/ |
| 65 | +COPY --from=builder-image /usr/local/bin/python /usr/local/bin/python |
| 66 | +COPY --from=builder-image /etc/ld.so.cache /etc/ld.so.cache |
54 | 67 |
|
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" |
| 68 | +ENV PATH="/usr/local/bin:${HOME}/.local/bin:/bin:/usr/bin:${VENV}/bin:${VENV}/lib/python${PYTHON_VERSION}/site-packages:$PATH" |
59 | 69 |
|
60 | | -WORKDIR $$HOME/app |
61 | | -COPY pyproject.toml poetry.lock ./ |
62 | | -RUN python3.10 -m venv /opt/venv |
| 70 | +RUN echo "${USERNAME}:x:1000:${USERNAME}" >> /etc/group |
| 71 | +RUN echo "${USERNAME}:x:1001:" >> /etc/group |
| 72 | +RUN echo "${USERNAME}:x:1000:1001::/home/${USERNAME}:" >> /etc/passwd |
| 73 | + |
| 74 | +# standardise on locale, don't generate .pyc, enable tracebacks on seg faults |
| 75 | +ENV LANG C.UTF-8 |
| 76 | +ENV LC_ALL C.UTF-8 |
| 77 | +ENV PYTHONDONTWRITEBYTECODE 1 |
| 78 | +ENV PYTHONFAULTHANDLER 1 |
63 | 79 |
|
64 | | -# Install pip requirements |
65 | | -RUN . /opt/venv/bin/activate && poetry install |
| 80 | +# remove dev bins (need sh to run `startup.sh`) |
| 81 | +RUN rm /bin/find /bin/ls /bin/rm /bin/which |
66 | 82 |
|
67 | | -# TODO: dive + docker-slim |
68 | | -FROM ubuntu:22.04 AS runner-image |
| 83 | +FROM distroless AS runner-image |
69 | 84 |
|
| 85 | +ARG PYTHON_VERSION=3.10 |
70 | 86 | ARG USERNAME=appuser |
71 | 87 | ENV HOME="/home/${USERNAME}" |
72 | | -ENV VIRTUAL_ENV="/opt/venv" |
73 | | -ENV PATH="${VIRTUAL_ENV}/bin:$HOME/.asdf/bin:$HOME/.asdf/shims:$PATH" |
| 88 | +ENV VENV="/opt/venv" |
74 | 89 |
|
75 | | -RUN useradd --create-home $USERNAME \ |
76 | | - && mkdir -p ${HOME}/app |
77 | | - |
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 |
81 | | - |
82 | | -# avoid stuck build due to user prompt |
83 | | -ARG DEBIAN_FRONTEND=noninteractive |
| 90 | +ENV PATH="/usr/local/bin:${HOME}/.local/bin:/bin:/usr/bin:${VENV}/bin:${VENV}/lib/python${PYTHON_VERSION}/site-packages:$PATH" |
84 | 91 |
|
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 |
| 92 | +# keeps Python from generating .pyc files in the container |
96 | 93 | ENV PYTHONDONTWRITEBYTECODE=1 |
97 | 94 |
|
98 | | -# Turns off buffering for easier container logging |
| 95 | +# turns off buffering for easier container logging |
99 | 96 | ENV PYTHONUNBUFFERED=1 |
100 | 97 |
|
101 | | -# activate virtual environment |
102 | | -RUN python -m venv $VIRTUAL_ENV |
| 98 | +# workers per core (https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker/blob/master/README.md#web_concurrency) |
| 99 | +ENV WEB_CONCURRENCY=1 |
103 | 100 |
|
104 | | -USER appuser |
| 101 | +WORKDIR /app |
105 | 102 |
|
106 | | -WORKDIR $HOME/app |
| 103 | +USER ${USERNAME} |
107 | 104 |
|
108 | 105 | # ENTRYPOINT ["python", "main.py"] |
109 | 106 | # CMD ["gunicorn", "-c", "config/gunicorn.conf.py", "main:app"] |
110 | | -CMD ["/bin/bash", "startup.sh"] |
111 | | -# CMD ["/bin/bash"] |
| 107 | +# CMD ["/bin/sh", "startup.sh"] |
| 108 | +CMD ["/bin/sh"] |
0 commit comments