Python Flask/Django Dockerfile Template
Python web application Docker images face several challenges that require careful Dockerfile design: virtual environment management inside containers, pip caching for fast builds, handling of C extension compilation, and choosing between gunicorn and uvicorn for production serving. A well-structured Python Dockerfile addresses all of these systematically.
Virtual environments inside Docker containers are sometimes considered redundant — the container itself is already isolated. However, using a virtual environment in your Dockerfile has concrete benefits: it prevents system Python packages from being accidentally imported, makes it easy to copy just the installed packages into a slim runtime stage, and is consistent with how your application is developed and tested locally using tools like pyenv and poetry.
The Python 3.11-slim or 3.12-slim base image strikes the right balance between size and compatibility. Unlike Alpine, the slim Debian base includes glibc, which means most Python packages with C extensions (numpy, pillow, psycopg2) will compile correctly without additional configuration. Alpine-based Python images frequently cause compilation failures for scientific and database packages.
Dependency installation layering is the critical performance optimization for Python Docker builds. Copy requirements.txt (or pyproject.toml for Poetry) before copying your application source, install dependencies, then copy the source. This ensures that pip install is only re-executed when your dependencies change, not on every code change. Use --no-cache-dir with pip to avoid adding the pip download cache to the image layer.
For Django specifically, the DJANGO_SETTINGS_MODULE environment variable must be set correctly for the container startup. If your application requires database migration, do not run migrations in the Dockerfile CMD — instead, run them as a separate init container or as part of your deployment pipeline before traffic is routed to new container replicas.
Gunicorn is the standard WSGI server for production Flask and Django deployments. The recommended configuration is four workers per CPU core. For async applications using Django Channels or FastAPI, use uvicorn or uvicorn[standard] behind nginx instead of gunicorn's WSGI workers.
Template Preview
{"language":"python","pythonVersion":"3.12","framework":"django","useSlim":true,"multiStage":true,"nonRootUser":true,"wsgiServer":"gunicorn","healthCheck":true}Customize this template with your own details using the free generator:
▸Open in GeneratorFAQ
- Should I use poetry or pip with requirements.txt in Docker?
- Both work. pip with requirements.txt is simpler and more universally understood. Poetry is better if you use it locally for dependency management — use poetry export -f requirements.txt --without-hashes to generate a requirements.txt for Docker, or use poetry install --no-dev directly in the container. Avoid using Poetry's lock file resolution inside Docker as it adds significant build time.
- How many gunicorn workers should I configure?
- The Gunicorn documentation recommends 2-4 workers per CPU core, so a typical single-core container should use 2–3 workers. For containerized deployments, it is often better to use fewer workers per container and scale horizontally with more container replicas, giving Kubernetes or ECS better control over resource allocation and rolling updates.
- How do I handle Django static files in Docker?
- Run python manage.py collectstatic --noinput during the build stage and copy the collected static files into the runtime image. In production, serve static files from a CDN or object storage (S3, GCS) rather than from gunicorn. Configure nginx as a reverse proxy to serve the static directory if you cannot use a CDN. Never configure DEBUG=True in the production container.