Skip to content

How to write a Dockerfile for a Python app

October 29, 2026 · 2 min read

Write a Dockerfile that starts from a Python base image, installs your packages from requirements.txt, copies your code, and sets the command that starts the app. Then docker build and docker run do the rest.

A small Flask app in a container

Make a folder with three files. First, app.py:

from flask import Flask

app = Flask(__name__)

PRICES = {
    "House Espresso, 5 lb": 55,
    "Single Origin, 5 lb": 72,
}


@app.route("/")
def price_list():
    text = "Kettle & Crane wholesale prices\n"
    for name, price in PRICES.items():
        text += f"{name}: ${price}\n"
    return text, {"Content-Type": "text/plain"}

Second, requirements.txt, with exact versions:

flask==3.1.3
gunicorn==26.2.0

Third, the Dockerfile:

FROM python:3.15-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Build and run it:

docker build -t pricelist .
docker run -d --name pricelist -p 8000:8000 pricelist
curl -s http://localhost:8000

Output of the curl command:

Kettle & Crane wholesale prices
House Espresso, 5 lb: $55
Single Origin, 5 lb: $72

What each line does

  • FROM picks the base image. -slim is a smaller Python image.
  • WORKDIR /app creates /app and makes it the working folder.
  • COPY requirements.txt . and RUN pip install ... come before the code on purpose. Docker reuses a finished step if nothing before it changed, so editing app.py does not reinstall your packages.
  • COPY . . copies the rest of your folder, including app.py.
  • EXPOSE 8000 is documentation. You still need -p 8000:8000 to reach the port.
  • CMD is the command the container runs. Gunicorn is a production web server; Flask's built-in one is only for testing.

Common mistake

Binding to 127.0.0.1. A server listening on localhost inside a container only accepts connections from that container, so curl fails with Empty reply from server or Connection reset by peer. Bind to 0.0.0.0, as the CMD above does.

Running the build in the wrong folder. "/requirements.txt": not found means the file is not in the build context, the . at the end of docker build. Run the command in the folder that holds your files.

Remove the container with docker rm -f pricelist when you are done.

A Python Dockerfile is six lines: base image, working folder, install requirements, copy code, expose the port, run the server on 0.0.0.0.

More on DevOps & Cloud