发布与部署
Go 单仓库 · Docker Compose · 单 VM 生产 · 向前迁移 · 镜像回滚
发布原则
| 原则 | 说明 |
|---|---|
| 主干可部署 | 合并前必须通过格式化、测试、构建和基础安全检查 |
| 镜像不可变 | 每次发布使用 git sha 作为镜像 tag |
| 数据库只向前 | 生产不依赖 down migration 回滚 |
| 先备份再迁移 | 涉及 schema 或关键数据变更前先做备份 |
| 小步发布 | 每次只发布一个可验证切片,避免同时改订单、支付、库存 |
| 可快速回滚 | 代码回滚通过切换旧镜像,数据问题走向前修复或备份恢复 |
CI Pipeline
| 步骤 | 命令 | 要求 |
|---|---|---|
| 格式化 | gofmt -w / CI 检查 diff | 必须无格式化差异 |
| 静态检查 | go vet ./... | 必须通过 |
| 单元测试 | go test ./... | 必须通过 |
| 漏洞扫描 | govulncheck ./... | 高危阻断发布 |
| Migration 检查 | migrate -path migrations -database $TEST_DATABASE_URL up | 临时库可完整迁移 |
| 镜像构建 | docker build -t dingwei/api-server:$GIT_SHA . | 必须成功 |
| 冒烟测试 | docker compose up -d + health check | 核心接口可用 |
核心交易模块还必须有集成测试:下单成功、库存不足、重复下单幂等、支付回调重复通知、支付成功确认库存、30 分钟超时取消、退款成功回滚库存。
Docker Compose 部署
yaml
services:
api-server:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/api-server"]
ports: ["8080:8080"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
admin-api:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/admin-api"]
ports: ["8081:8081"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
worker:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/worker"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
postgres:
image: postgres:16
volumes: [pgdata:/var/lib/postgresql/data]
restart: unless-stopped
valkey:
image: valkey/valkey:8
volumes: [valkeydata:/data]
restart: unless-stopped
volumes:
pgdata:
valkeydata:api-server、admin-api、worker 使用同一个镜像,不同启动命令。
发布流程
- 合并前跑完整 CI。
- 构建镜像:
dingwei/api-server:{git_sha}。 - 推送镜像仓库。
- 生产执行发布前备份:
pg_dump -Fc上传 COS。 - 停止 worker:避免迁移期间消费旧事件。
- 执行 migration:
migrate -path migrations -database "$DATABASE_URL" up。 - 更新
.env.production的APP_VERSION={git_sha}。 - 执行
docker compose pull && docker compose up -d。 - 跑冒烟测试。
- 恢复 worker 并观察 30 分钟。
建议发布窗口:周二/周四 14:00-16:00。支付、库存、订单相关发布避开运营高峰。
冒烟测试
| 检查 | 目标 |
|---|---|
GET /healthz | api-server 可用 |
GET /admin/healthz | admin-api 可用 |
GET /api/products | 商品列表可读 |
POST /api/orders/preview | 计价可用 |
| worker 日志 | outbox_events 可轮询,无启动错误 |
| 指标 | http_requests_total、outbox_pending_count 正常暴露 |
支付回调不能在生产用真实资金随意测试,需提供微信沙箱或固定验签样例进行 staging 验证。
Migration 规范
| 规则 | 说明 |
|---|---|
| 只向前 | 生产不依赖 down 回滚 |
| 小步迁移 | 一个 migration 只做一件事 |
| 先兼容代码 | 新列先 nullable 或有默认值,代码上线稳定后再收紧 |
| 禁止直接删列 | 先废弃,至少一个版本后再删除 |
| 大表索引 | 使用 CREATE INDEX CONCURRENTLY |
| 禁止手改生产库 | 所有 schema 变化走 migration |
| 数据修复脚本 | 必须可重复执行、可审计、可回放 |
命名:
text
migrations/
├── 000001_create_users.up.sql
├── 000001_create_users.down.sql
├── 000002_create_products.up.sql
└── 000002_create_products.down.sql虽然保留 down 文件用于本地开发,生产故障默认不执行 down。
回滚方案
代码回滚
bash
# 1. 将 APP_VERSION 改回上一个稳定 git sha
vim .env.production
# 2. 重新拉起旧镜像
docker compose pull
docker compose up -d api-server admin-api worker
# 3. 检查健康状态
docker compose ps
docker compose logs --tail=200 api-server worker数据库问题
| 场景 | 处理 |
|---|---|
| 新增列后代码异常 | 回滚代码,保留新增列 |
| 新索引导致性能问题 | 新 migration 删除索引或禁用相关查询 |
| 数据修复脚本写错 | 停止写入,基于备份和审计日志评估恢复 |
| 破坏性 schema 已执行 | 从备份恢复到新库,对比后人工修复,不直接覆盖生产 |
回滚决策
| 症状 | 动作 |
|---|---|
| 订单创建错误率 > 5% 持续 5 分钟 | 立即回滚代码 |
| 支付回调连续失败 | 停 worker,回滚 payment/order 相关版本,保留回调原文 |
| worker 堆积 > 100 持续 15 分钟 | 暂停新发布,排查后重试或扩 worker |
| 非关键后台 UI 问题 | 走 hotfix,不影响用户端 |
依赖管理
| 类型 | 策略 |
|---|---|
| Go patch | CI 通过可快速合并 |
| Go minor | 需要 review changelog 和核心测试 |
| Go major | 单独排期,写 ADR 或升级说明 |
| 安全漏洞 | 高危 24 小时内处理 |
| Docker 基础镜像 | 固定 major/minor,升级前 staging 验证 |
| PostgreSQL / Valkey | 单独维护窗口,必须有备份和恢复演练 |
关键依赖:
| 依赖 | 用途 | 风险 |
|---|---|---|
gin-gonic/gin | HTTP 路由 | 中 |
jackc/pgx 或 database/sql driver | PostgreSQL | 高 |
redis/go-redis | Valkey 客户端 | 中 |
golang-migrate/migrate | 数据库迁移 | 高 |
| 微信支付适配代码 | 支付签名/验签/退款 | 高 |
vitepress | 文档站 | 低 |
依赖升级 PR 必须写明:升级原因、breaking changes、验证命令、回滚方式。
发布检查清单
发布前
text
[ ] gofmt / go vet / go test 通过
[ ] govulncheck 无阻断项
[ ] migration 在临时库执行成功
[ ] 已生成并上传 PostgreSQL 备份
[ ] 当前版本号和目标版本号已记录
[ ] 支付、库存、订单相关风险已 review
[ ] 回滚镜像 tag 已确认发布中
text
[ ] worker 已停止或确认不会处理不兼容事件
[ ] migration 已执行成功
[ ] api-server / admin-api / worker 均已更新
[ ] 健康检查通过
[ ] 冒烟测试通过发布后
text
[ ] 观察 30 分钟错误率、延迟、支付回调、订单创建、worker 堆积
[ ] 检查 outbox_events failed 数量
[ ] 发布记录写入变更日志
[ ] 如有异常,按回滚矩阵执行