The whole process of Docker deployment: Dockerfile and Docker Compose orchestration
📂 Stage: Stage 6 - Online Deployment (Production) 🔗 Related chapters: Gunicorn and Nginx · Environment variables and security configuration
The local development goes smoothly, but as soon as it is thrown on the server, various errors are reported: the Python version is wrong, PostgreSQL cannot be connected, Redis is not installed, the path configuration is completely messed up... This kind of "environment inconsistency hell" is almost a must-have for every Flask project going online.
Docker is a good remedy for this kind of problem - it packages applications, dependencies, and runtime environments into a standardized "image", and then generates isolated "containers" through the image. No matter which machine it is run on, the environment in the container is exactly the same. This article will help you write a production-ready Dockerfile from scratch, then use Docker Compose to orchestrate a complete service of Flask + PostgreSQL + Redis + Nginx, and finally complete one-click deployment on the cloud server.
1. Write an efficient and safe Dockerfile
Dockerfile is an "image building guide", and each instruction will generate an image layer. A reasonable layering order can not only greatly improve the build speed, but also improve security. We will build a Flask application step by step based on the lightweight version of Python 3.11.
Complete Dockerfile
Dismantling of layered ideas:
- Base Image:
python:3.11-slimCompared with the full version, the compilation tools and documentation are removed, and the size is smaller and the attack surface is smaller. - Dependent Installation: Exploit
COPY requirements.txt .andRUN pip install ...Form an independent cache layer. Routine modifications to application code will not trigger dependency layer reconstruction, and build times are reduced from minutes to seconds. - Non-root operation: The default container has root permissions. Once compromised, the host may be endangered. Switch to normal user
appuserIt is the most basic security practice. - Start Command: Passed
gunicornStart the Flask application factory, which is suitable for multi-process request processing in production environments.
Supporting requirements.txt
This file lists the Flask family bucket and commonly used database drivers, asynchronous task libraries, etc. to ensure that all dependencies are available when the project is running:
💡 Tips:
psycopg2-binaryIt is a precompiled version and does not require installing the PostgreSQL development library in the container, making it very suitable for Docker scenarios.
2. Use Docker Compose to orchestrate multiple containers
In a production environment, a Flask application often requires multiple services such as database, cache, reverse proxy, etc. Manualdocker runStarting one by one is not only tedious, but also difficult to manage dependencies and networks. Docker Compose makes all this possible with just one YAML file that defines how all containers are built, environment variables, data volumes, health checks, and startup sequences.
2.1 Local development version: hot reloading, fast debugging
When developing we need:
- Automatically reload after modifying the code, no need to restart the container;
- Environment variables can be written directly in the Compose file to facilitate quick startup;
- Database and Redis have data persistence, but allow cleaning at any time.
Key design points:
- Code Mount:
volumesconvert local./appThe directory is mapped to the container, and any code changes can be refreshed immediately without rebuilding the image. - HEALTH CHECK:
depends_oncombinecondition: service_healthy, make sure the database is completely ready before starting the web service to avoid connection failure. - Development Server:
command: flask runConvenient for debugging, but actual production needs to be replaced back to Gunicorn.
2.2 Production environment version: safe, stable and durable
The biggest difference between production deployment and development is:
- Use pre-built images instead of on-site
build; -Environment variables are placed separately.env.productionFiles are never submitted to the code repository; - All containers open
restart: alwaysEnsure service self-healing; - Join Nginx reverse proxy to process static files and SSL certificates;
- Configure health checks for critical services.
Production configuration points:
restart: always: No matter what the reason is for exiting, Docker will automatically restart the container and cooperate with the health check to quickly restore the service.- Sensitive information external:
.env.productionThe file usually contains database passwords, keys, etc., via.gitignoreEliminate the risk of leakage. - HEALTH CHECK: The web service is accessed regularly
/healthinterface (you need to simply implement this endpoint in your application) to confirm that the service is in a normal state. - Data persistence: Database and Redis data are stored in named volumes, and the data will not be lost even if the container is deleted.
3. One-click build and deployment process
Local development
Open the project root directory and execute the following commands to start the complete development environment:
Cloud server production deployment
Prerequisite: Docker and Docker Compose have been installed on the server and exist in the project root directorydocker-compose.prod.yml、.env.productionas well asnginx/Configuration directory.
🚀 Common Tips: Use
--no-depsWhen a single service is restarted using parameters, the databases, Redis, etc. it depends on will not be restarted, thereby achieving zero-downtime rolling updates.
4. Review of Key Best Practices
- Hierarchical cache optimization: Dockerfile Lieutenant General
COPY requirements.txtPlace it before application code and take advantage of layer caching to speed up builds. - Security reduction: All containers must be run as non-root users to reduce the potential attack surface.
- Data persistence: Database, Redis, static files, uploaded files, etc. are all mounted to the Docker volume or host directory to avoid data loss when the container is destroyed.
- Full health check coverage: The production environment configures healthcheck for all services to ensure reliable startup of the dependency chain.
- Sensitive Information Isolation: Production environment variables, database passwords, etc. must be placed in
.env.productionFiles are never submitted along with the code. - Lightweight Image: Basic image is preferred
-slimor-alpineversion, which can not only reduce the size but also reduce security risks.
🔗 Extended reading
Now, you can apply this configuration directly to your Flask project and say goodbye to the trouble of "environment inconsistency" completely.

