Docker lets you package your app and everything it needs, like libraries and tools, into one container so it runs the same anywhere.
When you use it with Flask, a lightweight Python web framework, you get a solid middle ground between running your own servers and using fully managed platforms like Heroku.
Flask works well with Docker because containers are much lighter than virtual machines. They don’t need to simulate a whole computer; they just share the host system’s core while staying isolated. This means fewer environment issues and easier, more reliable deployments.
In this guide, you'll containerize a Flask app with Docker.
Prerequisites
Before you begin, ensure you have the following installed:
Setting up the project structure
In this section, you'll build a simple Flask app structure that works well with Docker. The setup is straightforward, with just one application file.
Start by creating a new directory for your project and navigating into it:
mkdir flask-docker-app && cd flask-docker-app
Next, set up a virtual environment to manage your Python dependencies separately:
python3 -m venv venv
Activate the virtual environment:
source venv/bin/activate
Install Flask and Gunicorn:
pip install flask gunicorn
Create a requirements.txt
file to track dependencies:
pip freeze > requirements.txt
Now, create a simple app.py
file as the single entry point for your application:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
return jsonify({"message": "Welcome to Flask in Docker!"})
@app.route('/health')
def health():
return jsonify({"status": "healthy"})
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
This straightforward structure provides:
- A simple Flask application in a single file
- A welcome endpoint that returns JSON
- A health check endpoint for container monitoring
- Configured to listen on all interfaces (required for Docker)
Let's start by testing our Flask application without Docker. Launch the Flask development server with:
flask run
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
Visit http://127.0.0.1:5000/
in your browser, and you should see a JSON response:
{"message": "Welcome to Flask in Docker!"}
After verifying it works, stop the server.
Getting started with Docker
In this section, you'll enhance your Flask application by adding Docker. With Docker, your application will gain portability, consistency, and isolation, making it easier to deploy and scale.
First, create a simple Dockerfile
in the root of your project:
touch Dockerfile
Open the Dockerfile
and add the following straightforward configuration:
FROM python:3.13.3-slim-bookworm
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn
# Copy application code
COPY app.py .
EXPOSE 5000
# Run with Gunicorn for production
CMD ["gunicorn", "--bind", "0.0.0.0:4000", "app:app"]
Open the Dockerfile
and add the following configuration. This Dockerfile
will define how Docker builds your application image.
It starts with a slim Python 3.13.3 base image to keep the image lightweight. The working directory inside the container is set to /app
, and it installs dependencies from the requirements.txt
file.
It also installs Gunicorn for serving the app in production. The application code, app.py
, is copied into the container, and port 5000 is exposed to handle incoming connections. Finally, the application is run with Gunicorn as the production WSGI server, binding it to 0.0.0.0:4000
.
Next, create a simple .dockerignore
file to prevent unnecessary files from being included:
touch .dockerignore
Add the following contents:
venv/
__pycache__/
*.pyc
.git/
.gitignore
.idea/
.vscode/
Now, build the Docker image:
docker build -t flask-app .
After the build completes, run the container:
docker run --name flask-container -d -p 4000:4000 flask-app
The -d
flag runs the container in detached mode (background), and the -p
flag maps port 5000 in the container to port 5000 on your host.
Your Flask application is now running inside a Docker container! Visit http://localhost:4000/
to verify it's working:
This confirms the app is up and running.
Working with container logs
Managing logs is essential when working with containerized applications. Docker automatically captures everything written to standard output (stdout) and standard error (stderr) by your application, making it easy to inspect what's happening inside the container.
You can view the logs of your running container with:
docker logs flask-container
[2025-05-08 16:44:18 +0000] [1] [INFO] Starting gunicorn 23.0.0
[2025-05-08 16:44:18 +0000] [1] [INFO] Listening at: http://0.0.0.0:4000 (1)
[2025-05-08 16:44:18 +0000] [1] [INFO] Using worker: sync
[2025-05-08 16:44:18 +0000] [7] [INFO] Booting worker with pid: 7
These logs show the Gunicorn WSGI server starting up successfully. The first line indicates Gunicorn's version, followed by the listening address and port. The third line shows it's using the default synchronous worker type, and the last line confirms a worker process has started with process ID 7.
You can follow the logs in real-time (similar to tail -f
) with:
docker logs -f flask-container
This is particularly useful during development or when troubleshooting issues, as you'll see log entries appear as they happen.
To see only the most recent entries:
docker logs --tail 50 flask-container
And for logs within a specific time range:
docker logs --since 2025-05-08T16:00:00 flask-container
When you're done with the container, you need to stop and remove it:
docker stop flask-container
docker rm flask-container
For simplicity and automatic cleanup, use the --rm
flag when starting, which will automatically remove the container when it stops:
docker run --name flask-container --rm -d -p 5000:5000 flask-app
This prevents accumulating stopped containers that take up disk space on your system.
Setting up Docker Compose for development
Now that you've successfully containerized your Flask application with Docker, let's improve your development workflow using Docker Compose. This tool simplifies managing Docker applications, especially when you need multiple containers working together.
Before proceeding, make sure to stop your currently running container from the previous section:
docker stop flask-container
First, create a docker-compose.yml
file in your project root:
touch docker-compose.yml
Add the following configuration:
services:
web:
build: .
ports:
- "4000:5000"
volumes:
- ./app.py:/app/app.py
environment:
- FLASK_DEBUG=True
command: python app.py
restart: unless-stopped
This configuration builds your application using the Dockerfile, maps port 4000
on the host to port 5000
in the container, and mounts the local app.py
to the container for live code reloading.
It sets the FLASK_DEBUG
environment variable for development, uses Flask's development server by overriding the default command, and ensures the container restarts automatically if it crashes.
Start your development environment:
docker-compose up
You'll see output showing your application starting up:
✔ Network flask-docker-app_default Created 0.0s
✔ Container flask-docker-app-web-1 Created 0.0s
Attaching to web-1
web-1 | * Serving Flask app 'app'
web-1 | * Debug mode: on
web-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
web-1 | * Running on all addresses (0.0.0.0)
web-1 | * Running on http://127.0.0.1:5000
web-1 | * Running on http://172.18.0.2:5000
web-1 | Press CTRL+C to quit
web-1 | * Restarting with stat
web-1 | * Debugger is active!
web-1 | * Debugger PIN: 666-640-080
Now, you can edit your app.py
file locally, and the changes will be reflected immediately in the running container thanks to the volume mapping. Try adding a new route to app.py
:
...
@app.route('/hello')
def hello():
return jsonify({"message": "Hello from Docker Compose!"})
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
Save the file and visit http://localhost:4000/hello
in your browser:
You'll see the changes without rebuilding the image or restarting the container.
To run the containers in the background, use the -d
flag:
docker-compose up -d
[+] Running 1/1
✔ Container flask-docker-app-web-1 Started 0.2s
View logs from Docker Compose:
docker-compose logs
And to shut it down when you're done:
docker-compose down
This Docker Compose setup gives you a more flexible development workflow than plain Docker commands and prepares you to add additional services like databases.
Final thoughts
Containerizing your Flask app with Docker ensures consistent deployment and scalability across environments. Docker Compose simplifies managing multi-container applications, making setting up, scaling, and maintaining development and production environments easier.
For more detailed documentation on Docker and Docker Compose, refer to the official Docker documentation and Docker Compose documentation. These resources provide deeper insights into container management, multi-container setups, and best practices for production-ready applications
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for us
Build on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github