面试 · 方案设计型
系统性取舍(高级岗)。每题给选型对比 + 设计要点 + 注意事项。考察系统性思维、取舍意识、生产经验。
子类 1:CI/CD 架构设计#
题目1:给 20 人团队从零设计 CI/CD + 多环境配置管理#
设计需求: 20 人技术团队,10 个微服务,AWS 单云,已有 EKS 集群。需要从零设计 CI/CD 体系,包含代码托管、CI 构建、制品管理、多环境部署(QA/PRE/PROD)。团队规模预计 1 年内增长到 50 人。
方案设计:
选型决策:
- 代码托管:GitHub(海外)或 Codeup(国内)
- CI:GitHub Actions(海外)或 云效 Flow(国内)
- 镜像仓库:AWS ECR
- GitOps:ArgoCD 2.13+(开发同学需要 UI 看部署状态)
- 配置语言:Kustomize(业务服务)+ Helm(第三方组件)
- 部署模式:Pull-based GitOps(CI 不碰集群)
五层架构:
①代码层 → ②CI层 → ③制品层 → ④GitOps层 → ⑤运行时层
GitHub Actions ECR ArgoCD EKS关键设计点:
GitOps 仓库目录结构(目录即配置):
textgitops/ ├── argocd/applicationsets/ # ApplicationSet 定义 ├── base/{project}/{service}/ # 共享模板(deployment/svc/pdb) ├── clusters/{env}/applications/{project}/{service}/ # overlay ├── scripts/deploy.py # CI 与 GitOps 的胶水 └── dockerfiles/{project}/{service}.Dockerfile镜像 tag 策略:
{commit短hash}-{YYYY-MM-DD-HH-MM-SS},全环境复用同一镜像(一次构建多环境晋升)。绝不用latest(不可溯源、不可回滚)。deploy.py 是 CI 与 GitOps 唯一通路:CI 构建完镜像后调 deploy.py → 改 GitOps overlay 的 newTag → git push → ArgoCD 自动 sync。CI 不直接连 K8s API。
多环境晋升流程:QA(自动部署)→ schema check(pre warning + post fail)→ PRE(人工审批)→ PROD(人工审批 + 灰度)。
ApplicationSet Matrix Generator:clusters × git directories 笛卡尔积,新服务建目录即被纳管,不需要手建 Application。
分支策略:GitHub Flow(feature → MR → main,main 永远可发)+ main 分支保护(禁直推,强制 MR)。
4 套标准模板覆盖 80% 场景:
unified-template:US+CN 不灰度unified-canary-template:US+CN 需灰度us-only-template:仅 UScn-only-template:仅 CN
注意事项:
- GitOps 闭环完整性:ApplicationSet 必须被 root Application 自管理(app-of-apps 模式),否则改 ApplicationSet 要手动 kubectl apply。
- 多 ArgoCD 凭据路由:如果有多 ArgoCD 实例(历史遗留),deploy.py 要维护显式的服务到 ArgoCD 映射,不要按 region 推断。
- CN 构建机特殊坑:Dockerfile 禁
# syntax=docker/dockerfile:1和--mount=type=cache(访问不了 Docker Hub),基础镜像用国内 mirror。 - Schema Check 双 Stage:pre 部署前 warning + post 部署后 fail,把破坏性 DDL 关在 PROD 之外。
- 回滚 = git revert:GitOps 声明式,ArgoCD 自动收敛回旧 tag,不需要重新跑流水线。
- 上线节奏:分 4 阶段(奠基 1-3 周 → CI 闭环 4-6 周 → 扩面+防护 7-12 周 → 收尾+治理 13-26 周),不要一刀切上线。
题目2:设计 3 个标准模板覆盖 80% 服务#
设计需求: 10 个微服务,需要设计标准化的 CI/CD 模板,让新服务接入从 1 天降到 1 小时。
方案设计:
3 套模板设计:
| 模板 | 命名规则 | 适用场景 | Stage 数 |
|---|---|---|---|
standard-template | {PROJECT}-{SERVICE} | 标准服务,单云单环境 | 6 |
canary-template | {PROJECT}-{SERVICE} | 核心服务,需要灰度 | 8 |
infra-template | infra-{SERVICE} | 基础设施服务,无审批 | 4 |
standard-template 流程:
构建 → QA(auto) → schema-check-pre(warning) → 审批 → PRE(manual)
→ schema-check-post(fail) → 审批 → PROD(manual)关键设计点:
命名即配置:流水线名被
step_parse用cut -d'-'拆成变量。us-goalfymax-relay→ REGION=us, PROJECT=goalfymax, SERVICE=relay。命名是强约束,不能随意改。YAML Anchors 去重:
&deploy-runsOn(构建机池)、&fetch-script(拉 deploy.py)、&ding-success/&ding-fail(钉钉通知)、&validators(审批人)——这些重复片段用 anchor 引用,改一处全模板生效。变量组分层:
service_common_env_group(通用):REGISTRY/REGION/AK/SK/钉钉us_env_group(US 线):US 特有配置cn_env_group(CN 线):CN 特有配置db_schema_check_group:schema 检查相关
审批门(OR 门):核心 QA 3 人 / PRE·Canary 2 人 / US 标准 2 人 / CN 标准 1 人。任一人过即可(OR 门),避免单点阻塞。
钉钉通知:成功/失败分别推不同模板,@触发人(用
${DING_AT_MOBILES}变量组,不要写${DINGTALK}未定义)。
注意事项:
- 模板化的隐性收益:① 流水线变更可批量推(改模板下次新建自动用新值);② review 标准变明确(和模板比多了什么少了什么);③ 故障复盘归因变快(是模板设计问题还是服务特殊性问题)。
- 不要为了 100% 覆盖强行模板化:20% 特殊服务走自定义路径并标记"长期例外"的原则同 1-概念·子类1·题目5,此处不赘。
- 模板版本管理:模板入 Git 仓库
gitops/pipeline-templates/,变更走 PR Review。 - 云效 Flow 特殊坑:stage 间永远线性(要并行双线必须同 stage 多 job);
branchesFilter必须字符串;cloneDepth必须字符串"0";step 级envs:字段被忽略,环境变量必须在run:里 export。
题目3:设计 PR 隔离环境#
设计需求: 5-50 人后端团队,并行 PR 常态 ≥3 个,需要每个 PR 有独立验证环境,不互相覆盖。
方案设计:
选型对比:
- 方案 A(共享 QA):淘汰——互相覆盖、数据污染、排队
- 方案 B(每 PR 独立域名+证书+Ingress):淘汰——域名/证书运维负担重、清理麻烦
- 方案 C(PR Pod + X-env header 路由 + 自动清理):推荐
方案 C 架构:
开发者 → push feat 分支
↓
CI 构建 + deploy.py 渲染 PR overlay → git push
↓
ArgoCD ApplicationSet 扫到新目录 → 自动 sync
↓
PR Pod Ready → 机器人评论"环境就绪"
↓
开发者浏览器装 ModHeader 加 X-env: pr-{env_id}
↓
入口 HTTPRoute 按 header 路由到 PR Pod
↓
PR 关闭 → webhook 触发清理 → ArgoCD GC关键设计点:
路由层不引入新域名:入口 Gateway 上挂 HTTPRoute,header
X-env=pr-{env_id}命中时打到 PR Service,否则走 base Service。每多一个 PR = 一个 HTTPRoute 资源(Kustomize patch 自动生成),不是一套域名/证书/Ingress。同 namespace + namePrefix:PR Pod 用
pr-{env_id}-前缀,复用 base 的 ServiceAccount/Secret/ConfigMap。不为每个 PR 拷贝这些资源。ApplicationSet Matrix Generator:监听
clusters/us-qa/applications/*-pr/*目录,新目录出现自动生成 Application。三层清理保障:
- 触发 1:PR 关闭 webhook → Lambda 删 overlay
- 触发 2:CronJob 每天扫 overlay 时间戳 + 远程分支存在性(TTL 14 天)
- 触发 3:容量水位(PR Pod 数 >30 时按 LRU 清理)
数据库隔离(方案 A:共享 DB + env_tag 字段隔离):
- 应用层中间件注入
env_tag = PR_ENV_ID - DB trigger 兜底(
env_tag为空时 SIGNAL ERROR) - 读路径默认过滤
env_tag = PR_ENV_ID OR env_tag = 'main'
- 应用层中间件注入
v2 升级(baggage 路由派):W3C baggage 跨 hop 透传 + OTel propagator 注入 + 下游无副本自动回 baseline。比克隆派省 85-90% 资源。
注意事项:
- includeSelectors 不够:base Service 的 selector 会反向选 PR Pod → 必须把 deployment selector + pod label + service selector 全部替换成
pr-{env_id}-{base_app}。 - CloudFront 默认不转发自定义 header:要配自定义 cache policy 把
X-env加入 whitelist(参与缓存键 + 向源转发),否则 PR 流量被缓存命中 base Pod。 - 异步消费者类服务不直接开 PR 隔离:PR Pod 和 base 共享 consumer group → 按概率截走消息用旧代码处理。要先做 per-PR consumer group 前缀 + backend 透传 X-env。
- env_id 命名规则:分支名 slug 化(小写、只保留 a-z0-9-)→ 截断到 40 字符(K8s label value 最大 63 字符,留余量给
pr-前缀和服务名)。 - feature 分支多次 push 用同 image tag 不会更新:tag 必须含 git sha + 时间戳,不要用分支名当 tag。
- 不建独立环境的克制:拓扑隔离解决不了数据隔离(DB/Kafka 复制不了),独立环境给假安全感;基于数据(事故频次)决策。
题目4:设计渐进式发布体系#
设计需求: 核心服务需要从"全量发布"升级到"渐进式交付"——只放一部分流量到新版、用指标自动判断好坏、好就逐步放量、坏就自动回滚。
方案设计:
5 大灰度策略选型:
- 蓝绿 Blue-Green:双倍资源,秒级切流,适合要求干净切换
- 金丝雀 Canary:低资源,细粒度可控,渐进式交付主力
- 滚动 Rolling:K8s 默认,无额外资源,低风险变更
- 影子 Shadow:镜像流量不返回,零用户风险,高风险变更先验
- 特性开关 Feature Flag:与部署解耦,秒级熔断,A/B 测试
推荐组合:金丝雀(Argo Rollouts)+ 特性开关(LaunchDarkly/Unleash)
架构设计:
git push 新镜像
↓
Argo Rollouts Controller
├── ① 按 Rollout.steps 调整流量权重(改 Istio VS)
│ setWeight 5% → pause 5m → analysis → setWeight 25% → ...
├── ② 到 analysis 步 → 起 AnalysisRun
│ query Prometheus 对比 canary vs baseline
│ ├── 成功率 ≥ 99%
│ ├── P99 延迟 ≤ 500ms
│ └── 错误率 ≤ baseline + 阈值
├── ③ 达标 → 下一步放量
└── ④ 劣化 → setWeight 0 自动回滚(秒级切回 baseline)关键设计点:
金丝雀分析(Canary Analysis)的 5 个门控:
- 足够样本:低于最小流量阈值豁免分析(样本不足不下结论)
- 相对比较:canary vs baseline 同时段对比(不是 vs 历史)
- 容忍带:成功率 ≥ baseline-1% / 延迟 ≤ baseline×1.1(不要求完全一致)
- 连续确认:连续 N 次分析通过才晋级(单次抖动不算数)
- 冷启动豁免:canary 刚起 JIT/缓存未热,前 M 分钟不计
染色与路由:
- 按身份(cookie/header 白名单)→ 内部人员先试
- 按比例(权重分桶)→ 5%→25%→50%→100% 渐进放量
- 跨 hop 透传:W3C baggage + OTel propagator
自动回滚触发:
- 金丝雀分析失败(连续 N 次指标不达标)
- SLO 错误预算烧速超门槛(canary 流量段 1h 烧 2% 月预算)
- 关键指标劣化
特性开关与部署解耦:
- 部署 = 把带新能力的代码发上去(开关默认关)
- 放量 = 改开关(不重新部署)
- 熔断 = 关开关(秒级)
成熟度演进路线:
- L1 手动灰度(现状常见):手动放量 + 人盯 Grafana + 手动回滚
- L2 半自动:指标看板自动化 + 金丝雀分析(人看结果手动晋级)
- L3 全自动(目标):Argo Rollouts/Flagger + canary analysis 自动晋级 + SLO 门控自动回滚 + 特性开关解耦
注意事项:
- 状态层不灰度:DB/Kafka/Redis 共享,灰度限无状态行为差异;schema 变更走 schema_check + 向前兼容。
- mesh 不透传 baggage 跨 hop:app 调下游要 OTel propagator 注入,漏接服务 → 半 canary 半 baseline;Kafka 显式 inject/extract、Redis key 前缀。
- 缓存隔离:灰度两版若共用 CDN 缓存会串味,cache key 要带染色字段。
- CloudFront 权重传播非瞬时:改权重秒级~数十秒、不同边缘 PoP 不同步;硬回滚靠 function 内置
DISABLED常量(改函数 publish),不能只指望 KVS 归 0。 - 不要停在 L1 手动灰度:纯手动放量 + 靠人盯指标,没有指标驱动的自动晋级/回滚,MTTR 受人响应速度限制。
子类 2:可观测性体系设计#
题目1:设计 Prometheus + Grafana 监控架构#
设计需求: 100 个微服务,2 个 K8s 集群(US + CN),需要设计可观测性监控架构。
方案设计:
三层架构:
①采集层:exporter + ServiceMonitor
├── node-exporter(节点指标)
├── kube-state-metrics(K8s 对象指标)
├── YACE(AWS CloudWatch 指标拉进 Prometheus)
├── blackbox-exporter(外部可达性探测)
└── 业务 /metrics(应用自定义指标)
②存储层:Prometheus + 远端存储
├── 每集群一个 Prometheus(replicas 2, retention 15d)
├── remote_write 到中央 VictoriaMetrics/Mimir(长期存储)
└── externalLabels 标记 cluster/region/env
③展示层:Grafana + Alertmanager
├── Grafana 统一看板(跨集群查询)
└── Alertmanager 统一告警路由关键设计点:
每集群一个 Prometheus:不要一个 Prometheus 管所有集群(网络打通难 + 单点压力)。每集群本地 Prometheus 抓取,通过 remote_write 发到中央存储。
Prometheus CR 关键配置:
yamlspec: replicas: 2 # HA scrapeInterval: 30s evaluationInterval: 30s retention: 15d retentionSize: 45GB serviceMonitorSelector: {} # 空 = 全收(不靠 release 标签) ruleSelector: {} # 空 = 任何 PrometheusRule 都加载 externalLabels: {cluster: us-prod, env: production}注意:
ruleSelector: {}空 = 全收。如果配了matchLabels: {release: monitoring},PrometheusRule 的 metadata.labels 必须匹配否则不加载(静默失效)。YACE 把 AWS 指标拉进 Prometheus:CloudWatch 的 RDS/ElastiCache/ACM 等指标通过 YACE 转 Prometheus 格式。注意:① 资源必须有 tag 才被发现;② metric 名转义诡异(
ElastiCacheProcessingUnits→aws_elasticache_elasti_cache_processing_units_sum),写规则前先curl yace:5000/metrics | grep ^aws_确认;③ dimension 大小写敏感 + 用{dimension_X!=""}过滤 global 聚合行。Alertmanager 统一告警路由:
yamlroute: receiver: webhook-dingtalk-observe group_by: [alertname, namespace, severity] group_wait: 30s group_interval: 5m repeat_interval: 30m routes: - match: { alertname: Watchdog } receiver: dead-mans-switch # 心跳走独立通道 - match: { severity: P0 } receiver: dingtalk-p0Watchdog 心跳兜底:一条
alert: Watchdog expr: vector(1)永远 firing,配独立 receiver 推 healthchecks.io。30s 收不到心跳 → 反向告警到独立钉钉群(不能与主告警同群,否则主链路挂了反向也挂)。"持久化资源必建告警"纪律:新建 PVC/RDS/EBS 的同一 PR/操作必须包含 PrometheusRule,否则会"满了 N 天没人发现"(Loki filesystem PVC 撑满 CrashLoop 20 天无人知是典型案例,详见 3-原理·Loki 写入路径题)。
注意事项:
- 高 cardinality 是 Prometheus OOM 最常见原因:不要把 user_id/request_id 当 label,会导致 index 爆炸。
- ruleSelector 不匹配是静默失效:PrometheusRule 的 metadata.labels 必须匹配 Prometheus.spec.ruleSelector,否则规则不加载且不报错。必须从
/api/v1/rules接口验证规则真的被加载。 - configmap 热更新延迟:改 webhook-dingtalk 模板后
/-/reload只重载 config.yml,模板文件要rollout restart。 - resolved 通知黑洞:钉钉关键词白名单要同时覆盖 firing + resolved("告警/运维/恢复"),否则 firing 能发但 resolved 被拒(原理详见 3-原理·Alertmanager 路由题)。
- Loki 用对象存储不要用 filesystem:filesystem 后端 PVC 会满,生产用 S3/OSS + retention 自动清理。
题目2:设计多云告警统一治理体系#
设计需求: 现有 5 套告警系统并行(US-Prom / sandbox-Prom / CN-Prom / 阿里云 CMS / 业务侧 SQL 轮询),200 条规则散落,告警直接捕获率仅 13%。需要统一治理。
方案设计:
选型对比:
- 方案 A(维持现状):淘汰——故障频率到一定程度后修补速度赶不上规则腐化速度
- 方案 B(全量迁到一套):淘汰——业务侧 103 条规则中 30+ 条是基于业务表的复合 SQL,改写成 PromQL 需要业务 emit metric,开发改造成本不可控
- 方案 C(保留两套但治理 + 互通):推荐——不强求技术统一,只要求"出口统一、规则不重叠、定期对账"
方案 C 架构:
①基础设施/时序指标 → Prometheus → Alertmanager
②业务复合判定 → 业务侧 SQL 引擎 → webhook bridge → Alertmanager
③云资源 → YACE → Prometheus → Alertmanager
↓
统一 Alertmanager(route/inhibit/silence)
↓
prometheus-webhook-dingtalk → 钉钉群
↓
Watchdog → healthchecks.io → 反向告警独立群关键设计点:
Alertmanager 是唯一收敛点:业务侧通过 webhook bridge(POST 到 Alertmanager API v2
/api/v2/alerts)注入。silence/inhibit/route/模板渲染只有一处。渠道梳理 + 禁止复用历史 Lambda:扫所有 SNS topic + Lambda,发现硬编码业务名的 Lambda(如
title = "RabbitMQ 告警: ...")立即记入"禁止复用清单"。新增资源告警走独立 SNS + 独立 Lambda,绝不复用历史 Lambda。silence 审计与负匹配规范:
- 周巡检 CronJob 扫长期 silence(>7 天)+ 永久 silence +
.+全匹配 - 所有"全部 silence"必须用负匹配排除 Watchdog:
alertname!=Watchdog - Watchdog 被误杀检测脚本退出码 2 = 立即告警
- 周巡检 CronJob 扫长期 silence(>7 天)+ 永久 silence +
规则归档 + 对账:
- 所有 PrometheusRule 入 GitOps(
clusters/{env}/monitoring/) - 对账脚本:git yaml 规则数 vs Prometheus API 加载的规则数,不匹配报 DRIFT
- 每周巡检必须含"规则总数 vs 集群规则总数对账"
- 所有 PrometheusRule 入 GitOps(
业务侧 webhook bridge:业务侧 SQL 轮询不动业务代码,让它 POST 到 sidecar,sidecar 翻译成 Alertmanager API v2 格式。
endsAt = now + 5min利用 Alertmanager 的"超时自动 resolved"机制——业务侧每分钟轮询,停止续推 5 分钟后自动 resolved。
注意事项:
- 告警体系是有腐化速度的活物:规则只增不减是默认状态、silence 是写完就忘的状态、Lambda/SNS 这种"不在 GitOps 里"的资源最容易腐化。半年没治理就是失控。
- 必须主动制造一次 firing 验证全链路:上线告警不能只看 kubectl get prometheusrule,必须 curl 测 firing + resolved 两类消息都真能推到目标群。
- 老 Lambda 退役要做并行对账 14 天:把老 Lambda 接过的所有 alarm 列出来,确认每条都已通过 YACE 在 Prom 侧覆盖,并行 14 天看两边告警次数是否吻合,吻合后再下线。
- 统一告警网关:在钉钉前加聚合/去重/路由层,或把业务侧引擎也经 Alertmanager,避免"同一故障三套系统各发一条"。
题目3:设计 SLO + 告警体系#
设计需求: 把告警范式从"症状阈值"(CPU > 80%)升级到"用户旅程 SLO + 错误预算烧速"。
方案设计:
监控对象多类目体系(关键纠错:不是所有监控都叫 CUJ):
├── 1. CUJ-based SLO ← 用户旅程,SLO + burn rate(允许错误预算)
├── 2. Invariant 监控 ← 系统必须保持的属性,零容忍异常告警(不积预算)
├── 3. 运维 SOP 健康度 ← 运维动作成功率,不进 SLO 看板
├── 4. 横向技术依赖 ← 跨 CUJ 共用基础设施,RED 信号 + inhibit
├── 5. 黑盒探测 ← synthetic monitor,兜底
└── 故障模式参考库 ← 不独立监控,是 runbook 排查项关键区别:CUJ 失败 → 用户感知 → 允许累积错误预算 → burn rate 告警;Invariant 违反(数据泄漏/计费错)→ 系统属性破缺 → 零容忍立刻告警。
SLO 标准设计:
定义用户旅程(14 个真 CUJ 示例):
- CUJ-1 登录成功率
- CUJ-2 对话完成率
- CUJ-3 沙箱拉起成功率
SLI 公式(good events / total events):
promql# SLI-1 登录成功率 sum(rate(goalfymax_sso_callback_total{status="success"}[5m])) / sum(rate(goalfymax_sso_callback_total[5m]))SLO 目标 + 错误预算:
- SLO 99.5%/30d → 错误预算 = (1-99.5%)×30d = 允许 3.6h 不可用/月
- 把"还能坏多久"变成可量化的预算
多窗口烧速告警(multi-window multi-burn):
级别 短窗烧速 短窗 含义 通道 P0(叫醒) 14.4× 1h 1h 消耗 2% 月预算 pager 群 P1(工时) 6× 6h 6h 消耗 5% 月预算 观察群 看板(趋势) 1× 3d 3d 消耗 10% 月预算 不发钉钉 为什么"多窗口":短窗判"现在烧得快不快"(快速发现)× 长窗判"是不是真的在持续烧"(防误报)。两个都超阈值才告警。
预算耗尽政策(需业务老板签字):
- ≥50% 剩余 → 正常发布
- 50%~25% → 发布前 review,禁灰度>50%
- 25%~10% → 仅修复性发布,新功能冻结
- <10% → 完全冻结,全员投入修复
合成监控兜底真实流量盲区:
- cuj-prober 主动拨测 5 条链路(登录/沙箱/文件/部署/访问 URL)
- 60s 一轮,7×24 主动打,能在无真实流量时发现链路断
- counter SLI ground truth + 自定义 buckets + OTel trace → Tempo
注意事项:
- 不是所有监控都叫 CUJ:业界标杆才 10-15 个 CUJ,第一版调研把 71 个点全叫 CUJ 是错的——把"跨用户隔离"(系统不变量)、「版本回滚」(运维动作)、「idcipher 改造」(技术债)都混进 CUJ。
- SLO 不是越高越好:100% SLO 意味着零错误预算,无法发版无法创新。Google 推荐 99%-99.95% 区间。
- SLI 要可度量可埋点:如果当前没有埋点,先做埋点改造再定 SLO。
- SLO 要业务方签字:SLO 决定了"还能坏多久",影响发布节奏,必须有业务方认可。
- 预算耗尽政策不能是数字摆设:要真的执行"预算耗尽冻结发布",否则 SLO 体系形同虚设。
- 烧速告警用 Sloth 自动生成:手写 multi-window multi-burn-rate 规则极易写错、难维护。Sloth 声明 SLO objective + SLI 查询,自动生成 recording rule + 三档烧速 alert。
题目4:设计日志采集方案选型#
设计需求: 100 个微服务,多云(AWS + 阿里云),日志量约 100GB/天,需要统一日志采集和查询方案。
方案设计:
选型对比:
- EFK(Elasticsearch + Fluentd + Kibana):全文索引快,但存储成本高、运维重
- Loki + Promtail:只索引 label,成本低,云原生友好
- Datadog Logs:SaaS 一站式,按量计费贵
- 云厂商原生(CloudWatch/SLS):开箱即用,但跨云不统一
推荐方案:Loki + Promtail(云原生场景 + 成本敏感 + 按 label 查询为主)
架构:
应用 stdout → Promtail(DaemonSet)→ Loki(SimpleScalable)→ S3/OSS
↓
Grafana Explore(LogQL)关键设计点:
Loki 部署模式:SimpleScalable(target=1-3 个 ingester + querier + compactor),后端用对象存储(S3/OSS,不要用 filesystem——PVC 会满)。
schema 配置(v13 + tsdb + 对象存储):
yamlloki.schemaConfig.configs[0]: from: 2024-04-01 store: tsdb object_store: s3 schema: v13retention 配置:默认永久保留会撑爆,配
retention_period: 30d+ compactor 自动清理。Promtail 配置:
- 采集 K8s Pod stdout(自动发现 + 添加 metadata label)
- label 严格控制基数(app/namespace/env,不要 user_id/request_id)
- pipeline_stages 解析 JSON 日志提取字段
结构化日志要求:应用输出 JSON(非文本),必填 ts/level/msg/service/trace_id/request_id + 业务字段(user_id/latency_ms/status_code…),敏感信息脱敏——字段规范与落地细节同 1-概念·子类3·题目6,此处不赘。
跨云统一查询:US Loki → S3,CN Loki → OSS,Grafana 配两个数据源按 cluster label 切换。
注意事项:
- Loki PVC 满是高频事故:filesystem 后端 PVC 会满(详见 3-原理·Loki 写入路径题)。生产必须用对象存储 + retention 清理。
- 高 cardinality 是 Loki 灾难:把 user_id 当 label 会导致 stream 数爆炸,ingester 内存爆 + index 爆。Loki 严格限制 label 基数。
- 全文搜索慢是设计代价:Loki 按 label + 时间范围扫描,全文搜索
|= "error"要扫描所有 chunk。查询模式要"先按 label + 时间范围缩小,再过滤内容"。 - Loki 3.x ruler 规则不能直接放 S3:必须走 ruler API 上传(
POST /loki/api/v1/rules/{ns}),kiwigrid sidecar 的本地文件模式对 S3 backend 无效。 - 跨集群查询用联邦:每个集群一个 Loki,Grafana 配 federated query 跨集群查询。
子类 3:安全架构设计#
题目1:设计零信任安全体系#
设计需求: 从"10 个 P0 漏洞 + 4 条独立路径可拖全量用户 PII + 13 人 prod cluster-admin + 0 MFA + 生产库对 0.0.0.0/0 全开"的安全审计出发,设计零信任整改方案。
方案设计:
五支柱架构:
①零信任接入 → Headscale mesh 替代公网直连
②暴露收敛 → 公网面收敛到 VPC + Istio Gateway
③权限最小化 → K8s/IAM 从 admin 降到最小
④凭据治理 → 静态 AK/SK → EKS Pod Identity
⑤数据保护 → 误删/勒索可恢复(S3 Versioning + KMS)关键设计点:
零信任接入选型(Headscale 自建):
- 控制面落阿里云国内直连(SaaS 的 DERP 在境外跨境劣化)
- Go 单二进制复用现有 ECS 零增量
- WireGuard mesh + ACL file 模式入 git
- 网段规划铁律:只 advertise VPC CIDR,永不广播 ClusterIP(多集群 172.20/16 互撞)
暴露收敛"先摸真实调用方再删":
- 8 个 RDS SG
0.0.0.0/0→ 逐个 zcat 访问日志确认零业务流量才删 - 7 个管理面板关匿名/补 TLS(Prometheus/Alertmanager 删 HTTPRoute,Grafana 关匿名,Nexus 补 LE TLS)
- CN geo-block:CloudFront GeoRestriction(>99%)+ Route53 Geolocation(~90%,黑洞目标指 zone 外
blocked.invalid.RFC 6761) - S3 公开桶整改 + PAB 强化
- 8 个 RDS SG
权限最小化"观察→最小→并行验证→切换→回收":
- K8s 开发从 cluster-admin → 内置 view + 自定义 pod-exec(can-i 实测 get secrets/create deploy = no)
- p2s 透传 SA 从能 dump 68-84 secret 收到 0(删
resources:["*"]通配,显式列业务用到的 9 个资源) - IAM
*FullAccess→ 具体桶(Simulator 验证 16/16 业务 allowed、14/14 越权 deny)
凭据治理 → EKS Pod Identity:
- service principal
pods.eks.amazonaws.com不绑集群,跨集群一个 Role 复用 - 6 服务迁移(agent/backend/eval/oa-backend/openclaw/sandbox)
- 18 个 Nacos dataId 摘 AK
- SDK 默认凭据链自动拾取,零业务改动
- service principal
数据保护:
- US S3 40 桶 Versioning + Lifecycle→Glacier(误删/勒索可恢复)
- 监控脚本周观察旧版本累积 + Glacier transition + 月成本
- 加密密钥(ChaCha20Poly1305/idcipher AES)拟迁 KMS
注意事项:
- 整改不能搞挂业务:每一步都先摸真实流量/CloudTrail 再动手。公网收敛 7 个对象全部先逐个 zcat 访问日志确认零业务流量才删。
- 预算≈0:零信任不新购(Headscale 自建 $0 替代 $7,200-$80,000/年 ZTNA SaaS)、Pod Identity 复用 EKS addon。
- "一个缺陷往往是一类":发现某组件缺 toleration / node role 缺 policy / SA 通配过宽,必当集群级缺陷排查所有同款。
- Route53 黑洞必须指 zone 外:
blocked.invalid.(RFC 6761 保留 TLD),否则被 zone 内*.goalfyai.comwildcard 捕获反噬。 - 回收要等观察期:新旧凭据并行 14 天 CloudTrail 无 AccessDenied 再禁旧 AK,30 天后才真删。
- 离职只回收身份:ACL 移除 user(秒级生效),节点不删(避免 peer 同步 bug)。
题目2:设计密钥管理方案#
设计需求: 统一管理 100 个微服务的密钥(数据库密码、API Key、TLS 证书),支持自动轮换和审计。
方案设计:
选型对比:
- Vault:完整密钥管理系统,支持动态密钥,运维重
- 云 KMS:加密原语服务,简单但功能单一
- SOPS:文件加密工具,GitOps 友好
- External Secrets Operator:K8s 原生,与 Vault/云 SM 集成
推荐组合:Vault(动态密钥)+ 云 KMS(数据加密)+ ESO(K8s 集成)+ SOPS(GitOps 静态 Secret)
架构:
开发者 → 写代码(不涉及 Secret)
↓
GitOps 仓库 → 只存 ExternalSecret/SecretStore CRD(无敏感值)
↓
ArgoCD 同步 → K8s 创建 ExternalSecret 对象
↓
ESO Controller → 读 SecretStore 配置 → 调 Vault API
↓
Vault → 验证 K8s ServiceAccount → 检查 Policy → 返回 Secret
↓
ESO → 创建/更新 K8s Secret
↓
Pod → 通过 envFrom/volumeMount 使用 Secret关键设计点:
Vault HA 部署:
- 3 节点 Raft(不需要 Consul)
- Auto-unseal(AWS KMS/阿里云 KMS)—— Pod 重启后不需要手动 unseal
- dataStorage PVC 20Gi gp3
Kubernetes Auth Method:
bashvault auth enable kubernetes vault write auth/kubernetes/config \ kubernetes_host="https://kubernetes.default.svc" \ token_reviewer_jwt=@/var/run/secrets/.../token vault write auth/kubernetes/role/myapp \ bound_service_account_names=myapp-sa \ bound_service_account_namespaces=production \ policies=myapp-policy \ ttl=1hPolicy 最小权限:
hclpath "secret/data/myapp/prod/*" { capabilities = ["read"] } path "database/creds/app-role" { capabilities = ["read"] }动态密钥(Database Engine):
- Vault 用 vault-admin 凭据连接数据库
- 每次 ESO 刷新调
vault read database/creds/app-role→ Vault 生成全新临时账号 - TTL 1h,refreshInterval 45m(确保新账号在旧账号过期前生成)
- 旧账号 TTL 到期自动吊销(DROP ROLE)
ESO 配置:
yamlapiVersion: external-secrets.io/v1beta1 kind: SecretStore spec: provider: vault: server: "http://vault.vault.svc:8200" path: "secret" version: "v2" auth: kubernetes: mountPath: "Kubernetes" role: "myapp" serviceAccountRef: name: "myapp-sa"Secret 轮换触发 Pod 重启:装 Reloader(
reloader.stakater.com/auto: "true"annotation)监听 Secret 变化自动重启 Pod。
注意事项:
- KV v2 路径混淆:ESO 的
remoteRef.key填 CLI 风格(不带 /data/),API 路径才带secret/data/——CLI/Policy/API 三者差异同 3-原理·子类4·题目2,此处不赘。 - K8s 1.24+ ServiceAccount Token:不再自动创建 Secret,需要手动创建或用 TokenRequest API。
- Vault Pod 重启 sealed:生产必须配 Auto-unseal(AWS KMS/阿里云 KMS),否则半夜 Pod 被 K8s 驱逐要爬起来手动 unseal 三次。
- ESO 同步失败排查:常见原因——SecretStore 连不上 Vault(NetworkPolicy)、K8s Auth Role 绑定的 SA 不对、Vault Policy 没有 read 权限、KV v2 路径写错。
- 不要把所有密钥都塞 Vault:简单场景用云 KMS + SOPS 更轻量。Vault 适合需要动态密钥 + 完整审计的场景。
- Git 仓库里永远不出现敏感值:base64 不是加密,
echo bXlwYXNzd29yZA== | base64 -d就能还原。GitOps 仓库只存 ExternalSecret/SecretStore CRD。
题目3:设计镜像供应链安全方案#
设计需求: 防止镜像被篡改、依赖投毒、CI 被攻陷后恶意镜像进入生产。
方案设计:
全链路安全流水线:
代码提交 → SAST 扫描 → 依赖扫描(SCA) → 构建镜像 → 镜像扫描
→ 镜像签名(Cosign) + SBOM → 部署时验证签名 → 运行时安全关键设计点:
代码阶段:
- pre-commit 钩子:gitleaks(硬编码密钥)+ semgrep(漏洞模式)+ detect-private-key
- PR 阶段:SonarQube 质量门禁 + Semgrep 自定义规则 + Snyk/Trivy 依赖扫描
构建阶段:
- Runner 隔离(不同项目不同 Runner)
- 构建不出网(只允许白名单域名)
- 不在 Runner 存长期 Secret(通过 Vault 动态注入)
- 多阶段构建 + distroless 基础镜像减少攻击面
镜像阶段:
- Trivy 扫描(HIGH/CRITICAL 阻断发布,
--ignore-unfixed过滤无修复版本的) - Cosign 签名(Keyless 模式,短期证书绑定 CI identity)
- SBOM 生成(Syft)+ 附加到镜像(
cosign attach sbom)
- Trivy 扫描(HIGH/CRITICAL 阻断发布,
部署阶段:
- Kyverno ClusterPolicy 强制验证签名(production/staging 命名空间的 Pod 必须有 Cosign 签名)
- 未签名镜像拒绝创建
- 镜像 tag 用
{commit}-{timestamp}不可变,避免 tag 覆盖
运行时:
- Falco/Tetragon 检测异常进程(如容器内 curl 下载文件)
- kube-bench 定期跑 CIS Benchmark
- 持续合规扫描(防止配置漂移)
注意事项:
- 渐进引入不要一刀切:三周渐进(第一周只跑不阻断收集基线 → 第二周新增代码阻断 → 第三周存量修复),详见 1-概念·质量门禁题。
- 维护白名单:每个工具有误报,建立白名单流程(安全团队 Review + 记录理由 + 到期时间)。
- 门禁要快:SAST 扫描超过 5 分钟开发就会跳过,用增量扫描(只扫改动文件)。
- Cosign Keyless 依赖 Rekor:网络不通时用传统密钥签名。自部署 Fulcio/Rekor 可避免依赖公共服务。
- SBOM 的价值在爆发时:Log4Shell 爆发时,有 SBOM 的团队 5 分钟查影响面,没 SBOM 的要几天。
- 签名验证用 Audit 模式先观察:Kyverno policy 先
validationFailureAction: Audit跑一段时间,确认无误报再切Enforce。
题目4:设计 RBAC 最小权限体系#
设计需求: 13 人 prod cluster-admin 需要降权到最小权限,同时不搞挂业务。
方案设计:
K8s RBAC 降权方案:
开发人员权限:
├── 内置 view ClusterRole(通用读:pods/log/deploy/svc/events/ingress)
├── 自定义 pod-exec ClusterRole(pods/exec create+get,支持排障)
└── 绑定到 IAM ARN(US)或 UID 字符串(CN ACK)
权限矩阵(can-i 实测):
✅ list pods/log、exec、list deploy/svc/events
❌ get secrets、list nodes、create deployments关键设计点:
先试纯 pods-only readonly 不够用:开发反馈
describe deploy/get svc/get events用不了影响排障。改为「内置 view 覆盖通用读 + 自定义 pod-exec 补 exec」。p2s 透传 SA ClusterRole 收紧:
- 删
resources:["*"]通配(= 能 dump 集群所有 secret) - 显式列 9 个业务实际用到的资源(appdeploys/pods/log/svc/events/jobs/httproute)
- 修前:us-p2s 84 secret 可读 / cn-prod 68 可读
- 修后:业务流程全通,secret/cm/deploy/node 全 403
- 删
IAM 服务账号收紧:
*FullAccess→ 具体桶- 用 CloudTrail Access Advisor 查实际使用范围(90 天内实际只用 2 桶)
- SimulatePrincipalPolicy 验证最小权限(16/16 业务 allowed、14/14 越权 deny)
- 新旧 policy 并行 7 天 CloudTrail 无 AccessDenied 再卸旧
Pod Identity 替代静态 AK/SK:
- service principal
pods.eks.amazonaws.com不绑集群 - 一个 Role 可绑任意集群 Association(跨集群复用关键)
- SDK 默认凭据链自动拾取(token 经
169.254.170.23endpoint 注入) - 验证:Pod 内
aws sts get-caller-identity应显示 AssumedRole
- service principal
注意事项:
resources:["*"]通配是隐形 secret 泄露:一条core/*通配 = 能 dump 全集群 secret(含 HARBOR_ADMIN_PASS/DB/OIDC)→ 显式列业务用到的资源。- ACK 不允许同集群同时 grant system + custom:CN view 这条只能直 apply CRB(K8s 层),ACK 控制台只显示 pod-exec(custom)。
- 观察实际使用 → 起草最小权限 → 并行验证 → 切换 → 回收:每个收权限动作都先用 CloudTrail/Access Advisor 验证真实使用范围,新旧并行观察期 7-14 天再切,旧的留 14-30 天再删。
- 纯收权限不搞挂业务的根本:先摸真实调用方再动手,绝不拍脑袋收权限。
- can-i 实测验证:
kubectl auth can-i get secrets -n production应返回 no;kubectl auth can-i list pods -n production应返回 yes。
子类 4:IaC 架构设计#
题目1:设计 Terraform 多环境多账号管理#
设计需求: 3 个 AWS 账号(prod/staging/dev),每账号 2-3 个 region,需要用 Terraform 统一管理基础设施。
方案设计:
架构:
terraform/
├── modules/ # 可复用模块
│ ├── vpc/
│ ├── eks/
│ └── rds/
├── environments/ # 每环境一个 state
│ ├── prod/
│ │ ├── main.tf
│ │ ├── backend.tf # S3 + DynamoDB lock
│ │ └── terraform.tfvars
│ ├── staging/
│ └── dev/
└── global/ # 跨环境共享资源(IAM/Route53)关键设计点:
State 分环境隔离:每环境一个 state 文件(
prod/vpc.tfstate/staging/vpc.tfstate),不要混在一个 state。避免一个环境 apply 影响其他环境。Backend 配置:
hclbackend "s3" { bucket = "my-tfstate-prod" key = "prod/vpc.tfstate" region = "us-west-2" dynamodb_table = "tf-locks-prod" encrypt = true }- S3 + DynamoDB lock(必须加锁防并发 apply)
- encrypt = true(state 里可能有敏感数据)
- S3 versioning 开启(误删可恢复)
Module 复用:把 VPC/EKS/RDS 封装成 module,环境间通过 tfvars 差异化配置。
跨账号访问:用
assume_role:hclprovider "aws" { region = "us-west-2" assume_role { role_arn = "arn:aws:iam::<PROD_ACCOUNT>:role/TerraformCrossAccount" } }Terragrunt 管理 DRY(可选):多个环境的 backend/provider 配置重复,Terragrunt 可以继承减少重复。
注意事项:
- State 文件不入 Git:可能含密码且每次 apply 都变。远端存储 + 加锁 + 加密 + 备份。
- 不要手动改 state:用
terraform state mv/rm命令,不要直接编辑 JSON。 - state 加锁必须配:DynamoDB lock 表必须存在,否则并发 apply 会 state 损坏。
- 跨账号 role trust policy:source 账号的 role 必须在 target 账号的 trust policy 里。
- OpenTofu 替代 Terraform:严格开源要求或想要 state encryption 等新特性时,改 CLI 名字即可迁移。
- 大规模 state 要拆分:3000+ 资源的 state plan 需要 2 分钟,拆成多个小 state(如 VPC/EKS/RDS 各一个)。
题目2:设计 Ansible 配置管理规范#
设计需求: 50 台 K8s worker 节点,需要统一配置(内核参数、安装监控 agent、分发证书)。
方案设计:
目录结构:
ansible/
├── inventory/
│ ├── hosts.ini # 主机清单
│ └── group_vars/
│ ├── all.yml # 全局变量
│ └── prod.yml # prod 环境变量
├── roles/ # 可复用 role
│ ├── common/ # 基础配置(内核参数/时间同步)
│ ├── node-exporter/ # 监控 agent
│ └── certificate/ # 证书分发
├── playbooks/ # playbook
│ ├── site.yml # 总入口
│ └── rolling-update.yml # 滚动更新
└── ansible.cfg # 配置关键设计点:
Role 模块化:每个功能封装成 role(
common/node-exporter/certificate),role 间通过dependencies声明依赖。inventory 分组:按环境(prod/staging)+ 角色(worker/master)分组,playbook 按 group 执行。
幂等性保证:
- 优先用 Ansible module(file/user/apt/service)而非 shell/command
- 必须用 shell 时加
creates=(文件存在则跳过) - 跑
--checkdry run 验证幂等
滚动更新:用
serial: 1(一次一台)避免同时影响所有节点:yaml- hosts: worker serial: 1 tasks: - name: drain node command: kubectl drain {{ inventory_hostname }} - name: upgrade kernel apt: name=linux-image-generic state=latest - name: uncordon node command: kubectl uncordon {{ inventory_hostname }}变量分层:
group_vars/all.yml(全局)→group_vars/prod.yml(环境)→host_vars/<hostname>.yml(单机)。
注意事项:
- Ansible 适合配置管理不适合基础设施编排:创建 VPC/RDS 用 Terraform,节点内配置用 Ansible。
- SSH 连接要稳定:网络不稳定时
ansible_ssh_retries: 3+ansible_ssh_timeout: 30。 - 不要在 Ansible 里存敏感数据:用 Ansible Vault 加密 vars 文件,或从 Vault/SSM 动态获取。
- CI 里重复跑 playbook 验证幂等:幂等性是 Ansible 的核心,第二次跑应该 0 changed。
题目3:设计混合云 IaC 方案#
设计需求: AWS + 阿里云双云,需要统一 IaC 管理双云资源。
方案设计:
架构:
terraform/
├── modules/
│ ├── aws-vpc/
│ ├── alicloud-vpc/
│ ├── aws-eks/
│ └── alicloud-ack/
├── environments/
│ ├── prod-aws/
│ ├── prod-alicloud/
│ └── prod-cross-cloud/ # 跨云资源(DNS/CDN)关键设计点:
Provider 分云:每云一个 provider,不要混在一个 provider 配置里:
hclprovider "aws" { region = "us-west-2" } provider "alicloud" { region = "cn-beijing" }Module 分云但接口统一:
aws-vpc和alicloud-vpc的 input/output 变量尽量一致(如都输出 vpc_id),方便上层调用。跨云资源单独管理:DNS(Route53/阿里云 DNS)、CDN(CloudFront/阿里云 CDN)等跨云资源放在
prod-cross-cloud目录。State 分云:每云一个 state,避免一个 state 太大。跨云资源单独一个 state。
凭据管理:AWS 用
aws configure/ IRSA,阿里云用ALICLOUD_ACCESS_KEY/ RAM Role。
注意事项:
- 阿里云 provider 文档可能滞后:新功能可能 provider 还没支持,要查 GitHub issues。
- 跨云网络打通:专线/VPN 配置复杂,建议用云厂商托管服务(如 AWS Direct Connect + 阿里云高速通道)。
- 资源命名规范:跨云资源命名要统一(如
{env}-{service}-{cloud}),避免混淆。 - 成本治理:双云成本要统一看板,用 CloudZero/Vantage 或自建脚本聚合 AWS Cost Explorer + 阿里云费用中心。
子类 5:平台工程设计#
题目1:设计内部开发者平台(IDP)#
设计需求: 100 人技术团队,10 个微服务,希望开发者自助创建新服务、部署、看监控,不需要平台团队介入。
方案设计:
IDP 架构:
开发者 → Backstage(IDP 前端)
├── 软件目录(服务清单/owner/依赖)
├── 软件模板(scaffolder:新服务从模板生成)
├── TechDocs(文档统一入口)
└── 插件集成(ArgoCD/Grafana/PagerDuty/Sentry)
↓
平台 API(封装底层工具)
├── 创建 GitOps overlay → ArgoCD 自动 sync
├── 创建 ECR 仓库
├── 创建流水线(云效/GitHub Actions)
└── 注册到服务发现关键设计点:
软件目录(Software Catalog):每个服务在 Backstage 注册一个 Component,包含 owner、依赖、API、文档。
catalog-info.yaml入服务仓库。软件模板(Scaffolder):新服务从模板生成——填表单(服务名/语言/owner)→ Backstage 自动创建 Git 仓库 + GitOps overlay + ECR 仓 + 流水线 + 监控。整个流程 5 分钟,不需要平台团队介入。
黄金路径文档化:在 Backstage TechDocs 里写清楚"新建一个 Go HTTP 服务的黄金路径"——按模板做 CI/CD/监控/告警/日志/密钥全自动到位。
插件集成:Backstage 的 ArgoCD 插件看部署状态、Grafana 插件看监控、PagerDuty 插件看告警、Sentry 插件看错误。开发者不需要跳多个工具。
Scorecards:给每个服务打分——是否有 README、是否有 owner、是否接监控、是否跑 SAST。驱动团队主动补齐。
注意事项:
- IDP 不是工具堆砌:核心是"黄金路径"——开发者按推荐路径做,一切自动化。不是把所有工具都塞进 Backstage。
- 平台团队 ownership:IDP 本身需要平台团队维护(Backstage 升级、插件维护、模板更新)。1-2 人平台团队维护 100 人 IDP 是合理的。
- 不要强制所有服务都走 IDP:20% 特殊服务走自定义路径并标记"长期例外"(同 1-概念·子类1·题目5)。
- Scorecards 要渐进:先有"是否有 README"这种基础项,再加"是否接监控"等高级项,不要一开始就 100 分要求。
- Backstage 学习曲线陡:需要 React 开发能力定制插件,小团队可考虑 Port/Humanitec 等 SaaS 替代。
题目2:设计开发者黄金路径#
设计需求: 为"新建一个 Go HTTP 服务"设计一条黄金路径,让开发者 30 分钟内完成从创建到部署到 QA 的全流程。
方案设计:
黄金路径步骤:
创建服务(5 分钟):
- 开发者在 Backstage 点"Create Component"
- 选"Go HTTP Service"模板
- 填表单:服务名、owner、是否需要数据库
- Backstage 自动创建:Git 仓库 + Dockerfile + base Kustomize + overlay 模板 + ECR 仓 + 流水线
写业务代码(按需):
- clone 仓库
- 模板已包含:health check endpoint、结构化日志、OTel SDK、Prometheus /metrics、Graceful shutdown
- 开发者只关心业务逻辑
push 代码(1 分钟):
- push 到 feature 分支 → PR
- CI 自动跑:单测 + SAST + 依赖扫描 + 镜像构建 + 镜像扫描 + Cosign 签名
PR Review + 合并(按需):
- main 分支保护(禁直推,强制 MR)
- Review 通过后 squash merge 到 main
自动部署 QA(5 分钟):
- push main 触发部署流水线
- deploy.py 改 GitOps overlay 的 newTag → git push
- ArgoCD ApplicationSet 检测到变化 → 自动 sync
- Pod Ready → 钉钉通知"部署成功"
验证(按需):
- 开发者访问 QA 域名验证
- Grafana 看监控、Loki 看日志、Tempo 看 Trace
模板包含的"开箱即用"能力:
- Dockerfile(多阶段构建 + distroless)
- base Kustomize(deployment + service + pdb + configmap)
- HPA(CPU 70%)
- ServiceMonitor(Prometheus 抓取)
- PrometheusRule(基础告警:Pod 重启、5xx 率)
- ExternalSecret(从 Vault 拉密钥)
- NetworkPolicy(默认 deny + 放行必要流量)
- OTel SDK(trace + metrics)
- 结构化日志(zap/slog)
- ReadinessProbe + LivenessProbe
- Resource requests/limits
- SecurityContext(runAsNonRoot + readOnlyRootFilesystem)
注意事项:
- 黄金路径不是强制:80% 走模板、20% 特殊服务走自定义路径并标记"长期例外"(同 1-概念·子类1·题目5)。
- 模板要持续维护:技术栈升级(如 Go 1.22 → 1.23)时更新模板,新建服务自动用新版本,老服务不强制迁移。
- 边际成本要低:第 11 个服务接入和第 1 个一样快(30 分钟),这是黄金路径成功的标志。
- 不要过度工程:模板包含基础能力即可,不要塞入业务特定的东西(如特定数据库 SDK)。
- Scorecards 驱动补齐:老服务没走黄金路径的,用 Scorecards 显示"缺 README/缺监控/缺告警",驱动团队主动补齐。
题目3:设计多租户 K8s 平台#
设计需求: SaaS 平台,多个租户共享 K8s 集群,需要隔离但成本可控。
方案设计:
隔离方案选型:
- 方案 A(每租户独立集群):最强隔离,但成本高(每集群固定开销)
- 方案 B(共享集群 + namespace 隔离):成本低,但隔离弱
- 方案 C(共享集群 + namespace + 资源配额 + NetworkPolicy):推荐,成本和隔离平衡
方案 C 架构:
K8s 集群
├── tenant-a namespace
│ ├── ResourceQuota(CPU/内存/PVC 限制)
│ ├── LimitRange(默认/最大资源)
│ ├── NetworkPolicy(default-deny + 放行必要流量)
│ ├── RBAC(tenant-a 团队只管自己 namespace)
│ └── 业务 Pod
├── tenant-b namespace(同上)
└── tenant-c namespace(同上)关键设计点:
namespace 即租户边界:每租户一个 namespace,RBAC 限制租户只能操作自己 namespace。
ResourceQuota 资源配额:
yamlspec: hard: requests.cpu: "32" requests.memory: "64Gi" persistentvolumeclaims: "20" services.loadbalancers: "2" pods: "200"NetworkPolicy 微分段:
- default-deny-all(默认拒绝所有入站出站)
- allow-internal(namespace 内互通)
- allow-egress-dns(放行 DNS)
- allow-egress-https(放行外部 API)
RBAC 最小权限:
- 租户管理员:自己 namespace 的 admin(不含 secrets)
- 租户开发者:自己 namespace 的 view + pod-exec
数据隔离(参考子环境 ID 撞车事故):
- 每租户独立数据库 schema 或独立 Aurora cluster
- 业务表 AUTO_INCREMENT 起点错开(如 tenant-a 从 1,tenant-b 从 1000 万)
- RabbitMQ/Kafka 独立 broker 或严格 topic 前缀
- Redis 独立实例或 key 前缀
Pod Security Admission:所有 namespace 配
restricted级别。
注意事项:
- 不要只靠 namespace 隔离:namespace 是软隔离,内核层仍共享。高安全要求用 gVisor 或独立集群。
- ResourceQuota 要合理:太严导致 Pod Pending,太松导致资源争抢。根据租户付费等级分配。
- NetworkPolicy 默认 deny:先部署 default-deny-all,再逐条放行必要流量。不要先 allow 再 deny。
- 数据隔离是最难的:参考"子环境 ID 撞车污染 10 万条数据"事故——4 件套(id 重叠 + broker 共用 + 过滤缺失 + 配置漏改)缺一不会爆雷,但省事姿势会让 4 件套同时为真。
- 多租户 SaaS 的租户隔离不在本范围:本方案是环境维度(dev/qa/prod)的隔离,不是租户(tenant_id)维度的隔离,后者通常需要在应用层解决。
题目4:设计成本治理 FinOps 体系#
设计需求: 月费从失控峰值 $36,829 治理到日均 ~$640,建立持续成本治理体系。
方案设计:
FinOps 心法(贯穿全程的纪律):
摸真实用量(CloudTrail/Cost Explorer/CloudWatch)
→ 评 ROI 与风险
→ 止血优先
→ 观察期/灰度
→ 根治/回收
↑ 省钱不破可用性(稳定性红线)关键设计点:
账单拆到分钟级:按 service × USAGE_TYPE × log group × 资源定位。成本突增先拆 USAGE_TYPE 再拆 log group。
bash# 按服务拆 aws ce get-cost-and-usage --group-by Type=DIMENSION,Key=SERVICE # 按 USAGE_TYPE 拆 aws ce get-cost-and-usage --group-by Type=DIMENSION,Key=USAGE_TYPE成本事故秒级止血(案例:Aurora 审计日志税一天烧 $170):
- 三层拆解定位:service → USAGE_TYPE → log group → QPS → commit
- 止血方案选择:① 关 CW export(本地可回查仅 47min);② 收窄事件(选用,保留 CONNECT/DDL/DCL);③ 全关 audit
- 止血 ≠ 根治:触发因素是 agent 轮询 bug(交开发根治),结构性缺陷是"成本侧没有突增告警"(要补 CloudWatch Logs Ingestion 单日 >50GB 告警)
结构性浪费识别:
- "缩不动节点"= requests 虚高:实际 CPU 2-6% 但 requests 占 90% → 降 requests 模板(100m→25m)
- "越扩越多"= 内存 HPA 误配:常驻内存型服务禁用 memory-Utilization HPA——加副本不降单 pod 内存(虚扩到 13 副本的完整案例见 4-场景·子类5·题目2)
- Serverless vs Provisioned:低吞吐稳定负载用 Provisioned 便宜(MSK Serverless $540 → t3.small×2 $75)
僵尸回收"五件套"确认零业务:
- NLB 流量(无请求)
- ConnectionCount(无连接)
- 应用日志(无业务调用)
- 节点 CPU(无活动)
- CloudTrail 真人活动(无 API 调用) 全部为零才删,删前做 final snapshot。
ROI 否决权(FinOps 的克制):
- QA/PRE 定时缩容能省 $300-500/月,但引入 Lambda + EventBridge + 钉钉 Bot 新基础设施(新故障面)+ 夜间 QA 不可用 → 主动否决
- MSK Serverless → Provisioned 省 $1,470/月,无故障面纯收益 → 做
- 区别在"这笔省钱的代价是什么"
稳定性红线(省钱不破可用性的护栏):
- P0 服务(agent/backend/dispatch/ai-gateway)min≥2 仅 On-Demand
- Prod DB 不合并、PRE 写保护
- Spot 仅限 P2 服务且必配 PDB + 拓扑约束
- 合并集群必加 NetworkPolicy + ResourceQuota
注意事项:
- 成本治理是有腐化速度的活物:每个新加的资源、每次故障复盘、每次临时 silence,都在往里堆熵。半年没治理就是失控。
- 止血 ≠ 根治 ≠ 防回退:事故先秒级止血(恢复服务),再根治(改代码/配置),再防回退(同类全排查 + 告警)。三层分清。
- 双层归因:故障不只问"为什么烧钱"(轮询 bug),更问"为什么 3 天才发现"(没有成本突增告警)——后者才是真正该修的。
- EOL 成本炸弹:K8s 1.33 在 2026-07-29 截止 → 提前改 EXTENDED 买窗口,否则被强制升级。
- Savings Plans 采购:稳定 1 月后再采购,不要在治理初期就 lock-in。
- 不为了"省"而省:能用 SaaS 省一个全职工程师工作量的(如 CI 用云效/GitHub Actions 而不自建 Jenkins),不要为了省 SaaS 费用而自建。