阶段8: 部署上线
目标: 系统有域名、HTTPS,可公开访问,CI/CD 自动部署。
| 模块 | 内容 |
|---|---|
| Module 16 | Docker 多阶段构建、CI/CD 流水线、部署策略 |
| Module 17 | 域名解析、Nginx/Caddy 反向代理、HTTPS/TLS |
步骤 1:生产 Dockerfile
Section titled “步骤 1:生产 Dockerfile”多阶段构建,最终镜像 < 100MB。
请帮我为酒店预订系统编写生产级 Dockerfile:
要求:1. 多阶段构建: - 阶段1(builder):golang:1.22-alpine,编译 Go 二进制 - 设置 CGO_ENABLED=0 GOOS=linux - 只复制 go.mod/go.sum 先下载依赖(利用缓存层) - 再复制源码编译:go build -ldflags="-s -w" -o /app/server ./cmd/server - 阶段2(runtime):alpine:3.19 - 安装 ca-certificates 和 tzdata - 创建非 root 用户 appuser - 从 builder 复制二进制 - 用 appuser 运行 - EXPOSE 8080 - HEALTHCHECK 每 30s 访问 /health
2. 前端构建: - 阶段1:node:20-alpine,npm ci && npm run build - 阶段2:把 dist/ 复制到 Go 服务的静态文件目录,或单独用 Caddy 托管
3. .dockerignore 文件,排除 node_modules/.git/.env/data/
给出完整的 Dockerfile 和 .dockerignore。步骤 2:生产 docker-compose
Section titled “步骤 2:生产 docker-compose”编排所有服务。
请帮我编写酒店预订系统的生产 docker-compose.yml:
服务:1. app(Go 后端): - build: . - 依赖 postgres 和 redis - 环境变量从 .env 文件读取 - restart: unless-stopped - healthcheck: wget /health - 不暴露端口(通过 Caddy 反代)
2. postgres: - image: postgres:16-alpine - volumes: postgres_data:/var/lib/postgresql/data - 环境变量:POSTGRES_DB/USER/PASSWORD - healthcheck: pg_isready - restart: unless-stopped
3. redis: - image: redis:7-alpine - volumes: redis_data:/data - command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru - healthcheck: redis-cli ping - restart: unless-stopped
4. caddy(反向代理 + HTTPS): - image: caddy:2-alpine - ports: "80:80", "443:443" - volumes: - ./Caddyfile:/etc/caddy/Caddyfile - caddy_data:/data - caddy_config:/config - ./web/dist:/srv(前端静态文件) - restart: unless-stopped
volumes: postgres_data: redis_data: caddy_data: caddy_config:
networks: default 即可,所有服务同一网络
给出完整的 docker-compose.yml 和 .env.example。步骤 3:服务器准备
Section titled “步骤 3:服务器准备”购买 VPS 并配置基础环境。
我要把酒店预订系统部署到一台全新的 Linux VPS(Ubuntu 22.04)。请给我一份服务器初始化脚本:
1. 系统更新:apt update && apt upgrade2. 创建部署用户 deploy,加入 docker 组3. 配置 SSH: - 禁用密码登录,只允许 SSH Key - 修改默认端口为 2222 - 禁止 root 远程登录4. 安装 Docker 和 Docker Compose(官方源)5. 配置 UFW 防火墙: - 允许 2222/tcp(SSH) - 允许 80/tcp 和 443/tcp(HTTP/HTTPS) - 拒绝其他所有入站 - 启用 UFW6. 配置 swap(如果内存 < 2GB,创建 2GB swap)7. 配置自动安全更新(unattended-upgrades)
给出完整的 setup.sh 脚本,带注释。步骤 4:域名与 DNS
Section titled “步骤 4:域名与 DNS”配置域名解析。
我已经有一台 VPS(IP: 假设 203.0.113.50),现在要配置域名。请指导我:
1. 域名购买建议: - 推荐注册商(Cloudflare/Namesilo/阿里云) - 推荐域名格式:hotel-booking.example.com
2. DNS 配置: - 添加 A 记录:@ → 203.0.113.50 - 添加 A 记录:www → 203.0.113.50 - TTL 设为 300(5 分钟,方便调试)
3. 验证: - dig hotel-booking.example.com +short - curl -I http://hotel-booking.example.com
4. 注意事项: - DNS 生效时间(通常 5-30 分钟) - 如果用 Cloudflare,先关闭代理(灰色云朵),等 Caddy 拿到证书后再开 - 确认没有 AAAA 记录冲突
给出完整的操作步骤。步骤 5:HTTPS 配置
Section titled “步骤 5:HTTPS 配置”Caddy 自动获取 Let’s Encrypt 证书。
请帮我编写酒店预订系统的 Caddyfile:
域名:hotel.example.com
要求:1. 自动 HTTPS(Let's Encrypt)2. 前端静态文件: - /srv 目录托管前端 build 产物 - SPA 路由:try_files {path} /index.html - 静态资源缓存:Cache-Control max-age=31536000(带 hash 的文件)3. API 反向代理: - /api/* → http://app:8080 - 传递真实 IP:X-Real-IP, X-Forwarded-For - WebSocket 支持(如果需要)4. 安全头: - X-Frame-Options: DENY - X-Content-Type-Options: nosniff - Referrer-Policy: strict-origin-when-cross-origin5. www 重定向到裸域6. 访问日志7. Gzip 压缩
给出完整的 Caddyfile。步骤 6:CI/CD 自动部署
Section titled “步骤 6:CI/CD 自动部署”GitHub Actions 推送后自动部署。
请帮我为酒店预订系统配置 CI/CD 自动部署:
文件:.github/workflows/deploy.yml
流程:1. 触发条件:push 到 main 分支 + CI 测试通过2. 构建阶段: - 构建 Docker 镜像 - 推送到 GitHub Container Registry(ghcr.io) - 镜像标签:git commit SHA + latest3. 部署阶段: - 通过 SSH 连接到 VPS - 拉取最新镜像 - docker compose up -d --pull always - 等待健康检查通过 - 如果失败,回滚到上一个版本
需要的 Secrets:- SERVER_HOST:VPS IP- SERVER_USER:deploy- SSH_PRIVATE_KEY:部署用 SSH 私钥- SERVER_PORT:2222
给出完整的 deploy.yml,包括回滚逻辑。步骤 7:首次部署
Section titled “步骤 7:首次部署”上传配置、启动服务、验证。
请给我酒店预订系统首次部署的完整操作清单:
1. 本地准备: - 确认 Dockerfile/docker-compose.yml/Caddyfile 都已提交 - 确认 .env.production 已准备好(不提交到 git) - 构建前端:npm run build
2. 上传到服务器: - scp .env.production deploy@server:/home/deploy/hotel-booking/.env - scp docker-compose.yml deploy@server:/home/deploy/hotel-booking/ - scp Caddyfile deploy@server:/home/deploy/hotel-booking/ - scp -r web/dist deploy@server:/home/deploy/hotel-booking/web/dist
3. 服务器上操作: - docker compose pull - docker compose up -d - docker compose logs -f(观察启动日志)
4. 验证清单: - curl -I https://hotel.example.com → 200 - curl https://hotel.example.com/api/health → {"status": "ok"} - 浏览器访问,测试搜索和预订功能 - 检查 HTTPS 证书是否有效 - 检查 SSL Labs 评分(ssllabs.com/ssltest)
5. 常用运维命令: - 查看日志:docker compose logs -f app - 重启服务:docker compose restart app - 数据库备份:docker compose exec postgres pg_dump -U user dbname > backup.sql - 查看资源:docker stats
给出完整的操作步骤和验证命令。- Dockerfile 使用多阶段构建,最终镜像 < 100MB
- docker-compose.yml 包含 app/postgres/redis/caddy 四个服务
- 所有服务有 healthcheck 和 restart 策略
- VPS 已配置 SSH Key 登录、防火墙、Docker
- 域名 A 记录已指向服务器 IP
- Caddy 自动获取 HTTPS 证书成功
- CI/CD 流水线:push 到 main → 构建镜像 → 自动部署
- 首次部署成功,HTTPS 访问正常
- 数据库有备份策略
-
Dockerfile 缓存失效导致构建慢: 先 COPY go.mod/go.sum 再 RUN go mod download,最后才 COPY 源码。这样只有依赖变化时才重新下载。前端同理——先 COPY package.json/package-lock.json 再 npm ci。
-
Caddy 拿不到 HTTPS 证书: 常见原因:防火墙没开 80 端口(Let’s Encrypt HTTP-01 验证需要)、域名还没解析到服务器、Cloudflare 代理开启了(灰色云朵才行)。看 Caddy 日志
docker compose logs caddy排查。 -
数据库数据丢失: docker-compose down -v 会删除 volumes(包括数据库数据)!日常用
docker compose down(不加 -v)。另外确认 volumes 声明在 docker-compose.yml 的顶层 volumes 中,而不是用的匿名 volume。 -
部署后前端路由 404: SPA 的路由是前端控制的,直接访问
/bookings/123时 Caddy 找不到文件。Caddyfile 中必须配置try_files {path} /index.html,让所有非文件请求 fallback 到 index.html。 -
SSH 部署权限问题: GitHub Actions 的 SSH 私钥需要精确配置——注意换行符不能丢。推荐用
appleboy/ssh-action或webfactory/ssh-agent。deploy 用户必须在 docker 组中才能执行docker compose命令。