跳转到内容

阶段8: 部署上线

目标: 系统有域名、HTTPS,可公开访问,CI/CD 自动部署。

模块内容
Module 16Docker 多阶段构建、CI/CD 流水线、部署策略
Module 17域名解析、Nginx/Caddy 反向代理、HTTPS/TLS

多阶段构建,最终镜像 < 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。

编排所有服务。

请帮我编写酒店预订系统的生产 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。

购买 VPS 并配置基础环境。

我要把酒店预订系统部署到一台全新的 Linux VPS(Ubuntu 22.04)。请给我一份服务器初始化脚本:
1. 系统更新:apt update && apt upgrade
2. 创建部署用户 deploy,加入 docker 组
3. 配置 SSH:
- 禁用密码登录,只允许 SSH Key
- 修改默认端口为 2222
- 禁止 root 远程登录
4. 安装 Docker 和 Docker Compose(官方源)
5. 配置 UFW 防火墙:
- 允许 2222/tcp(SSH)
- 允许 80/tcp 和 443/tcp(HTTP/HTTPS)
- 拒绝其他所有入站
- 启用 UFW
6. 配置 swap(如果内存 < 2GB,创建 2GB swap)
7. 配置自动安全更新(unattended-upgrades)
给出完整的 setup.sh 脚本,带注释。

配置域名解析。

我已经有一台 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 记录冲突
给出完整的操作步骤。

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-origin
5. www 重定向到裸域
6. 访问日志
7. Gzip 压缩
给出完整的 Caddyfile。

GitHub Actions 推送后自动部署。

请帮我为酒店预订系统配置 CI/CD 自动部署:
文件:.github/workflows/deploy.yml
流程:
1. 触发条件:push 到 main 分支 + CI 测试通过
2. 构建阶段:
- 构建 Docker 镜像
- 推送到 GitHub Container Registry(ghcr.io)
- 镜像标签:git commit SHA + latest
3. 部署阶段:
- 通过 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,包括回滚逻辑。

上传配置、启动服务、验证。

请给我酒店预订系统首次部署的完整操作清单:
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 访问正常
  • 数据库有备份策略

  1. Dockerfile 缓存失效导致构建慢: 先 COPY go.mod/go.sum 再 RUN go mod download,最后才 COPY 源码。这样只有依赖变化时才重新下载。前端同理——先 COPY package.json/package-lock.json 再 npm ci。

  2. Caddy 拿不到 HTTPS 证书: 常见原因:防火墙没开 80 端口(Let’s Encrypt HTTP-01 验证需要)、域名还没解析到服务器、Cloudflare 代理开启了(灰色云朵才行)。看 Caddy 日志 docker compose logs caddy 排查。

  3. 数据库数据丢失: docker-compose down -v 会删除 volumes(包括数据库数据)!日常用 docker compose down(不加 -v)。另外确认 volumes 声明在 docker-compose.yml 的顶层 volumes 中,而不是用的匿名 volume。

  4. 部署后前端路由 404: SPA 的路由是前端控制的,直接访问 /bookings/123 时 Caddy 找不到文件。Caddyfile 中必须配置 try_files {path} /index.html,让所有非文件请求 fallback 到 index.html。

  5. SSH 部署权限问题: GitHub Actions 的 SSH 私钥需要精确配置——注意换行符不能丢。推荐用 appleboy/ssh-actionwebfactory/ssh-agent。deploy 用户必须在 docker 组中才能执行 docker compose 命令。