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后需要立即做三件事:
- 配置镜像加速(国内直连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- 安装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- 设置用户组(避免每次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.txt3. 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 镜像构建的坑与技巧
缓存利用:构建时按依赖变更频率排序COPY指令,把变动少的放前面。比如先COPY requirements.txt再COPY代码,这样修改代码时不会重复安装依赖。
国内加速:在Dockerfile最前面添加:
ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple- 镜像瘦身:构建完成后运行以下命令清理无用层:
docker image prune --force --all4. 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 --build6. 运维监控与问题排查
6.1 常用诊断命令
查看实时日志:
docker-compose logs -f --tail=100 web进入容器调试:
docker exec -it myapp_web_1 bash资源占用查看:
docker stats6.2 性能优化参数
在docker-compose.yml中添加资源限制:
web: deploy: resources: limits: cpus: '2' memory: 1G reservations: memory: 512M6.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 reload7.2 日志集中管理
在compose文件中添加:
services: fluentd: image: fluent/fluentd volumes: - ./logs:/fluentd/log web: logging: driver: "fluentd" options: fluentd-address: localhost:24224 tag: myapp.web7.3 自动伸缩配置
使用docker-swarm模式:
docker swarm init docker service create --name web --replicas 3 -p 5000:5000 myapp_web8. 踩坑记录与终极建议
- 时区问题:所有容器默认UTC时间,必须在Dockerfile中添加:
ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone- 文件权限:容器内用户权限与宿主机冲突时,在docker-compose.yml中添加:
user: "${UID:-1000}:${GID:-1000}"- 内存泄漏: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