下载工作台
Django Web 开发

Docker/K8s 交付与框架选型

试读上半部分 · 解锁后可读全文

第 19 章 · Docker/K8s 交付与框架选型

本章目标:为 shop-demo 编写多阶段 Dockerfile.dockerignore非 root 用户;构建阶段执行 collectstatic,运行 Gunicorn;使用 docker-compose.prod.yml 编排 web + worker + Nginx + PostgreSQL + Redis;理解 K8s 核心对象并阅读虚构 api.example.com YAML;全面对照 Django vs Flask vs FastAPI;回答面试框架选型;完成 19 章结业总结100 分进阶验收表(选修);说明与 xiaozi-cloud 衔接。

学时建议:6~8 小时(含 3 小时容器演练)

前置ch11 Gunicorn/Nginx;ch18 可观测性;ch10 Redis/Celery。K8s 深度见 xiaozi-cloud


19.1 从「能跑」到「可交付」

源码 ──docker build──► registry.example.com/shop-demo:1.0.0 ──pull──► K8s / VM
                                                              api.example.com
交付物说明
Docker 镜像不可变制品,含依赖与代码
compose / K8s YAML进程拓扑与配置
.env.example文档化变量,不含密钥
虚构 shop-demoapi.example.comregistry.example.com严禁真实镜像地址、Kubeconfig、数据库密码。

19.2 多阶段 Dockerfile

shop-demo/Dockerfile

FROM python:3.12-slim AS builder
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev \
    && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN python -m venv /opt/venv && /opt/venv/bin/pip install -r requirements.txt gunicorn

FROM python:3.12-slim AS static
WORKDIR /app
ENV PATH="/opt/venv/bin:$PATH" DJANGO_SETTINGS_MODULE=shopdemo.settings
COPY --from=builder /opt/venv /opt/venv
COPY . .
RUN SECRET_KEY=build-only-not-for-runtime \
    python manage.py collectstatic --noinput

FROM python:3.12-slim AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 curl \
    && rm -rf /var/lib/apt/lists/* \
    && groupadd --gid 1000 app && useradd --uid 1000 --gid app --create-home app
WORKDIR /app
ENV PATH="/opt/venv/bin:$PATH" PYTHONUNBUFFERED=1 DJANGO_SETTINGS_MODULE=shopdemo.settings
COPY --from=builder /opt/venv /opt/venv
COPY --chown=app:app . .
COPY --from=static --chown=app:app /app/staticfiles /app/staticfiles
USER app
EXPOSE 8000
HEALTHCHECK CMD curl -f http://127.0.0.1:8000/health/ || exit 1
CMD ["gunicorn", "shopdemo.wsgi:application", "-c", "gunicorn.conf.py"]
实践原因
三阶段builder 装依赖、static 收集静态、runtime 最小
collectstaticNginx 或 WhiteNoise 可服务 /static/
USER app非 root,降权限
HEALTHCHECK编排器可重启不健康实例
docker build -t shop-demo:1.0.0 .
docker run --rm -p 8000:8000 -e SECRET_KEY=dev-only shop-demo:1.0.0

gunicorn.conf.pybind = "0.0.0.0:8000"workers = 2timeout = 60


19.3 .dockerignore

.git .venv __pycache__ .pytest_cache .coverage
media/* staticfiles/ .env .env.* !.env.example
docs/ tests/ *.md Dockerfile* docker-compose*.yml
db.sqlite3

勿将 .env 打进镜像;忽略测试/docs 加快构建。


19.4 docker-compose.prod.yml

shop-demo/docker-compose.prod.yml

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: shop_demo
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme-db}
      POSTGRES_DB: shop_demo
    volumes: [pg_data:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U shop_demo"]
      interval: 10s

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes: [redis_data:/data]

  web:
    build: .
    image: shop-demo:1.0.0
    command: gunicorn shopdemo.wsgi:application -c gunicorn.conf.py
    depends_on:
      db: {condition: service_healthy}
    environment:
      SECRET_KEY: ${SECRET_KEY}
      DATABASE_URL: postgresql://shop_demo:${POSTGRES_PASSWORD:-changeme-db}@db:5432/shop_demo
      REDIS_URL: redis://redis:6379/0
      CELERY_BROKER_URL: redis://redis:6379/1
      ALLOWED_HOSTS: api.example.com,web
      DEBUG: "false"
    volumes: [media_data:/app/media]
    expose: ["8000"]
    restart: unless-stopped

  worker:
    image: shop-demo:1.0.0
    command: celery -A shopdemo worker --loglevel=INFO
    depends_on: [web, redis]
    environment: {SECRET_KEY: ${SECRET_KEY}, DATABASE_URL: postgresql://shop_demo:${POSTGRES_PASSWORD:-changeme-db}@db:5432/shop_demo, CELERY_BROKER_URL: redis://redis:6379/1}
    restart: unless-stopped

  nginx:
    image: nginx:1.25-alpine
    depends_on: [web]
    ports: ["80:80", "443:443"]
    volumes:
      - ./deploy/nginx/shop-demo.conf:/etc/nginx/conf.d/default.conf:ro
      - ./deploy/certs:/etc/nginx/certs:ro
      - ./staticfiles:/var/www/static:ro
      - media_data:/var/www/media:ro
    restart: unless-stopped

volumes: {pg_data: {}, redis_data: {}, media_data: {}}

deploy/nginx/shop-demo.conf 要点:

upstream shop_demo_upstream { server web:8000; }
server {
    listen 443 ssl http2;
    server_name api.example.com;
    ssl_certificate /etc/nginx/certs/api.example.com.pem;
    ssl_certificate_key /etc/nginx/certs/api.example.com.key;
    client_max_body_size 10m;
    location /static/ { alias /var/www/static/; }
    location /media/  { alias /var/www/media/; }
    location /metrics { deny all; }
    location / {
        proxy_pass http://shop_demo_upstream;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }
}
cp .env.example .env
docker compose -f docker-compose.prod.yml up -d --build
服务角色
web / worker / nginx / db / redisGunicorn+Django / Celery / TLS+静态 / 持久化 / 缓存

19.5 Kubernetes 核心概念与 YAML(虚构)

Internet → Ingress(api.example.com) → Service → Deployment(3 Pods) ← ConfigMap / Secret
对象作用
Deployment镜像、副本数、滚动更新
Service稳定虚拟 IP,负载到 Pod
IngressHTTP 路由、TLS、域名
ConfigMap / Secret非敏感 / 敏感配置(Secret 勿明文进 Git)

deploy/k8s/configmap.yaml

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。