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
Written by
Marketing Team at Civo
Written by
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-slimCOPY . /appWORKDIR /appRUN pip install flaskEXPOSE 8080CMD ["python", "main.py"]
What each instruction does:
FROM python:3.11-slimsets the base image. Always pin to a specific version rather than latest so your builds are reproducible.COPY . /appcopies your application code into the /app directory inside the image.WORKDIR /appsets/appas the working directory for all subsequent instructions.RUN pip install flaskinstalls Flask inside the image at build time.EXPOSE 8080documents 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 SIZEyour-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 NAMES9f8e7d6c5b4a your-dockerhub-username/dockerfile-demo:v1 "python main.py" Up 2 minutes 0.0.0.0:8080->8080/tcp keen_hopper

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.
Share this lesson