Table of Contents:
requirements.txt
poetry
This article will show you how to containerize a Python application and run it in three single steps. This is a shorter version of How to write a great Dockerfile for Python apps, for a more in depth explanation I recommend you to check it.
I decided to containerize a Django application but the dockerfiles below work with any kind of Python application, you can use them as examples to containerize your Python applications.
The dockerfiles in this article have some nice features:
GIT_HASH
tini
You can reuse the dockerfiles from this article with any Python project as long as you have:
requirements.txt
If you are managing your dependencies directly with pip
you can create your requirements.txt
manually,
or with pip freeze > requirements.txt
.
You can create a new Dockerfile
inside the root path of your project and copy-paste the code below
# 💥 change the Python version with your version 💥
FROM python:3.8.3-slim-buster
ENV TINI_VERSION="v0.19.0"
ENV PIP_NO_CACHE_DIR=True
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
RUN pip install -U \
pip \
setuptools \
wheel
WORKDIR /project
RUN useradd -m -r user && \
chown user /project
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
USER user
ARG GIT_HASH
ENV GIT_HASH=${GIT_HASH:-dev}
ENTRYPOINT ["/tini", "--"]
# 💥 here you need to specify your command 💥
CMD ["gunicorn", "app.wsgi", "-b", "0.0.0.0:8080"]
poetry
With poetry
the dockerfile is slightly different, we need to install poetry, copy the poetry's files and then run poetry install --no-dev
.
An important note: we don't really care about creating a virtual environment inside the image, so we install the dependencies globally.
# 💥 change the Python version with your version 💥
FROM python:3.8.3-slim-buster
ENV TINI_VERSION="v0.19.0"
ENV PIP_NO_CACHE_DIR=True
ENV POETRY_VIRTUALENVS_CREATE=False
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
RUN pip install -U \
pip \
setuptools \
wheel \
poetry
WORKDIR /project
RUN useradd -m -r user && \
chown user /project
COPY poetry.lock pyproject.toml ./
RUN poetry install --no-dev && \
rm -rf ~/.cache/pypoetry/{cache,artifacts}
COPY . .
USER user
ARG GIT_HASH
ENV GIT_HASH=${GIT_HASH:-dev}
ENTRYPOINT ["/tini", "--"]
# 💥 here you need to specify your command 💥
CMD ["gunicorn", "app.wsgi", "-b", "0.0.0.0:8080"]
If you cloned the repo locally you can build a docker image with this command
docker build -t django-app -f Dockerfile.requirements .
The -f
flag specifies the dockerfile we want to use, for poetry
we need to specify a different file
docker build -t django-app -f Dockerfile.poetry .
Remember that if you rename one of the files to Dockerfile
then you can omit -f
completely
docker build -t django-app .
One last thing, we can pass the GIT_HASH
value using build-arg
, this is not really needed locally, but is extremely useful inside a CI/CD.
export GIT_HASH = $(git rev-parse --short HEAD)
docker build --build-arg GIT_HASH=${GIT_HASH} -t django-app -f Dockerfile.poetry .
Once the image is built we can run it with
docker run -it --rm -p 8080:8080 django-app
and then test the container with curl http://localhost:8080/healthz
.
This is a bonus step, but it shows you how to push a docker image to a registry.
In this case I'll use the docker hub, but the process is the same with any registry. Just remember that the docker image name (-t my-image-name
) would change depending on the registry.
docker -t django-app pybootcamp/django-app:poetry
Once the image is tagged properly we can push it to the registry
docker push pybootcamp/django-app:poetry
Here you can find the docker image that I just published.
You can start using these Dockerfiles inside your projects, ideally only a small number of changes are necessary.
Refactoring Dockerfiles is also important!
If you use the same dockerfile for multiple repositories you could consider extracting a base docker image.
For example we can have a base docker image tagged as python-base:3.8.3
created with the Dockerfile below
# a base docker image used across different projects
FROM python:3.8.3-slim-buster
ENV TINI_VERSION="v0.19.0"
ENV PIP_NO_CACHE_DIR=True
ENV POETRY_VIRTUALENVS_CREATE=False
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
RUN pip install -U \
pip \
setuptools \
wheel \
poetry
WORKDIR /project
RUN useradd -m -r user && \
chown user /project
ENTRYPOINT ["/tini", "--"]
Then in your project specific Dockerfile you can use the image as a base
FROM python-base:3.8.3
COPY poetry.lock pyproject.toml ./
RUN poetry install --no-dev && \
rm -rf ~/.cache/pypoetry/{cache,artifacts}
COPY . .
USER user
ARG GIT_HASH
ENV GIT_HASH=${GIT_HASH:-dev}
CMD ["gunicorn", "app.wsgi", "-b", "0.0.0.0:8080"]
Get great content on Python, DevOps and cloud architecture.