I can produce working image for my python app with following simple Dockerfile
:
FROM python:3.7
WORKDIR /myapp
COPY Pipfile* ./
RUN pip install pipenv
RUN pipenv install --system --deploy
COPY src .
CMD ["python3", "app.py"]
However, it will produce ~1 GB image, which can contain temporary files, and is heavy to deploy. And I only need full python image for building purposes. My app can successfully run on alpine variant, so I can make two-pass Dockerfile
:
FROM python:3.7 as builder
COPY Pipfile* ./
RUN pipenv lock --requirements > requirements.txt
RUN python3 -m venv /venv
RUN /venv/bin/pip install --upgrade pip
RUN /venv/bin/pip install -r requirements.txt
FROM python:3.7-alpine
COPY --from=builder /venv /venv
WORKDIR /myapp
COPY src .
CMD ["/venv/bin/python3", "app.py"]
So far so good, it also works, being 6 times smaller. But this scheme was considered as some "stub", having some drawbacks:
COPY --from=builder
steppipenv
but needs also pip
for installing (+1 extra step, pipenv lock
+pip install
is always slower than just pipenv install
)/venv
, which is to be avoided inside a containerHow to combine these two approaches, to get lightweitht alpine-based image with pipenv
, lacking mentioned drawbacks?
Or can you offer your production Dockerfile
ideas?
The problem comes when you need things like ciso8601
, or some libraries, requiring build process. Build tools are not "incorporated" into the both slim
and alpine
variants, for low-size footprint.
So to install deps, you'll have to:
And do that 3 actions inside a single RUN
layer, like following:
FROM python:3.7-slim
WORKDIR /app
# both files are explicitly required!
COPY Pipfile Pipfile.lock ./
RUN pip install pipenv && \
apt-get update && \
apt-get install -y --no-install-recommends gcc python3-dev libssl-dev && \
pipenv install --deploy --system && \
apt-get remove -y gcc python3-dev libssl-dev && \
apt-get autoremove -y && \
pip uninstall pipenv -y
COPY app ./
CMD ["python", "app.py"]
RUN
commands would not delete data from layers, and would result in ~500MiB image. That's docker specifics.So that would result in perfectly working ~200MiB sized image, which is
python:3.7
, (that is >1.0GiB)At the time, we're fine with slim
(debian buster
) build variants, preferring slim
over alpine
(for most compatibility). If you're really up to further size optimization, I'd recommend you to take a look at some excellent builds of these guys: