Docker 部署全流程:Dockerfile 与 Docker Compose 编排

📂 所属阶段:第六阶段 — 上线部署(生产篇)
🔗 相关章节:Gunicorn 与 Nginx · 环境变量与安全配置


1. Dockerfile 编写

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# 先复制依赖文件(利用 Docker 层缓存)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非 root 用户
RUN useradd --create-home appuser && \
    chown -R appuser:appuser /app
USER appuser

EXPOSE 8000

# 启动命令
CMD ["gunicorn", "-c", "gunicorn.conf.py", "app:create_app()"]
# requirements.txt
Flask>=3.0.0
gunicorn>=21.0.0
flask-sqlalchemy>=3.1.0
flask-login>=0.6.3
flask-wtf>=1.2.0
flask-migrate>=4.0.0
flask-cors>=4.0.0
psycopg2-binary>=2.9.0
redis>=5.0.0
python-dotenv>=1.0.0
email-validator>=2.0.0
Pillow>=10.0.0
celery>=5.3.0

2. Docker Compose 编排

2.1 本地开发

# docker-compose.yml
version: "3.9"

services:
  web:
    build: .
    container_name: daoman_web
    ports:
      - "8000:8000"
    environment:
      - FLASK_ENV=development
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/daoman
      - REDIS_URL=redis://redis:6379/0
    volumes:
      - ./app:/app
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    command: flask run --host=0.0.0.0

  db:
    image: postgres:16-alpine
    container_name: daoman_db
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: daoman
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: daoman_redis

  celery:
    build: .
    container_name: daoman_celery
    command: celery -A app.celery_app worker --loglevel=info
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/daoman
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - db
      - redis

volumes:
  postgres_data:

2.2 生产环境

# docker-compose.prod.yml
version: "3.9"

services:
  web:
    image: daoman/flask:latest
    container_name: daoman_web
    restart: always
    env_file:
      - .env.production
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  db:
    image: postgres:16-alpine
    restart: always
    volumes:
      - postgres_prod:/var/lib/postgresql/data
    env_file:
      - .env.production

  redis:
    image: redis:7-alpine
    restart: always
    command: redis-server --appendonly yes
    volumes:
      - redis_prod:/data

  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - static_files:/var/www/static
    depends_on:
      - web

volumes:
  postgres_prod:
  redis_prod:
  static_files:

3. 构建与部署

# 本地构建
docker build -t daoman/flask:latest .

# Docker Compose 本地启动
docker-compose up -d
docker-compose logs -f web

# Docker Compose 生产部署
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d --no-deps --build web

# 进入容器调试
docker exec -it daoman_web /bin/sh

4. 小结

Docker 部署流程:

1. 写 Dockerfile(构建说明)
2. 写 docker-compose.yml(本地开发)
3. 写 docker-compose.prod.yml(生产)
4. docker build 构建镜像
5. docker-compose up -d 启动服务
6. 配置 Nginx + SSL

💡 最佳实践:Dockerfile 分层优化,利用缓存加速构建。非 root 用户运行容器保证安全。生产环境使用 Docker Compose 编排多个服务。


🔗 扩展阅读