文档
Dockerfile 与 Docker Compose 实战
目标
编写 Dockerfile 容器化一个 Python Web 应用,并用 Docker Compose 编排多服务。
完整代码
示例应用(app/main.py)
from flask import Flask
import os
import socket
app = Flask(__name__)
@app.route('/')
def hello():
return f"Hello from {socket.gethostname()} | ENV={os.getenv('ENV', 'dev')}"
@app.route('/health')
def health():
return {"status": "ok"}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Dockerfile
# ===== 多阶段构建 =====
# 阶段1:构建依赖
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# 阶段2:运行镜像
FROM python:3.12-slim
WORKDIR /app
# 创建非 root 用户
RUN useradd -m -s /bin/bash appuser
# 从 builder 复制依赖
COPY --from=builder /root/.local /home/appuser/.local
COPY app/ ./app/
# 切换到非 root 用户
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
ENV ENV=production
EXPOSE 5000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
CMD ["python", "app/main.py"]
docker-compose.yml
version: '3.9'
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: flask-app
ports:
- "5000:5000"
environment:
- ENV=production
- REDIS_URL=redis://redis:6379
depends_on:
redis:
condition: service_healthy
restart: unless-stopped
networks:
- app-network
redis:
image: redis:7-alpine
container_name: redis
command: redis-server --appendonly yes
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
restart: unless-stopped
networks:
- app-network
nginx:
image: nginx:alpine
container_name: nginx-proxy
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
redis-data:
运行步骤
# 构建并启动
docker compose up -d --build
# 查看状态
docker compose ps
# 查看日志
docker compose logs -f app
# 测试
curl http://localhost:5000/
curl http://localhost/ # 通过 Nginx 代理
# 停止
docker compose down
预期输出
Hello from <container-id> | ENV=production