14.1 多环境隔离 (dev / staging / prod)
一句话
多环境的目的不是 “有三套机器”,而是 “让变更在低风险环境里暴露问题,同时保证生产环境不被误操作”;隔离的维度是 网络、数据、密钥、权限、配额 五件事,少一件就会 “测试事故打到生产”。
五维隔离
| 维度 | dev | staging | prod |
|---|---|---|---|
| 网络 | 可访问公网、共享 VPC | 独立 VPC、可访问生产只读副本(可选) | 独立 VPC、默认拒绝入站 |
| 数据 | 假数据/脱敏 | 生产同构的脱敏数据 | 真实数据(加密 + 审计) |
| 密钥 | 测试凭证 | 测试凭证(与生产不同) | 生产密钥(KMS/Vault) |
| 权限 | 开发者可写 | 发布流水线可写 | 仅流水线 + 值班可写 |
| 配额 | 小 | 中(接近生产) | 按容量规划 |
关键:staging 要 “像生产”(同构、同依赖版本),否则 “测试通过” 没有意义;但 staging 不能连生产库写,只能读脱敏副本。
环境矩阵与常见配置错误
| 配置 | 常见错误 | 后果 |
|---|---|---|
| 数据库连接串 | dev 指向 staging、staging 指向 prod | 测试数据写进生产 |
| 消息队列 topic | 共用同一 topic | 测试消息被生产消费 |
| 密钥 | 三套环境同一把 key | 泄露即全线沦陷(见 13.4 密钥与凭证管理) |
| 域名/回调地址 | staging 回调打到生产 | 支付/通知串环境 |
| 定时任务 | staging 也开定时任务 | 重复跑批、重复发券 |
# 环境配置用“同一份声明 + 不同 values”,避免手工改
# values-staging.yaml
database: {host: pg-staging.internal, name: app_staging}
features: {payment_mock: true}
cron: {enabled: false} # staging 默认关掉定时任务
反模式
| 反模式 | 后果 |
|---|---|
| 环境靠 “手工配置” 维护 | 漂移成 “三套不同系统”,问题复现不了 |
| staging 连生产库(可写) | 测试数据污染生产 |
| 三套环境共用一个数据库/账号 | 隔离形同虚设 |
| staging 与生产依赖版本不同 | 测出来的结论不成立 |
| 没有 “生产变更审批/双人” | 误操作直接打生产 |
| 环境太多(dev1/dev2/qa/uat…) | 维护成本爆炸,没人管得过来 |
三条铁律
🔑 staging 要像生产,但不能连生产写。
🔑 五维隔离缺一不可;只隔离网络等于没隔离。
🔑 环境靠声明式配置生成,不靠手工。
自检
Q1 为什么 “staging 像生产” 很重要?
▸ 答案:因为很多问题只在真实规模与真实依赖下才出现:数据量大后的慢查询、依赖版本差异、并发下的竞态。如果 staging 数据量小、依赖版本不同,测试通过也证明不了生产可用。
Q2 staging 连生产只读副本有什么风险?
▸ 答案:两个:读到敏感数据(未脱敏则违规,见 3.2 个人信息保护与 GDPR);误写(权限没管住,只读变可写)。若要连,必须只读账号 + 脱敏视图 + 审计。
Q3 为什么 “三套环境共用一把密钥” 是严重问题?
▸ 答案:因为泄露面变成全线:dev 的开发者、测试环境的日志、CI 缓存都可能泄露这把 key,一旦泄露,生产也沦陷。正确做法是每环境独立密钥 + 轮换,生产密钥只对生产工作负载可见。
Q4 “环境太多” 为什么反而危险?
▸ 答案:因为维护成本与漂移概率随环境数增长:每个环境都要配网络/密钥/数据,没人能保证一致;最终出现 “只有某台机器能复现” 的困境。通常 dev / staging / prod 三套足够,临时环境用 “按需创建、用完销毁”。
Q5 如何避免 “测试消息被生产消费”?
▸ 答案:topic/队列按环境隔离(前缀或独立实例),消费组同理;用 IaC 生成名字(如 app-staging-orders),而不是手工建。共用 topic 是最典型的 “隔离漏洞”。
Q6 定时任务在 staging 该怎么处理?
▸ 答案:默认关闭,需要时手动触发或用 “mock 外部副作用” 的运行。否则 staging 会重复发券/重复对账,甚至因为连了生产下游而影响真实用户。
Q7 怎么证明 “环境隔离有效”?
▸ 答案:做故障演练:在 staging 制造 “写生产” 的尝试(如误配连接串),验证它被拦住(权限/网络/审计);再验证 “生产变更必须经流水线 + 审批”。隔离不是文档,是能被攻击验证的边界。