Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make lightweight docker image for python app with pipenv

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:

  • It has unnesesary extra COPY --from=builder step
  • It does not utilizes pipenv but needs also pip for installing (+1 extra step, pipenv lock+pip install is always slower than just pipenv install)
  • It does not install system-wide, but into /venv, which is to be avoided inside a container
  • Minor: Build pollutes intermediate-images cache more, and requires downloading both image variants..

How to combine these two approaches, to get lightweitht alpine-based image with pipenv, lacking mentioned drawbacks?

Or can you offer your production Dockerfile ideas?

like image 827
xakepp35 Avatar asked Oct 09 '19 08:10

xakepp35


2 Answers

I am using micropipenv for the job, which describes itself as

A lightweight wrapper for pip to support requirements.txt, Pipenv and Poetry lock files or converting them to pip-tools compatible output. Designed for containerized Python applications but not limited to them.

An image created from it would look like the following. Since the alpine base image lacks a toml parser we have to use the version of micropipenv that includes the toml extras (micropipenv[toml] instead of micropipenv).

FROM python:3.9-alpine

WORKDIR /myapp
COPY Pipfile Pipfile.lock ./

RUN \
  # Install dependencies
  && pip install --no-cache-dir micropipenv[toml] \
  && micropipenv install --deploy \
  && pip uninstall -y micropipenv[toml]

COPY src .
CMD ["python3", "app.py"]
like image 73
ofhouse Avatar answered Sep 22 '22 23:09

ofhouse


How about,

FROM python:3.7-alpine

WORKDIR /myapp

COPY Pipfile* ./

RUN pip install --no-cache-dir pipenv && \
    pipenv install --system --deploy --clear

COPY src .
CMD ["python3", "app.py"]
  1. It utilises the smaller Alpine version.
  2. You won't have any unnecessary cache files left over using --no-cache-dir option for pip and --clear option for pipenv.
  3. You also deploy outside of venv.

You can also add && pip uninstall pipenv -y after pipenv install --system --deploy --clear in the same RUN command to eliminate space taken by pipenv if that extra image size bothers you.

like image 21
Jay Avatar answered Sep 25 '22 23:09

Jay