多环境管理与审批流程
1. 环境分层
| 环境 | 用途 | 部署时机 | 访问范围 |
|---|---|---|---|
| dev / preview | PR 预览 | PR 打开自动 | 开发者 |
| staging | 集成测试 | main 合并自动 | 团队内部 |
| production | 线上 | tag / 手动审批 | 全量用户 |
1.1 Preview 环境
每个 PR 一个临时环境(Vercel preview / K8s namespace):
# 动态 namespace
- run: |
NS="preview-pr-$}} github.event.pull_request.number }}"
kubectl create ns $NS --dry-run=client -o yaml | kubectl apply -f -
helm upgrade --install preview ./chart \
-n $NS \
--set image.tag=sha-$}} github.sha }} \
--set ingress.host=pr-$}} github.event.pull_request.number }}.preview.example.com
PR 合并 / 关闭后自动清理。
2. 环境变量管理
2.1 GitHub Environments
Settings → Environments → production / staging / dev
每个 environment 独立 secrets + variables:
jobs:
deploy:
environment:
name: production
env:
API_URL: $}} vars.API_URL }} # 从 environment variables 读
DB_URL: $}} secrets.DB_URL }} # 从 environment secrets 读
2.2 .env 文件策略
.env # 默认(开发)
.env.local # 本地覆盖(gitignore)
.env.staging # staging 变量
.env.production # 生产变量(不含密钥)
构建时注入:
# Vite
VITE_API_URL=https://api.prod.example.com npm run build
# Next.js
NEXT_PUBLIC_API_URL=https://api.prod.example.com next build
敏感变量永远不写 .env 文件,走 CI secrets / K8s secrets / Vault。
2.3 运行时 vs 构建时
| 类型 | 何时注入 | 改了怎么生效 |
|---|---|---|
| 构建时(VITE_、NEXT_PUBLIC_) | build 阶段写死 | 必须重新 build |
| 运行时(服务端环境变量) | 容器启动时读 | 重启容器即可 |
前端公开变量(API URL)走构建时。后端密钥走运行时。
3. 审批流程
3.1 GitHub Environments 审批
Settings → Environments → production → Required reviewers:
- 添加 1-2 个 reviewer
- 设等待时间(可选)
- 限制 branch(只 main / release/*)
部署到 production 时 CI 暂停等审批:
deploy-prod:
environment:
name: production
url: https://app.example.com
needs: deploy-staging
reviewer 在 GitHub UI 批准后继续。
3.2 GitLab manual gate
deploy_prod:
stage: deploy
when: manual # 手动触发
only: [main]
environment:
name: production
3.3 ArgoCD 审批
# Argo Rollout 暂停步骤
steps:
- setWeight: 10
- pause: {} # 需要人工 promote
- setWeight: 100
kubectl argo rollouts promote my-frontend -n frontend
4. 分支保护
main:
- Require PR(不能直推)
- Require status checks(CI 通过)
- Require 1+ approvals
- Dismiss stale reviews(push 新代码后旧 review 失效)
- Require linear history(no merge commit / squash only)
5. 数据隔离
| 资源 | 隔离方式 |
|---|---|
| 数据库 | 每环境独立实例 / 独立库 |
| Redis | 独立实例或不同 db number |
| 对象存储 | 独立 bucket |
| 消息队列 | 独立 topic prefix |
| 域名 | staging.example.com vs example.com |
| 密钥 | 不同 Vault path |
绝对不能:staging 用 production 数据库。泄露 / 误操作直接影响线上。
6. 回滚策略
| 环境 | 回滚方式 |
|---|---|
| preview | 删除 namespace |
| staging | 重新部署 main(自动) |
| production | kubectl rollout undo / 重新部署老 tag |
自动回滚:
- run: |
kubectl rollout status deployment/frontend -n production --timeout=300s || \
kubectl rollout undo deployment/frontend -n production
7. 环境清理
Preview 环境不清理会堆积。自动清理:
# PR 关闭时触发
on:
pull_request:
types: [closed]
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- run: |
NS="preview-pr-$}} github.event.pull_request.number }}"
kubectl delete ns $NS --ignore-not-found
8. 常见反模式
- dev / staging / prod 共用数据库:误操作影响线上
- secrets 硬编码 yaml 提交 git:泄露
- 生产无审批直推:事故概率高
- 环境变量不分层管理:staging 意外连了生产 API
- preview 环境不清理:K8s 资源 / 域名堆积
- 构建时环境变量改了不重新 build:用户看到旧 API URL
- 回滚靠"重新部署旧代码":慢。应该靠
rollout undo或旧产物直接推