ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Day 19:Docker + Nginx 部署上线,让你的商城真正跑起来!

Day 19:Docker + Nginx 部署上线,让你的商城真正跑起来! 摘要项目写完了联调也通过了但代码还在服务器上裸跑今天这篇手把手带你把商城从开发环境打包部署到生产服务器上。Docker 容器化、Nginx 反向代理、Gunicorn 高性能应用服务器、HTTPS 证书配置、域名备案流程一套完整上线流程全走完。三个核心配置文件Dockerfile、docker-compose.yml、nginx.conf全部完整可用带详细注释。最后再教你用 AI 写部署脚本和排错指南省下大量踩坑时间。开发完了用户还看不到前 18 天我们把商城从 0 搭到了联调完毕。Django 的 API 写好了DRF 的接口通了MySQL 8.0 数据跑起来了Redis 缓存也配上了uni-app 前端也对接完了。但是——你的项目现在是什么状态大概率是这样在服务器上跑着python manage.py runserver 0.0.0.0:8000裸奔着。这就好比你开了一家店招牌没挂、门没装、灯没亮客人从门口路过都不知道这是不是正经营业。runserver是开发用的调试服务器单线程、不安全、不支持并发。性能不存在的。安全更不存在。那怎么让你的商城真正跑起来让用户通过域名 HTTPS 安全地访问到今天的主角来了Docker Nginx Gunicorn三件套。这三样东西在生产环境部署 Django 项目里是标配学会了这个以后部署任何 Python Web 项目都是同一套流程。三个家伙各管什么动手之前先搞清楚每个角色负责什么这样后面看配置才不会一头雾水。Gunicorn —— 干活的工人Django 自带的runserver是单线程的来了 100 个请求就排队等着慢得要死。Gunicorn 是一个 WSGI HTTP Server它能起多个 worker 进程真正处理并发请求。你可以把它理解成一个车间里的多个工人同时处理多个订单。Nginx —— 门面担当Nginx 是整个架构的入口它干三件事反向代理把用户的请求根据规则转发给后面的 Gunicorn静态文件服务CSS、JS、图片这些静态资源直接由 Nginx 返回不需要经过 Django性能提升巨大HTTPS 终端SSL 证书的加解密都在 Nginx 层完成后面用 HTTP 通信就行Nginx 处理静态文件的能力非常强单机轻松应对上万并发。让 Django 去处理图片请求那简直是大材小用。Docker —— 一键搬家Docker 把你的整个运行环境打包成一个镜像Python 版本、系统依赖、代码、配置文件全在一起。换服务器拉镜像docker compose up -d30 秒搞定。不用再手动装 Python、装依赖、配环境变量了。而且环境一致性有保障——开发、测试、生产用的都是同一个镜像不会出现在我电脑上能跑的经典问题。一句话总结Nginx 负责接客和分流 → Gunicorn 负责实际干活 → Docker 负责打包整个环境。动手实战从零到上线第一步编写 DockerfileDockerfile 就是打包说明书告诉 Docker 怎么一步步构建你的运行镜像。用多阶段构建来减小最终镜像体积# 第一阶段构建依赖 FROM python:3.11-slim AS builder WORKDIR /app # 安装系统依赖编译 MySQL 客户端等需要 RUN apt-get update apt-get install -y \ gcc \ default-libmysqlclient-dev \ pkg-config \ rm -rf /var/lib/apt/lists/* # 先复制依赖文件利用 Docker 缓存层 COPY requirements.txt . RUN pip install --no-cache-dir --prefix/install -r requirements.txt # 第二阶段运行镜像 FROM python:3.11-slim WORKDIR /app RUN apt-get update apt-get install -y curl rm -rf /var/lib/apt/lists/* # 从构建阶段拷贝安装好的 Python 包运行时不需要 gcc 这些编译工具 COPY --frombuilder /install /usr/local COPY . . # 收集静态文件生产模式需要 RUN python manage.py collectstatic --noinput EXPOSE 8000 # 启动命令4 个 worker绑定 0.0.0.0:8000日志输出到 stdoutdocker logs 可见 CMD [gunicorn, shop.wsgi:application, \ --bind, 0.0.0.0:8000, \ --workers, 4, \ --threads, 2, \ --timeout, 120, \ --access-logfile, -, \ --error-logfile, -]几个关键点多阶段构建第一阶段装编译工具gcc 这些第二阶段只拷贝装好的包。最终镜像里没有编译工具体积能从 1GB 降到 300MB 左右依赖缓存先 COPY requirements.txt再 COPY 代码。改了业务代码不会触发重新装依赖构建速度快workers 数量经验公式是2 * CPU核心数 14 核机器就配 4-5 个 worker。太多反而会因上下文切换变慢第二步编写 docker-compose.yml光有 Dockerfile 还不够。项目不只有 Django还有 MySQL、Redis 这些服务。docker-compose.yml是编排清单定义所有服务和它们之间的关系一键启动version:3.8services:# MySQL 数据库 mysql:image:mysql:8.0restart:alwaysenvironment:MYSQL_ROOT_PASSWORD:${MYSQL_ROOT_PASSWORD}MYSQL_DATABASE:shop_mallTZ:Asia/Shanghaiports:-127.0.0.1:3306:3306# 只监听本地不暴露到公网volumes:-mysql_data:/var/lib/mysql# 数据持久化command:---character-set-serverutf8mb4---default-authentication-pluginmysql_native_passwordhealthcheck:# 健康检查MySQL ready 前应用不启动test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5# Redis 缓存 redis:image:redis:7-alpinerestart:alwaysports:-127.0.0.1:6379:6379volumes:-redis_data:/datacommand:redis-server--appendonly yes--requirepass ${REDIS_PASSWORD}healthcheck:test:[CMD,redis-cli,-a,${REDIS_PASSWORD},ping]interval:10stimeout:5sretries:5# Django 应用 web:build:context:.dockerfile:Dockerfilerestart:alwaysports:-127.0.0.1:8000:8000# 只监听本地由 Nginx 转发volumes:-static_files:/app/static# 静态文件共享给 Nginx-media_files:/app/media# 用户上传文件env_file:-.env# 环境变量文件敏感配置不硬编码environment:-DJANGO_SETTINGS_MODULEshop.settings.prod-DATABASE_HOSTmysql# 指向 compose 内的 mysql 服务-REDIS_HOSTredisdepends_on:mysql:condition:service_healthy# 数据库就绪后才启动应用redis:condition:service_healthy# Nginx 反向代理 nginx:image:nginx:1.25-alpinerestart:alwaysports:-80:80-443:443volumes:-./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro-./nginx/ssl:/etc/nginx/ssl:ro# SSL 证书目录-static_files:/usr/share/nginx/html/static:ro-media_files:/usr/share/nginx/html/media:rodepends_on:-webvolumes:mysql_data:# 命名卷容器删了重建数据不丢redis_data:static_files:media_files:设计讲究网络隔离MySQL 和 Redis 都绑定127.0.0.1外网扫描根本扫不到这两个端口。只有容器之间能通信安全性拉满健康检查MySQL/Redis 配了 healthcheckweb 的depends_on配condition: service_healthy确保数据库完全就绪后应用才启动——不再踩应用启动但数据库还没 ready的坑环境变量外置密码放.env文件不硬编码在 yml 里数据持久化命名卷保证容器重建数据不丢第三步配置 NginxNginx 配置放在nginx/nginx.conf核心块# 上游 Gunicorn 服务扩容时加 server web2:8000 即可Nginx 自动轮询 upstream shop_backend { server web:8000; } # HTTP → HTTPS 强制跳转 server { listen 80; server_name your-domain.com; # Lets Encrypt 验证路径 location /.well-known/acme-challenge/ { root /var/www/certbot; } # 其余所有请求跳转到 HTTPS location / { return 301 https://$host$request_uri; } } # HTTPS 主配置 server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; # 安全头 add_header Strict-Transport-Security max-age31536000; includeSubDomains always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; client_max_body_size 20M; # 允许上传最大 20M图片、头像等 # Gzip 压缩 gzip on; gzip_types text/plain text/css application/json application/javascript; gzip_min_length 1000; # ---------- 静态文件Nginx 直接返回不经过 Django---------- location /static/ { alias /usr/share/nginx/html/static/; expires 30d; # 缓存 30 天 add_header Cache-Control public, immutable; access_log off; } # ---------- 用户上传的媒体文件 ---------- location /media/ { alias /usr/share/nginx/html/media/; expires 7d; } # ---------- API 请求反向代理到 Gunicorn ---------- location /api/ { proxy_pass http://shop_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_read_timeout 120s; } # ---------- 健康检查端点 ---------- location /health/ { proxy_pass http://shop_backend; access_log off; } }核心设计upstream 块定义后端服务地址扩展时加server web2:8000就行Nginx 自动轮询HTTP 跳 HTTPS所有 80 端口请求 301 重定向到 443确保用户始终走加密通道静态文件分离/static/、/media/由 Nginx 直接返回不经过 Django。原来 Django 处理一个静态文件要 50msNginx 只要 2ms安全头HSTS 强制浏览器只用 HTTPS、X-Frame-Options 防点击劫持、X-Content-Type-Options 防 MIME 嗅探第四步准备环境变量文件项目根目录创建.env管理所有敏感配置# .env - 生产环境变量千万别提交到 GitDJANGO_SETTINGS_MODULEshop.settings.prodSECRET_KEY你的django-secret-keyDEBUGFalseALLOWED_HOSTSyour-domain.com,www.your-domain.comMYSQL_ROOT_PASSWORDxxxMYSQL_PASSWORDxxxREDIS_PASSWORDxxx记得在.gitignore里加上.env密码泄露到 GitHub 上可不是闹着玩的。第五步申请 SSL 证书推荐用Let’s Encrypt的免费证书certbot申请90 天自动续期# 1. 安装 certbotaptupdateaptinstall-ycertbot# 2. 临时停 Nginx释放 80 端口给 certbot 验证dockercompose stop nginx# 3. 申请证书standalone 模式certbot certonly--standalone-dyour-domain.com-dwww.your-domain.com# 4. 把证书拷到项目目录cp/etc/letsencrypt/live/your-domain.com/{fullchain.pem,privkey.pem}./nginx/ssl/# 5. 启动所有服务dockercompose up-d# 6. 验证自动续期certbot renew --dry-run证书 90 天到期certbot 会自动加定时任务续期。只要 80 端口不长期关闭续期全自动。第六步域名 SSL 备案域名这块新手容易懵完整流程捋一遍买域名阿里云、腾讯云、Cloudflare 都行。.com大概 50-70 元/年.cn更便宜DNS 解析在域名管理后台添加 A 记录把域名指向服务器公网 IPICP 备案国内服务器必须备案不备案 80/443 端口会被云厂商封掉在服务器所在云厂商后台提交一般审核 7-20 个工作日准备身份证正反面、域名证书、网站负责人核验照片、真实性承诺书公安备案ICP 备案通过后 30 天内去全国公安互联网站安全管理服务平台再备案一次小贴士赶时间可先用香港或海外服务器不需要备案但国内用户访问延迟会高 50-100ms正式运营的项目老老实实备案不然后面麻烦更多第七步上线检查清单部署完别急着收工按清单逐条检查✅ docker compose ps → 所有服务 running ✅ 浏览器访问 https://your-domain.com → 页面正常 ✅ /admin/ 后台 → 能正常登录 ✅ curl https://your-domain.com/api/ → 返回正常 JSON ✅ 静态文件 → CSS/JS/图片正常F12 看 Network ✅ 图片上传 → 功能正常图片能显示 ✅ HTTPS 证书 → 浏览器地址栏有绿色锁 ✅ HTTP 跳转 → 输入 http:// 自动跳 https:// ✅ 数据持久化 → docker compose restart数据还在 ✅ .env 文件 → 确认没提交到 Git ✅ 日志查看 → docker compose logs -f web 能看到实时日志部署顺序与踩坑经验第一次上线部署顺序很重要。别一上来就docker compose up按这个顺序来1. 服务器基础配置防火墙、SSH 密钥登录、系统更新 2. 安装 Docker Docker Compose 3. git clone 拉代码 4. 配置 .env 环境变量 5. docker compose build 构建镜像 6. 先启动数据库和缓存docker compose up -d mysql redis 7. 健康检查通过后执行迁移docker compose exec web python manage.py migrate 8. 创建管理员docker compose exec web python manage.py createsuperuser 9. 收集静态文件docker compose exec web python manage.py collectstatic --noinput 10. 申请 SSL 证书 11. 启动全部服务docker compose up -d 12. 逐项检查上线清单常见踩坑坑 1应用启动后数据库连接失败应用启动太快MySQL 还没初始化好。compose 里配了 healthcheck condition: service_healthy基本可以避免。还有问题就在应用启动脚本加个重试逻辑。坑 2静态文件 404两种可能忘了执行collectstatic或 Nginx 的 alias 路径和卷映射对不上。进容器ls /app/static/看有没有文件再检查 nginx.conf 里 alias 的路径。坑 3HTTPS 证书无效或不受信任可能是域名解析没生效DNS 缓存最长等 48 小时或证书路径写错。用openssl s_client -connect your-domain.com:443查看实际返回的证书。坑 4Gunicorn worker 频繁重启先docker stats看内存够不够。2G 内存跑 4 个 worker 可能不够减到 2 个。再检查 timeout——有些接口执行超过 120 秒需要调大。AI 加速让 AI 帮你写部署脚本和排错部署和运维的活AI 特别擅长。三个实操场景亲测好用。场景 1生成一键部署脚本“我有一个 Django 4.2 项目目录结构如下[贴 tree 输出]。服务器是 Ubuntu 22.04已装 Docker 24.0。请生成一个一键部署 shell 脚本包含环境检查、代码拉取、镜像构建、数据库迁移、静态文件收集、SSL 证书申请、服务启动。要求有错误处理、彩色日志输出、每一步都有提示。”几分钟生成一个完整 bash 脚本比手写调试快太多。场景 2排查线上问题“我的 Django Docker 部署后访问 API 返回 502 Bad Gateway。Nginx 错误日志[贴日志]。docker compose ps 输出[贴输出]。容器内 gunicorn 日志[贴日志]。请分析原因并给出修复方案。”AI 能快速定位根因——可能是 worker 全挂、端口映射错误、内存不足被 OOM kill。场景 3生成监控告警脚本“帮我写一个 Docker 健康监控脚本。每 5 分钟检查所有容器状态如果 web 容器异常则自动重启。连续重启 3 次仍失败就发告警邮件。用 bash 编写日志记录到 /var/log/shop-monitor.log。”这种运维脚本手写要半小时AI 几分钟搞定质量还高。学完来练练手日志管理配置 Nginx 的 access_log / error_log 输出到独立目录用logrotate做日志轮转防止磁盘撑爆可视化监控部署 Portainer 做 Docker 可视化管理部署 Watchtower 实现镜像自动更新负载均衡修改 docker-compose 启动 2 个 web 实例配置 Nginx upstream 的轮询和权重策略自动备份写定时脚本每天凌晨mysqldump备份数据库上传到远程 OSS 存储Docker 官方文档docs.docker.comGunicorn 部署 Django 官方指南docs.djangoproject.comLet’s Encrypt。本系列为梅雅达编程笔记原创首发于 CSDN。有问题评论区见
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表