DEV Community

Nickolena
Nickolena

Posted on • Edited on

9 2

My favorite way to write a Dockerfile for a Python app

There's more than one way to skin a cat, but this pattern makes my heart flutter.

Containerize a Python app

The asgi.py in our app directory

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def hello():
  return "World"
Enter fullscreen mode Exit fullscreen mode

Dockerfile

FROM python:3.7-buster as base

ENV SHELL=/bin/bash \
    USER=python \
    UID=10001

# Create a user for the app to be owned by
RUN set -eux; adduser \
    --disabled-password \
    --gecos "" \
    --home "/var/lib/python3" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    "${USER}"

# Manually create the users home directory
RUN mkdir -p "/var/lib/python3" && chown -R "${USER}" /var/lib/python3

FROM base as build

# Install the app requirements in its own layer.  
# Isolating the "build" stage from the application stage removes
# some of the unwanted cruft that comes with install 
# python dependencies
USER ${USER}
RUN python -m pip install \
      --user \
      'uvicorn[standard]' \
      'fastapi' \
      'wheel'

FROM base

COPY --from=build --chown=${USER} /var/lib/python3/.local /var/lib/python3/.local
ENV PATH=$PATH:/var/lib/python3/.local/bin

USER root 
ENTRYPOINT ["docker-entrypoint.sh"]
COPY docker-entrypoint.sh /usr/bin/docker-entrypoint.sh 

# Create a designated location for the app as the python user
USER ${USER}
WORKDIR /usr/lib/python

COPY ./app ./app

CMD ["app.asgi:app"]
Enter fullscreen mode Exit fullscreen mode

Entrypoint

#!/bin/bash -e

# If the CMD has not changed process it as a pure Python implementation
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ]; then
  set -- uvicorn "$@" --host 0.0.0.0 --http h11 --loop asyncio
fi

echo 
echo "Running $@"
echo

exec "$@"
Enter fullscreen mode Exit fullscreen mode

Breaking down the stages of the Dockerfile

This Dockerfile is separated in a few stages to organized by the function of its build step. The multi-stage build strips our application of unnecessary files.

base stage

The first stage is aliased as the "base". This stages bootstraps our required instructions that the remaining layers share. The user lets us install requirements outside of the root user.

build stage

The second stage brings in external requirements and installs them as the python user. This is useful because only the user's .local directory needs to be copied in the final stage. Copying the .local directory brings with only the requirements that application requires to run.

The nameless application stage

The base image of the app starts with a clean layer from the first stage. Removing the need to redeclare any instructions already provided.

The requirements can be copied to the user's .local directory like they were installed by pip. The app layer is not based on the build layer to reduce any left over's brought in by pip install.

Finally, the app itself is copied into a directory outside of user's home.


Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed: Zero in on just the tests that failed in your previous run
  • 2:34 --only-changed: Test only the spec files you've modified in git
  • 4:27 --repeat-each: Run tests multiple times to catch flaky behavior before it reaches production
  • 5:15 --forbid-only: Prevent accidental test.only commits from breaking your CI pipeline
  • 5:51 --ui --headed --workers 1: Debug visually with browser windows and sequential test execution

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️

Top comments (3)

Collapse
 
nickmaris profile image
nickmaris

Why do you need "USER root"?

I didn't know that nodejs has best practices for docker. I wish ruby had too.

Collapse
 
ndfishe profile image
Nickolena

You really don't need it....it's definitely redundant, but I use as indicator for, "hey, these commands are running as root"

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

👋 Kindness is contagious

Please show some love ❤️ or share a kind word in the comments if you found this useful!

Got it!