How to dockerize a Python app: Dockerfile, build and run

Step-by-step guide to dockerizing a Python Flask application. Covers writing a Dockerfile, building an image with docker build, and running a container with docker run.

5 lessons · 16 min · Beginner

3 minutes reading time

Written by

Civo Team
Civo Team

Marketing Team at Civo

Containers solve a common problem in software development: an application that works on one machine but fails on another due to differences in dependencies, environment variables, or system libraries. In this guide you will dockerize a simple Python Flask application, build a Docker image from a Dockerfile, and run it as a container.

By the end you will have a working containerized Flask app and understand the key Docker commands needed to build, run, and inspect containers.

What is a container?

Imagine a shipping container. It does not matter what is inside or which ship carries it. The container works the same way at every port. Software containers work the same way. They package your application together with everything it needs to run into a single portable unit that behaves identically regardless of where it is deployed.

The application

We will work with a simple Python Flask application that responds to HTTP requests. The application runs on port 8080 and returns a greeting when called.

Before containerizing, the app runs with:

python main.py

The goal is to package this so it can run identically in any environment without installing Python, Flask, or any dependencies manually.

Writing the Dockerfile

A Dockerfile is a set of instructions that defines what goes into the image. Here is the complete Dockerfile for this application:

FROM python:3.11-slim
COPY . /app
WORKDIR /app
RUN pip install flask
EXPOSE 8080
CMD ["python", "main.py"]
civo-dockerfile-layers

What each instruction does:

  • FROM python:3.11-slim sets the base image. Always pin to a specific version rather than latest so your builds are reproducible.
  • COPY . /app copies your application code into the /app directory inside the image.
  • WORKDIR /app sets /app as the working directory for all subsequent instructions.
  • RUN pip install flask installs Flask inside the image at build time.
  • EXPOSE 8080 documents that the container listens on port 8080. It does not publish the port automatically.
  • CMD ["python", "main.py"] defines the default command to run when the container starts.

A note on ENTRYPOINT vs CMD

Both define what runs when the container starts, but they behave differently. CMD provides default arguments that can be overridden when you run the container. ENTRYPOINT sets the main executable and cannot be overridden without the --entrypoint flag. A common pattern is to set ENTRYPOINT to the executable and CMD to the default arguments. For a simple application like this, CMD alone is sufficient.

If you need to run multiple commands during the build, chain them with && to keep them in a single layer:

RUN apt-get update && apt-get install -y curl

Building the image

Replace your-dockerhub-username with your own Docker Hub account name:

docker build -t your-dockerhub-username/dockerfile-demo:v1 .

The -t flag tags the image with a name and version. Without it Docker defaults to latest, which is fine for local development but not recommended for production.

Verify the image was created:

docker image ls

Expected output:

REPOSITORY TAG IMAGE ID CREATED SIZE
your-dockerhub-username/dockerfile-demo v1 a1b2c3d4e5f6 1 minute ago 125MB

Running the container

Run the container in interactive mode to see the output directly in your terminal:

docker run -it -p 8080:8080 your-dockerhub-username/dockerfile-demo:v1

The -p 8080:8080 flag maps port 8080 on the container to port 8080 on your host. Open http://localhost:8080 in your browser to see the application running.

Running in detached mode

For long-running services you will usually want to run the container in the background:

docker run -d -p 8080:8080 your-dockerhub-username/dockerfile-demo:v1

The -d flag runs the container in detached mode, returning you to your terminal immediately. The application continues running in the background.

List all running and exited containers:

docker ps -a

Expected output:

CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
9f8e7d6c5b4a your-dockerhub-username/dockerfile-demo:v1 "python main.py" Up 2 minutes 0.0.0.0:8080->8080/tcp keen_hopper
Civo Team
Civo Team

Marketing Team at Civo

Civo is the Sovereign Cloud and AI platform designed to help developers and enterprises build without limits. We bridge the gap between the openness of the public cloud and the rigorous security of private environments, delivering full cloud parity across every deployment. As a team, we are dedicated to providing scalable compute, lightning-fast Kubernetes, and managed services that are ready in minutes. Through CivoStack Enterprise and our FlexCore appliance, we empower organizations to maintain total data sovereignty on their own hardware.

Our mission is to make the cloud faster, simpler, and fairer. By providing enterprise-grade NVIDIA GPUs and streamlined model management, we ensure that high-performance AI and machine learning are accessible to everyone. Built for transparency and performance, the Civo Team is here to give you total control over your infrastructure, your data, and your spend.

View author profile