1. Python Web应用部署方案概述

在2023年的开发现场,Docker+Nginx的组合已经成为Python Web应用部署的事实标准方案。这套方案之所以被广泛采用,关键在于它完美解决了传统部署中的三个痛点:环境不一致导致的"在我机器上能跑"问题、多应用端口管理混乱、以及HTTPS配置复杂。

我最近刚用这套方案部署了一个Flask电商项目,从测试环境到生产环境只用了不到15分钟。相比之前手动配环境、改配置的部署方式,效率提升了至少10倍。下面我就结合这个实战案例,拆解每个环节的技术细节和避坑要点。

2. 环境准备与工具选型

2.1 服务器基础配置

推荐使用Ubuntu 22.04 LTS作为基础系统,这是目前最稳定的生产环境选择。在阿里云/腾讯云购买实例时,注意勾选"自动安装Docker"选项,能省去后续安装步骤。最低配置建议:

  • CPU:2核(动态页面多的选4核)
  • 内存:4GB(Python应用内存占用较高)
  • 系统盘:50GB SSD(Docker镜像很占空间)

重要提示:购买云服务器时一定要选择同一个地域的ECS和容器镜像服务,否则拉取镜像会产生流量费用。我曾经因为跨地域拉镜像一天被扣了200多块。

2.2 Docker环境配置

安装完Docker后需要立即做三件事:

  1. 配置镜像加速(国内直连Docker Hub慢到怀疑人生):
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 安装docker-compose:
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
  1. 设置用户组(避免每次sudo):
sudo usermod -aG docker $USER
newgrp docker  # 立即生效

2.3 Python项目结构调整

你的项目目录应该调整为以下结构(以Flask为例):

myapp/
├── app/              # 应用代码
│   ├── __init__.py
│   └── views.py
├── requirements.txt  # 依赖文件
├── Dockerfile        # 生产环境镜像
├── docker-compose.yml 
└── nginx/
    ├── nginx.conf    # 主配置
    └── sites-enabled/ # 站点配置

关键点:requirements.txt必须精确指定版本号,否则后续构建可能失败。建议生成时使用:

pip freeze | grep -v "pkg-resources" > requirements.txt

3. Docker镜像构建实战

3.1 编写高效的Dockerfile

多阶段构建是必须掌握的技巧,能大幅减小最终镜像体积(我做的电商项目从1.2GB瘦身到180MB):

# 构建阶段
FROM python:3.9-slim as builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

# 运行阶段
FROM python:3.9-slim
WORKDIR /app

# 从构建阶段拷贝已安装的包
COPY --from=builder /root/.local /root/.local
COPY . .

# 确保脚本可执行
RUN chmod +x ./start.sh

ENV PATH=/root/.local/bin:$PATH
CMD ["./start.sh"]

几个优化点:

  • 使用slim版本基础镜像
  • 分离构建和运行环境
  • 设置PATH让python命令可用
  • 通过start.sh启动应用(方便注入环境变量)

3.2 镜像构建的坑与技巧

  1. 缓存利用:构建时按依赖变更频率排序COPY指令,把变动少的放前面。比如先COPY requirements.txt再COPY代码,这样修改代码时不会重复安装依赖。

  2. 国内加速:在Dockerfile最前面添加:

ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
  1. 镜像瘦身:构建完成后运行以下命令清理无用层:
docker image prune --force --all

4. Nginx配置精要

4.1 反向代理配置

这是最简可用的Nginx配置(保存为nginx/sites-enabled/myapp.conf):

server {
    listen 80;
    server_name yourdomain.com;
    
    location / {
        proxy_pass http://web:5000;  # 这里的web是compose中的服务名
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /static {
        alias /app/static;  # 静态文件直接由Nginx处理
        expires 30d;
    }
}

4.2 HTTPS自动配置

使用Let's Encrypt的certbot自动获取证书:

docker run -it --rm \
  -v "/etc/letsencrypt:/etc/letsencrypt" \
  -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
  -p 80:80 \
  certbot/certbot certonly --standalone -d yourdomain.com

然后在nginx配置中添加:

listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

5. 终极部署方案:docker-compose

完整的docker-compose.yml示例:

version: '3.8'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=production
    restart: unless-stopped
    volumes:
      - ./app:/app  # 开发时挂载代码实时更新

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt
    depends_on:
      - web

启动命令:

docker-compose up -d --build

6. 运维监控与问题排查

6.1 常用诊断命令

查看实时日志:

docker-compose logs -f --tail=100 web

进入容器调试:

docker exec -it myapp_web_1 bash

资源占用查看:

docker stats

6.2 性能优化参数

在docker-compose.yml中添加资源限制:

web:
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 1G
      reservations:
        memory: 512M

6.3 备份与恢复

完整备份命令:

docker-compose exec db pg_dump -U postgres mydb > backup.sql  # PostgreSQL示例

7. 高级技巧与扩展方案

7.1 蓝绿部署实践

通过标签实现零停机更新:

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --scale web=3 --no-recreate
docker-compose exec nginx nginx -s reload

7.2 日志集中管理

在compose文件中添加:

services:
  fluentd:
    image: fluent/fluentd
    volumes:
      - ./logs:/fluentd/log

  web:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: myapp.web

7.3 自动伸缩配置

使用docker-swarm模式:

docker swarm init
docker service create --name web --replicas 3 -p 5000:5000 myapp_web

8. 踩坑记录与终极建议

  1. 时区问题:所有容器默认UTC时间,必须在Dockerfile中添加:
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
  1. 文件权限:容器内用户权限与宿主机冲突时,在docker-compose.yml中添加:
user: "${UID:-1000}:${GID:-1000}"
  1. 内存泄漏:Python应用建议在启动命令前加:
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "--threads", "2", "app:app"]

最后分享一个监控脚本check_deploy.sh:

#!/bin/bash
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health)
if [ "$response" != "200" ]; then
    docker-compose restart web
    echo "$(date) - 检测到服务异常,已自动重启" >> /var/log/app_monitor.log
fi

更多推荐