How to build multistage python with venv the smart way

5 min read
How to build multistage python with venv the smart way

The smartest way to create a multistage Dockerfile for a python application and be compatible with OpenShift non-root / arbitrary user is to use virtual environments.

FROM python:3.9-alpine3.13 as base

# in the builder, install build-base and build some python modules
FROM base as builder
RUN apk add --no-cache --virtual .build-deps build-base

# Always update pip
RUN pip install --upgrade pip

# Create an Virtual Environent
# and activate it Itamar style (see link to pythonspeed)
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

RUN pip install --no-cache-dir "uvicorn[standard]" gunicorn
ADD ./requirements.txt /
RUN pip install --no-cache-dir -r /requirements.txt

# Then in the runner, copy in the virtual environment and the app with config
FROM base
COPY --from=builder /opt/venv /opt/venv
COPY ./docker-scripts/start.sh ./docker-scripts/gunicorn_conf.py /
COPY ./app/ /app/

RUN chmod +x /start.sh

WORKDIR /app/

ENV PYTHONPATH=/app:/opt/venv
ENV PATH=/opt/venv/bin/:$PATH

EXPOSE 8000

# And then will start Gunicorn with Uvicorn
CMD ["/start.sh"]

This article is inspired by the great article on pythonspeed and the Dockerfile and start.sh and gunicorn_conf.py is inspired and mostly copied from Sebastián Ramírez's fastapi docker image