Multi-stage Python builds with Docker on CentOS
Following on from my getting started with Docker on CentOS post, I found that the version of Docker is very old (1.13) and, amongst other things, does not support multi-stage builds which will allow use to cut down our image size (useful, as the Azure registry charges for data transfer).
Install a newer Docker
In order to get a more up to date Docker, I needed to remove the old version:
yum erase docker docker-cli docker-common
Add a new yum repository (downloading https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d
will do) and then install the new version:
yum install docker-ce containerd.io
The multi-stage build
The python:slim
Docker image does not include the tools necessary to build compiled extensions, but python:latest
(the full-image) results in very large (>1.1GB) images. In order to get the best of both worlds, I use a multi-stage build to install the extensions in a virtualenv and then copy that over to the slim python image in order to run the project.
FROM docker:latest AS compile-image
# Setup a virtualenv, to make copying to the final image easy
RUN python -m venv /project/venv
ENV PATH="/project/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install -r requirements.txt
# Deploy image
FROM docker:slim
COPY --from=compile-image /project/venv /project/venv
# Copy project files over
COPY *.py /project/
# This project wants this port exposed
EXPOSE 8080
ENV PATH="/project/venv/bin:$PATH"
CMD ["python", "/project/main.py"]
This results in an imaged of 328MB, compared to 1.16GB, for my project.