09 部署与发布:让 AI 安全地把版本送上生产¶
部署不是“把代码推上去”,而是一次 受控的、可回滚的、可验证的状态变更。AI 可以执行部署,但人必须掌握发布节奏和批准权。
1. 环境与晋级路径¶
local ──► dev ──► staging ──► prod
│ │ │ │
│ │ │ └─ 生产验证 + 监控
│ │ └─ 预发验收(接近生产)
│ └─ 联调、E2E、Word 报告
└─ 开发、单元测试
| 环境 | 用途 | 数据 | 谁能部署 |
|---|---|---|---|
| local | 开发 | 本地 Docker | 开发者 |
| dev | 联调/E2E | 合成数据 | AI + 开发者 |
| staging | 预发验收 | 脱敏/合成 | AI + 人工批准 |
| prod | 生产 | 真实数据 | 人工批准,AI 执行 |
规则:不允许从 local 直接跳 prod;每个环境都要有独立的配置、数据库和凭证。
2. 配置与密钥¶
2.1 12-Factor 配置¶
- 配置来自环境变量;
- 代码中不写死 URL、密钥、账号;
- 每个环境独立;
- 敏感值放 Secrets Manager / SSM Parameter Store;
- 配置变更也走版本控制(值除外)。
# 示例
DATABASE_URL=postgres://...
REDIS_URL=redis://...
JWT_SECRET=... # 来自 Secrets Manager
AWS_REGION=ap-northeast-1
LOG_LEVEL=info
2.2 密钥管理¶
- 不要把密钥提交到 Git;
- 不要把密钥写进 Docker 镜像;
- 不要在日志/错误响应中输出密钥;
- 使用 IAM Role 而不是长期 Access Key(在 AWS 上);
- 定期轮换;
- 最小权限。
3. CI/CD 流水线¶
3.1 标准阶段¶
1. checkout
2. lint / format check
3. unit test
4. integration test (Testcontainers)
5. contract test (OpenAPI)
6. build (binary / frontend dist / image)
7. security scan (deps / image)
8. push image to ECR
9. deploy dev
10. smoke test dev
11. manual approval
12. deploy staging
13. smoke test staging
14. manual approval
15. deploy prod
16. smoke test prod
17. 通知 + 记录
3.2 GitHub Actions 示例¶
name: ci-cd
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
AWS_REGION: ap-northeast-1
ECR_REPOSITORY: teamtask-api
ECS_CLUSTER: teamtask-dev
ECS_SERVICE: teamtask-api
CONTAINER_NAME: api
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
- name: Lint
run: |
gofmt -l . | (! grep .)
go vet ./...
- name: Unit tests
run: go test -race -coverprofile=coverage.out ./...
- name: Integration tests
run: go test -tags=integration ./...
- name: Build
run: go build ./cmd/api
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
working-directory: frontend
- run: npm run typecheck
working-directory: frontend
- run: npm run lint
working-directory: frontend
- run: npm run test
working-directory: frontend
- run: npm run build
working-directory: frontend
deploy-dev:
needs: [test, frontend]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: dev
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_DEV }}
aws-region: ${{ env.AWS_REGION }}
- uses: aws-actions/amazon-ecr-login@v2
id: ecr
- name: Build and push
env:
REGISTRY: ${{ steps.ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t "$REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" ./backend
docker push "$REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Render task definition
id: taskdef
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: infra/ecs/task-definition-dev.json
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
- name: Deploy
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
task-definition: ${{ steps.taskdef.outputs.task-definition }}
cluster: ${{ env.ECS_CLUSTER }}
service: ${{ env.ECS_SERVICE }}
wait-for-service-stability: true
- name: Smoke test
run: |
curl -fsS https://dev-api.example.com/healthz
curl -fsS https://dev-api.example.com/readyz
deploy-prod:
needs: deploy-dev
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # 在 GitHub 中配置 required reviewers
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_PROD }}
aws-region: ${{ env.AWS_REGION }}
# ... 与 dev 类似,替换 cluster/service/task definition
关键点:
- 用 OIDC(
role-to-assume)而不是长期 Access Key; environment: production配置人工审批;- 每个环境独立 role;
- 部署后必须冒烟;
- 失败自动停止,不自动重试到生产。
3.3 其他 CI 系统¶
- GitLab CI:
stages+rules+environment+when: manual。 - Jenkins:
pipeline+input步骤做审批。 - 你已有的
cicd-*/publish-*技能可以作为“部署执行器”,但要确保: - 输入版本号/分支明确;
- 有审批;
- 有回滚;
- 有日志。
4. AWS 部署的四种常见形态¶
4.1 前端:S3 + CloudFront¶
cd frontend
npm ci
npm run build
aws s3 sync dist/ "s3://$FRONTEND_BUCKET/" --delete
aws cloudfront create-invalidation \
--distribution-id "$CLOUDFRONT_DISTRIBUTION_ID" \
--paths "/*"
注意:
--delete会删除 S3 中不在dist/的文件,确认 bucket 只放前端产物;- 缓存策略:HTML 不缓存或短缓存,静态资源带 hash 长缓存;
- 自定义错误页回退到
index.html(SPA 路由)。
4.2 后端:ECS Fargate¶
# 登录 ECR
aws ecr get-login-password --region "$AWS_REGION" | \
docker login --username AWS --password-stdin "$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
# 构建/推送
docker build -t "$IMAGE_URI:$TAG" ./backend
docker push "$IMAGE_URI:$TAG"
# 更新服务
aws ecs update-service \
--cluster "$CLUSTER" \
--service "$SERVICE" \
--force-new-deployment \
--region "$AWS_REGION"
# 等待稳定
aws ecs wait services-stable \
--cluster "$CLUSTER" \
--services "$SERVICE" \
--region "$AWS_REGION"
4.3 后端:Lambda¶
aws lambda update-function-code \
--function-name "$FUNCTION_NAME" \
--image-uri "$IMAGE_URI:$TAG" \
--region "$AWS_REGION"
aws lambda wait function-updated \
--function-name "$FUNCTION_NAME" \
--region "$AWS_REGION"
4.4 数据库迁移¶
不要在应用启动时自动迁移生产数据库。 正确做法:
- 在 CI 中跑一个一次性的迁移任务(ECS task / Lambda / 跳板机);
- 迁移前备份/快照;
- 迁移使用 expand-contract;
- 迁移失败自动停止部署;
- 记录迁移版本和耗时。
如果使用 RDS:
aws rds create-db-snapshot \
--db-instance-identifier "$DB_ID" \
--db-snapshot-identifier "$DB_ID-pre-$TAG"
5. 基础设施即代码(IaC)¶
推荐用 Terraform / AWS CDK / CloudFormation 管理:
- 网络、ALB、ECS、RDS、S3、CloudFront、IAM、Secrets;
- 环境隔离(workspace/stack);
- 变更走 PR + plan/diff;
- 生产 apply 需审批;
- 状态文件加密存储(S3 + DynamoDB lock)。
不要让 AI 直接在控制台点资源。 控制台操作不可复现、不可审计。用 IaC。
6. AWS 登录与 Syncthing 同步¶
6.1 推荐:AWS SSO¶
aws configure sso
# 输入 SSO start URL、region、account、role
aws sso login --profile teamtask-dev
aws sts get-caller-identity --profile teamtask-dev
使用:
SSO 的优点:
- 短期凭证,自动过期;
- 不需要在本地保存长期 Access Key;
- 可以按账号/角色最小权限;
- 适合多环境切换。
6.2 为什么用 Syncthing 同步登录态¶
AWS SSO 的缓存文件在:
里面是短期 token(通常几十分钟到几小时)。如果你在多台机器/Windows + WSL 之间切换,重复登录很烦。Syncthing 可以把 ~/.aws/sso/cache 同步过去,让另一台机器直接复用未过期的登录态。
6.3 安全边界(非常重要)¶
可以同步:
~/.aws/config(不含密钥,只有 profile 配置)~/.aws/sso/cache/*.json(短期 token)
不要同步:
~/.aws/credentials(长期 Access Key)- 任何包含
aws_secret_access_key的文件 - 生产账号的长期凭证
必须做到:
- Syncthing 设备之间启用加密/可信设备;
- 不要同步到共享、公用、不受控的设备;
- 文件权限
600; - 定期清理过期 cache;
- 怀疑泄露时立即在 AWS 中撤销会话/轮换凭证;
- 生产环境优先在 CI 中用 OIDC,不依赖个人登录态。
6.4 Syncthing 配置示例¶
在 Syncthing 中添加文件夹:
Folder ID: aws-sso
Path: /home/<user>/.aws (WSL)
或 C:\Users\<user>\.aws (Windows)
Ignore patterns:
credentials
cli/cache/*
**/*.pem
只同步 config 和 sso/cache,不要整个 .aws 无脑同步。
注意:Syncthing 的 ignore 语法可能因版本不同。配置后在另一台机器确认
credentials没有被同步过去。
6.5 登录态过期怎么办¶
如果 Agent 在部署时遇到 ExpiredToken:
- 停止部署;
- 由人重新登录;
- 验证
aws sts get-caller-identity; - 继续。
不要让 AI 自动尝试刷新/绕过登录。 凭证过期是安全机制,不是 bug。
7. 发布策略¶
7.1 三种常见策略¶
| 策略 | 适用 | 优点 | 缺点 |
|---|---|---|---|
| 滚动发布 | 大多数服务 | 简单、资源省 | 新旧版本短暂共存 |
| 蓝绿 | 需要快速回滚 | 切换快、回滚简单 | 资源翻倍 |
| 金丝雀 | 高风险变更 | 影响面小 | 需要流量控制/监控 |
7.2 功能开关¶
高风险功能用 feature flag 控制:
发布后先关闭,验证基础功能,再逐步打开。出问题直接关开关,不用回滚代码。
7.3 数据库变更与发布顺序¶
永远不要先删列再部署新代码。
8. 发布检查清单(G7)¶
8.1 发布前¶
- G6 验收通过,人已签字
- CI 全绿
- 镜像/构建产物已推送,tag 可追溯
- 数据库迁移已评审,有备份/回滚
- 配置/密钥已就绪
- 发布窗口、负责人、通知渠道明确
- 回滚方案已演练或至少验证过
- 监控/告警正常
- 生产测试账号/数据准备就绪
- 人工批准生产发布
8.2 发布中¶
- 按顺序执行(迁移 → 后端 → 前端)
- 每步后检查健康检查
- 观察错误率/延迟/日志
- 冒烟测试通过
- 记录发布版本、时间、操作人
8.3 发布后¶
- 线上 E2E(见 10 线上验证)
- 监控基线对比
- 用户反馈渠道畅通
- 发布记录写入
docs/05-release/ - 更新 CSV 的
prod_deploy_status
8.4 回滚条件¶
出现以下任一情况,立即回滚:
- 错误率显著上升;
- P0/P1 功能不可用;
- 数据写入错误;
- 性能严重下降;
- 安全事件。
回滚步骤:
9. 部署 Agent 提示词¶
9.1 部署到 dev¶
你是发布工程师。请把 main 分支的最新提交部署到 dev。
前提:
- CI 已全绿
- 镜像 tag 使用 commit SHA
- 目标:ECS cluster=teamtask-dev, service=teamtask-api
- 前端:S3 bucket=teamtask-dev-frontend, CloudFront distribution=...
步骤:
1. 确认 `aws sts get-caller-identity` 是 dev 账号。
2. 构建并推送镜像。
3. 更新 ECS 服务并等待稳定。
4. 执行前端构建和 S3 同步 + CloudFront 失效。
5. 跑冒烟:/healthz, /readyz, 登录页 200。
6. 输出:镜像 tag、任务定义版本、部署时间、冒烟结果、任何错误。
7. 更新 docs/05-release/dev-<date>.md 和 CSV。
约束:
- 不要操作 prod 资源。
- 不要修改 IaC。
- 遇到权限/凭证错误,停止并报告。
9.2 部署到生产¶
你是发布工程师。请准备生产发布,但不要直接执行。
输入:
- 版本:<commit/tag>
- 变更内容:<release notes>
- 回滚版本:<previous tag>
- 迁移:<有/无,文件列表>
请输出:
1. 发布前检查清单的逐项结果
2. 将要执行的命令(按顺序)
3. 每一步的验证方法
4. 回滚命令
5. 风险和注意事项
等我明确回复“批准发布”后,再执行。
生产部署必须有人类批准。 不要让 Agent 从“准备”直接滑到“执行”。
10. 常见问题¶
问题 1:本地能跑,线上 500¶
排查:
- 环境变量缺失/不同;
- 数据库迁移未执行;
- 权限/IAM role 不同;
- 网络/安全组;
- 时区/编码;
- 依赖版本不同(锁文件)。
问题 2:部署后旧页面还在¶
- CDN 缓存;
- Service Worker;
- 浏览器缓存;
index.html被长缓存。
处理:HTML 短缓存/no-cache,静态资源带 hash,CloudFront 失效。
问题 3:迁移把线上锁住¶
- 大表加索引未用
CONCURRENTLY; - 长时间事务;
- 未分批回填。
处理:expand-contract、并发索引、分批、低峰执行。
问题 4:AWS 登录态过期¶
aws sso login重新登录;- 检查 Syncthing 同步是否成功;
- 不要让 Agent 自动重试到锁定。
问题 5:AI 在生产执行了危险命令¶
预防:
- 生产凭证不放在开发环境;
- 使用只读角色做验证;
- 写操作需人工批准;
- 命令白名单/包装脚本;
- 审计日志;
- 备份。
11. 本章交付清单¶
- CI/CD 流水线可用
- dev/staging/prod 环境独立
- 密钥管理合规
- 数据库迁移有备份/回滚
- 发布检查清单完成
- 人工批准记录
- 冒烟测试通过
- 发布记录已归档
- CSV 的
prod_deploy_status已更新
下一章:10 线上验证与运营 —— 在生产环境再走一遍用户流程,用同一套证据链完成最终验收。