路线图

面试 · 方案设计型

星辉 2026-07-02 阅读 26 min 5,392 字 路线图
面试 · 方案设计型 封面

答题提示:系统设计题不要直接给方案。先问清楚约束条件(规模、SLA、成本预算、团队规模),再展开设计。每个方案都要能讲清楚“为什么这么选”和“代价是什么”。

答题结构:需求/约束 → 架构 → 关键设计点 → 取舍 → 验证 → 治理。题干(设计需求)与参考答案(其后各节)分开阅读。

API 版本速查(截至 2026,K8s 1.3x):HPA=autoscaling/v2、NetworkPolicy/Ingress=networking.k8s.io/v1(Ingress 已冻结,新场景用 Gateway API gateway.networking.k8s.io/v1,v1 已 GA)、Karpenter=karpenter.sh/v1、EncryptionConfiguration=apiserver.config.k8s.io/v1、Lease=coordination.k8s.io/v1。已废弃勿用:extensions/v1beta1autoscaling/v2beta1/2networking.k8s.io/v1beta1 Ingress、PodSecurityPolicy。


子类 1:集群规划与高可用设计#

题目 1:etcd 集群规划 — 3 节点 vs 5 节点#

设计需求: 需要为一个生产 K8s 集群规划 etcd 集群,要求保证控制面数据的强一致性和高可用。

方案对比:

维度3 节点5 节点
容错能力容忍 1 节点故障容忍 2 节点故障
Quorum需要 2 票(> 3/2)需要 3 票(> 5/2)
写入延迟更低(只需等 2 节点确认)略高(需等 3 节点确认)
资源成本3 × (4C8G + SSD)5 × (4C8G + SSD)
适用场景一般生产集群大规模集群 / 金融级 / 跨区域部署

关键设计点:

  1. 奇数节点是硬要求:Raft 协议需要奇数节点形成 quorum,偶数节点(如 4 节点)容错能力 = 3 节点(都只能容忍 1 节点故障),但多了资源开销
  2. 磁盘是关键瓶颈:必须用 SSD(NVMe 最佳),不要与其他高 IO 服务共享磁盘。etcd 的 WAL 写入是同步的,磁盘延迟直接决定写入性能
  3. 独立部署 vs 与控制面混合:生产环境建议 etcd 独立部署(或使用托管 etcd),避免与控制面组件争抢资源
  4. 跨可用区部署:3 节点部署在 3 个 AZ,单个 AZ 故障不影响 etcd 可用性
  5. 定期备份etcdctl snapshot save + 定期 defrag(碎片整理)

架构拓扑(文字描述):

text
AZ-a: etcd-0 (4C8G, 100GB SSD NVMe)
AZ-b: etcd-1 (4C8G, 100GB SSD NVMe)
AZ-c: etcd-2 (4C8G, 100GB SSD NVMe)
├── Raft Leader Election → 同一时刻仅一个 Leader 接受写入
├── 默认线性一致性读:通过 ReadIndex 与 Leader 确认最新 commit index,可由任意成员响应(并非全部打到 Leader);追求极致读吞吐可显式用 serializable 读走本地副本(可能读到旧值)
└── 3 节点部署 → 容忍 1 个 AZ 故障

注意事项:

  • etcd 存储配额 --quota-backend-bytes 默认 2GB,最大不建议超过 8GB(超过后性能下降明显;写满触发 NOSPACE 告警后集群转只读,须 defrag + 解除 alarm 恢复)
  • 配置 --auto-compaction-mode=periodic --auto-compaction-retention=1h 自动清理历史版本
  • 监控指标:etcd_disk_wal_fsync_duration_seconds_bucket(P99 < 10ms)、etcd_server_has_leader(必须 = 1)

题目 2:Control Plane 高可用方案#

设计需求: 设计一个生产级 K8s 控制面的高可用架构,确保 API Server 在任何单点故障下仍可用。

方案设计:

三层高可用架构:

text
                    ┌──────────────────────┐
                    │   External LB        │  (AWS NLB / 阿里云 SLB / HAProxy)
                    │   VIP: 10.0.0.100    │
                    └──────┬───────┬───────┘
                           │       │
              ┌────────────┘       └────────────┐
              ▼                                  ▼
    ┌──────────────────┐              ┌──────────────────┐
    │ API Server #1    │              │ API Server #2    │  (无状态,生产建议 ≥3 个跨 AZ;图中简化为 2)
    │ AZ-a             │              │ AZ-b             │
    └────────┬─────────┘              └────────┬─────────┘
             │                                 │
             └───────────┬─────────────────────┘
              ┌──────────────────┐
              │   etcd Cluster   │  (3 或 5 节点,跨 AZ)
              │   Raft Quorum    │
              └──────────────────┘
    ┌────────────────────┼────────────────────┐
    ▼                                             ▼
┌──────────────┐ Leader Election ──────────┐
│ Scheduler    │  ───────────── │ Scheduler (standby) │
│ Controller   │                │ Controller (standby)│
│ Manager      │                │ Manager             │
└──────────────┘                └─────────────────────┘

关键设计点:

  1. API Server 无状态:3 个实例部署在不同 AZ,前面挂 L4 LB(TCP 6443)。API Server 本身不存状态,可以任意水平扩展
  2. Scheduler/ControllerManager Leader Election:多实例同时只有一个 Leader 工作(通过 kube-apiserver 中的 Lease 对象 coordination.k8s.io/v1 抢锁实现,最终持久化到 etcd,而非直接读写 etcd),Leader 挂了自动选举新 Leader
  3. LB 选择:AWS 用 NLB(Network Load Balancer),阿里云用 SLB,自建用 HAProxy + Keepalived
  4. 证书管理:API Server 证书必须包含 LB 的 VIP/域名,否则客户端通过 LB 访问时 TLS 验证失败

注意事项:

  • etcd 与控制面组件之间的网络延迟必须 < 10ms
  • API Server 过载保护优先用 APF(API Priority and Fairness,flowcontrol.apiserver.k8s.io/v1,1.29 GA) 做请求分级限流;--max-requests-inflight(默认 400 非 mutating)/--max-mutating-requests-inflight(默认 200)是 APF 关闭时的兜底,需按集群规模调整
  • 控制面节点不要调度业务 Pod(加 taint 隔离)

题目 3:多 Master 部署拓扑设计#

设计需求: 某公司需要在 3 个可用区各部署一个 Master 节点,设计多 Master 的部署拓扑。

方案设计:

部署拓扑:

text
Region: cn-hangzhou
├── AZ-a
│   ├── Master-1 (API Server + Scheduler + ControllerManager)
│   ├── etcd-1
│   └── Worker Nodes (3-5 台)
├── AZ-b
│   ├── Master-2 (API Server + Scheduler + ControllerManager)
│   ├── etcd-2
│   └── Worker Nodes (3-5 台)
└── AZ-c
    ├── Master-3 (API Server + Scheduler + ControllerManager)
    ├── etcd-3
    └── Worker Nodes (3-5 台)

跨 AZ 通信:
├── etcd 节点间:内网 HTTPS 2380(peer)/ 2379(client)
├── API Server → etcd:内网 HTTPS 2379
├── Worker → API Server:通过 LB(跨 AZ 负载均衡)
└── Worker 间 Pod 通信:CNI 跨 AZ 路由(VPC 原生或 Overlay)

关键设计点:

  1. kubeadm 部署:第一个 Master 执行 kubeadm init,后续 Master 通过 kubeadm join --control-plane 加入
  2. etcd 部署模式
    • Stacked etcd(与控制面同节点):简单,适合中小集群
    • External etcd(独立节点):性能更好,etcd 不受控制面影响
  3. 跨 AZ 延迟要求:etcd 节点间延迟 < 10ms,否则 Raft 写入性能骤降
  4. Worker 节点分布:每个 AZ 至少 3 台 Worker,保证 Pod 可以跨 AZ 分散部署

注意事项:

  • 跨 AZ 的 etcd 延迟是关键指标,部署前必须实测
  • 使用 Pod 反亲和性让 CoreDNS 副本分布在不同 AZ
  • 跨 AZ 流量可能产生费用(取决于云厂商网络架构)

题目 4:集群规模估算#

设计需求: 预计运行 100 个微服务(每个 2-3 个副本),总计约 300 个 Pod。需要估算集群节点规模、性能瓶颈。

估算方法:

1. 节点规模估算:

计算维度估算
总 Pod 数300(业务)+ 50(系统组件)+ 50(buffer)= 400
每节点 Pod 上限建议 < 110(默认 kubelet max-pods)
节点核心数假设 c6a.2xlarge(8C32G),每节点跑 30-40 Pod
节点总数400 / 35 ≈ 12 台 → 加 buffer 15 台

2. Service 数量估算:

  • 100 个 Service(每个微服务一个)+ 系统 Service ≈ 120 个
  • 每个 Service 对应 iptables 或 ipvs 规则
  • iptables 模式下规则数 = Service × Endpoints → 可能上千条
  • 超过 1000 个 Service 建议切换到 ipvs 模式(O(1) 查找)

3. 控制面性能瓶颈:

组件瓶颈点阈值参考
etcd存储大小< 8GB
etcd磁盘 IOPSSSD NVMe,P99 fsync < 10ms
API Server并发请求默认 max-requests-inflight=400(mutating=200)
kube-scheduler调度吞吐约 100 Pods/s(默认配置)
CoreDNS内存大集群需调至 512Mi limit

注意事项:

  • 单集群建议上限:5000 节点 / 150000 Pod / 10000 Service(以上需分割为多集群)
  • 实际瓶颈通常是 etcd(存储和 IOPS)→ 大集群考虑 etcd 独立部署或托管 etcd
  • Service/节点规模大时用 IPVS 或 kube-proxy nftables 后端(1.31 beta、2025 年 GA) 替代 iptables,避免规则线性膨胀;Cilium/Calico 的 eBPF 数据面可直接绕过 kube-proxy

题目 5:kubeadm vs Managed K8s 选型#

设计需求: 团队需要决定自建 kubeadm 集群还是使用云厂商托管 K8s(如 ACK/EKS/GKE)。

方案对比:

维度kubeadm 自建Managed K8s(ACK/EKS)
控制面管理团队负责高可用、升级、备份云厂商负责(SLA 99.95%)
etcd 运维自行管理(备份/恢复/扩缩)托管 etcd(无需运维)
版本升级手动执行,需停机窗口控制台/CLI 触发,滚动升级
网络插件自由选择 Calico/Cilium/Flannel预集成(ACK=Terway, EKS=VPC CNI)
成本控制面节点成本 + 运维人力按集群收费(ACK Pro ~¥3k/月)
自定义能力完全控制所有组件配置有限(不能改 API Server 参数)
适用场景混合云/边缘/合规约束标准云原生场景

选择逻辑:

  • 选 Managed K8s(推荐大多数场景):
    • 团队规模 < 10 人,无专职 SRE
    • 控制面运维投入产出比低
    • 需要快速扩容多集群
  • 选 kubeadm
    • 混合云/多数据中心(统一部署工具链)
    • 需要自定义 API Server 参数(如 OIDC、Admission Webhook)
    • 合规要求控制面不能出企业网络
    • 边缘计算场景(轻量级 K3s/k0s)

注意事项:

  • Managed K8s 的控制面升级窗口不可控(云厂商决定),提前了解升级策略
  • kubeadm 集群务必配置 etcd 自动备份(CronJob)
  • 混合场景:核心业务用 Managed K8s,边缘节点用 kubeadm/K3s

子类 2:多租户与命名空间设计#

题目 1:命名空间划分策略设计#

设计需求: 一个中型公司(50+ 开发人员,5 个业务团队)需要设计 K8s 命名空间划分策略,支持多环境(dev/qa/staging/prod)。

方案设计:

命名空间命名规范:

text
<team>-<env> 模式

team-alpha-dev        team-beta-dev
team-alpha-qa         team-beta-qa
team-alpha-staging    team-beta-staging
team-alpha-prod       team-beta-prod

# 共享基础设施
kube-system           monitoring
ingress-nginx         cert-manager
argocd                vault

隔离层次设计:

text
第一层:集群级隔离
├── Prod 集群(独立集群,物理隔离)
└── Non-Prod 集群
    ├── Dev/QA/Staging 共用集群
    └── 按 namespace 逻辑隔离

第二层:命名空间级隔离
├── 每个团队 × 每个环境一个 namespace
├── ResourceQuota 限制 CPU/Memory/Storage
├── LimitRange 设置默认 request/limit
└── NetworkPolicy 限制跨 namespace 流量

第三层:RBAC 权限隔离
├── 每个 namespace 一个 ServiceAccount
├── RoleBinding 限制团队只能操作自己的 namespace
└── ClusterRole 只读(如查看节点状态)

注意事项:

  • 不要用 namespace 做安全边界(namespace 是管理边界,NetworkPolicy + RBAC 才是安全边界)
  • Prod 和 Non-Prod 必须物理隔离(不同集群或至少不同节点池)
  • 避免 namespace 爆炸(> 50 个 namespace 管理困难)

题目 2:ResourceQuota 配额体系设计#

设计需求: 为多团队共享集群设计 ResourceQuota 策略,防止某个团队耗尽集群资源。

方案设计:

三层配额架构:

yaml
# 第一层:集群总配额(防止超卖)
# 集群所有 namespace requests 之和 < 节点总 capacity

# 第二层:Namespace 配额(按团队分配)
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha-prod
spec:
  hard:
    requests.cpu: "20"        # 最多申请 20 核
    requests.memory: "40Gi"   # 最多申请 40GB
    limits.cpu: "40"          # 使用上限 40 核
    limits.memory: "80Gi"     # 使用上限 80GB
    persistentvolumeclaims: "10"  # 最多 10 个 PVC
    requests.storage: "500Gi"
    services: "20"
    configmaps: "50"
    secrets: "50"
    pods: "100"
    services.nodeports: "0"   # 禁止使用 NodePort

# 第三层:单个 Pod 限制(LimitRange)
apiVersion: v1
kind: LimitRange
metadata:
  name: team-alpha-limits
  namespace: team-alpha-prod
spec:
  limits:
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"     # 未指定 limit 的容器默认值
    defaultRequest:
      cpu: "200m"
      memory: "256Mi"     # 未指定 request 的容器默认值
    max:
      cpu: "4"
      memory: "8Gi"       # 单个容器最大限制
    min:
      cpu: "50m"
      memory: "64Mi"      # 单个容器最小限制

关键设计点:

  1. 配额 = 反超卖sum(namespace requests) < cluster allocatable,否则 Pod 无法调度
  2. default vs defaultRequest:不指定 limit/request 时自动注入,避免 BestEffort Pod
  3. max 限制:防止单个容器申请过大资源
  4. Scope 区分:可以用 scopes: [BestEffort, NotBestEffort, Terminating, NotTerminating] 精确控制

注意事项:

  • 配额变更需要与团队协商,避免一刀切
  • 配额过紧会导致开发体验差(申请被拒),过松导致资源浪费
  • 配合监控:Prometheus 告警 namespace_quota_usage > 80%

题目 3:多租户方案选型 — vCluster vs Capsule vs HNC vs Namespace#

设计需求: 为 SaaS 平台设计多租户隔离方案。每个租户需要独立的命名空间、RBAC、网络策略,且租户之间完全隔离。租户数 100+。

方案对比:

维度原生 NamespacevClusterCapsuleHNC (Hierarchical Namespace)
隔离程度逻辑(RBAC+NP)物理(独立 API Server)逻辑(增强 RBAC)逻辑(层级继承)
API Server 开销每个租户一个 vCluster(K3s)
租户管理员体验需学 K8s RBAC完整的 K8s 管理员体验简化的租户 CRD继承父 namespace 配置
资源效率最高最低(每租户额外 Pod)
适用租户数< 50< 100100-50050-200
运维复杂度高(管理 n 个集群)中(学习 Capsule CRD)中(学习 HNC CRD)

选择建议:

  • 原生 Namespace:租户 < 30,隔离要求不高,团队熟悉 K8s
  • vCluster:租户需要完整 K8s 体验(CRD/Custom Controller),强隔离要求
  • Capsule:租户 50+,需要 namespace 额度管理和租户自助服务
  • HNC:需要层级化(如 team → sub-team → env)的 namespace 策略继承

Capsule 架构示意:

text
Capsule Tenant "tenant-A"
├── Namespace: tenant-a-dev
├── Namespace: tenant-a-prod
├── NetworkPolicy: 跨 namespace 隔离 + 只允许到 ingress
├── ResourceQuota: 汇总所有子 namespace 配额
└── RBAC: Tenant Owner 角色(只能操作自己的 namespace)

注意事项:

  • vCluster 的每个虚拟集群需要跑 API Server + Controller Manager + etcd/kine(≈ 300MB 内存 / 租户),100 个租户 = 30GB 开销
  • Capsule 的租户配额是 summary 级别,子 namespace 配额由租户管理员自行分配
  • HNC 的层级继承可能造成意外影响(如某父 namespace 的 NetworkPolicy 被所有子 namespace 继承)

题目 4:网络隔离策略分层设计#

设计需求: 在多租户 K8s 集群中设计网络隔离策略,实现:同 namespace 内 Pod 自由通信、跨 namespace 默认拒绝、特定 namespace 可访问共享服务。

方案设计:

text
默认策略(Deny-All Baseline):
┌──────────────────────────────────────┐
│ 1. 每个 namespace 默认拒绝所有 ingress │
│ 2. 每个 namespace 默认拒绝所有 egress  │
└──────────────────────────────────────┘

逐层放行(Least Privilege):
┌──────────────────────────────────────┐
│ 3. 允许同 namespace 内 Pod 互访       │
│ 4. 允许 DNS 查询(UDP 53 → kube-system)│
│ 5. 允许访问 Ingress Controller       │
│ 6. 允许访问监控/metrics 端点          │
│ 7. 允许特定跨 namespace 业务调用      │
└──────────────────────────────────────┘

配置示例(关键 NetworkPolicy):

yaml
# 1. 默认拒绝所有 ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: team-alpha
spec:
  podSelector: {}        # 匹配所有 Pod
  policyTypes:
  - Ingress

---
# 2. 默认拒绝所有 egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
  - Egress

---
# 3. 放行 DNS(必须最先放行)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53

注意事项:

  • DNS 放行规则必须放在最前面(几乎所有服务都需要 DNS)
  • Calico/Cilium 支持更细粒度的网络策略(FQDN 级别、L7 级别)
  • 测试网络策略用 netshoot 容器:kubectl run tmp --rm -it --image=nicolaka/netshoot -- /bin/bash

子类 3:网络架构设计#

题目 1:CNI 选型 — Flannel vs Calico vs Cilium#

设计需求: 为生产 K8s 集群选择 CNI 插件。集群规模 50 节点、2000 Pod,需要 NetworkPolicy、高性能、可观测性。

方案对比:

维度FlannelCalicoCilium
数据平面vxlan/host-gwiptables/ipvseBPF
NetworkPolicy不支持原生(需额外组件)支持原生 + 自有扩展支持原生 + L7(DNS/HTTP)
性能中等(vxlan 有开销)高(BGP 模式近乎原生)最高(eBPF 内核处理)
可观测性基本 flow logHubble(L3/L4/L7 + API 调用图)
Service Mesh需独立部署 Istio需独立部署 Istio内置(Cilium Service Mesh)
学习曲线高(需理解 eBPF)
适用规模中小集群中大集群大集群(500+ 节点)

选择逻辑:

text
集群规模选择:
├── < 100 Pod → Flannel(简单够用)
├── 100-2000 Pod → Calico(NetworkPolicy + 高性能)
└── > 2000 Pod → Cilium(eBPF 性能 + Hubble 可观测性)

功能需求选择:
├── 只需要基本网络 → Flannel
├── 需要 NetworkPolicy → Calico
├── 需要 L7 策略 + 可观测性 → Cilium
└── 需要 Service Mesh → Cilium(无 sidecar)vs Istio(sidecar)

关键设计点:

  1. IPAM 模式选择
    • Calico:推荐使用 Kubernetes API 作为 IPAM 后端(简单可靠)
    • Cilium:推荐 Cluster Pool(自动分配 Pod CIDR)
  2. 路由模式选择
    • 同 VPC/二层可达:BGP 或 Direct Routing(性能最好)
    • 跨 VPC/三层隔离:VXLAN 或 Geneve(Overlay 模式)
  3. eBPF 要求:Cilium 最低 kernel 4.19,推荐 >= 5.4(kube-proxy replacement 及部分 eBPF 高级特性需 5.10+),云环境注意节点内核版本

注意事项:

  • Calico BGP 直连模式适用于自建/裸金属等可控网络;AWS VPC 不支持与节点做 BGP peering,云上 Calico 多用 VXLAN/IPIP overlay 或直接改用云厂商 VPC CNI
  • Cilium 替换 kube-proxy(新版用 kubeProxyReplacement: true,旧取值 strict/probe/partial 已废弃)有严格内核要求
  • CNI 迁移风险极高,选型后基本不会再换

题目 2:Service Mesh 选型 — Istio vs Cilium vs Linkerd#

设计需求: 100+ 微服务需要使用 Service Mesh 实现流量管理、mTLS、可观测性。

方案对比:

维度Istio (sidecar 模式)Cilium Service MeshLinkerd
流量管理VirtualService + DestinationRule(最强大)L7 HTTP Route(eBPF)SMI + 自有扩展
mTLS自动(istiod 签发,早期组件叫 Citadel)自动(基于 SPIFFE)自动(identity-based)
可观测性Kiali + Jaeger/ZipkinHubble(无需额外组件)Linkerd Viz
资源开销高(每个 Pod 一个 sidecar ~100MB)低(无 sidecar,eBPF 内核处理)中(rust proxy 约 10MB)
性能影响中等(两次网络栈处理)最低(eBPF 在内核处理)低(rust proxy 开销小)
生态成熟度最成熟(CNCF Graduated)正在追赶(功能不如 Istio 全)成熟(CNCF Graduated)
学习曲线最高
社区活跃度Google + 社区Isovalent (Cisco)Buoyant

选择建议:

  • Istio:需要复杂的流量管理(金丝雀/A/B Test/熔断/限流),已有独立运维团队
  • Cilium:新项目,追求性能和运维简便,愿意接受功能尚未完全对标 Istio
  • Linkerd:只需 mTLS + 基础流量管理,运维简单优先

架构示意 (Istio):

text
Service A (sidecar: istio-proxy)
    ├── mTLS ──→ Service B (sidecar)
    │              │
    │              └──→ Service C (sidecar)
    ├── Telemetry → Prometheus (metrics)
    ├── Tracing → Jaeger (traces)
    └── Logs → stdout → Fluent Bit → Loki

注意事项:

  • Istio sidecar 资源开销估算:100 个 Pod × 100MB = 10GB 额外内存
  • Istio Ambient 模式(无 sidecar,1.24 GA):L4 mTLS 由每节点 ztunnel 承载、L7 才按需拉起 waypoint proxy,资源开销显著低于 sidecar 模式,新项目可优先评估(对标 Cilium 的无 sidecar 卖点)
  • 启用 mesh 前必须扫所有 workload 的 excludeOutboundPorts annotation
  • 基础 Service selector 不能加 version 标签限制(会破坏 Istio DR subset 路由)

题目 3:Ingress Controller 选型#

设计需求: 为多租户平台选择 Ingress Controller,需求:HTTPS 终止、基于域名的路由、限流、WAF 集成。

方案对比:

维度NGINX IngressTraefikIstio GatewayAWS ALB Controller
协议支持HTTP/HTTPS/TCP/UDPHTTP/HTTPS/TCP/UDPHTTP/HTTPS/TCP(gRPC)HTTP/HTTPS
限流注解配置中间件EnvoyFilterWAF 集成
金丝雀发布注解(canary-by-header)中间件VS weight routingALB target group 权重
自动证书cert-manager 配合内置 ACMEcert-manager 配合ACM(AWS 原生)
WAF需外部需外部需外部AWS WAF 原生集成
适用场景通用场景云原生 + 自动发现已用 Istio 时首选AWS 环境最优

选择建议:

  • NGINX Ingress:通用,社区最成熟,功能全面
  • Traefik:追求自动服务发现,配置简洁
  • Istio Gateway:已使用 Istio Service Mesh 时的最佳选择(统一管理南北/东西流量)
  • AWS ALB Controller:纯 AWS 环境,需要 WAF + ACM + Cognito 集成时最佳

注意事项:

  • Gateway API v1 已 GA(gateway.networking.k8s.io/v1,2023-10),Ingress API 已进入维护冻结(不再加新特性);新平台优先 Gateway API(Gateway + HTTPRoute,角色分离、原生支持流量切分与多协议),Ingress 仅作存量兼容
  • 多 Ingress Controller 共存时注意 ingressClassName 隔离
  • ALB 每个 Ingress 创建一个 ALB(成本),可用 IngressGroup 合并

题目 4:NetworkPolicy 分层设计#

设计需求: 设计一个覆盖 L3/L4/L7 的 NetworkPolicy 体系,实现生产环境的零信任网络架构。

方案设计:

text
安全环模型(Defense in Depth):

第一环:集群边界(Ingress Controller)
├── HTTPS 终止 + cert-manager 自动证书
├── Rate Limiting
├── WAF 规则
└── 只允许白名单 path/method

第二环:命名空间边界(NetworkPolicy)
├── 默认拒绝所有跨 namespace 流量
├── 白名单放行特定 namespace/service
└── 禁止 Pod 出公网(通过 egress gateway)

第三环:Pod 边界(NetworkPolicy + mTLS)
├── 只允许声明过的 ingress/egress
├── Istio mTLS STRICT 模式
├── L7 策略:HTTP method + path + header 控制
└── Sidecar 资源限制 egress 范围

第四环:出口控制
├── Egress NetworkPolicy:只允许特定域名
├── Cilium DNS Policy:FQDN 级别出口过滤
├── 出口流量审计(Hubble / Istio access log)
└── 异常流量检测与告警

关键 NetworkPolicy 实现:

yaml
# 出口限制到特定 FQDN(Cilium 特有)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: egress-whitelist
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: my-service
  egress:
  - toFQDNs:
    - matchName: "api.trusted-partner.com"
    - matchName: "monitoring.internal.com"
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
        k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP

注意事项:

  • 不要一步到位全部 deny(会导致业务中断),按 namespace 逐步收紧
  • DNS egress 永远是第一个放行的规则
  • 出口 IP 白名单最好配合 egress gateway 或 HTTP proxy

子类 4:CI/CD 与 GitOps 设计#

题目 1:ArgoCD vs FluxCD 选型#

设计需求: 技术团队(20+ 人)需要实现 GitOps,管理 200+ 应用在多集群上的部署。

方案对比(核心差异):

维度ArgoCDFluxCD
架构单体 API Server + Application Controller五控制器解耦(source/kustomize/helm/image/notification)
抽象层Application/ApplicationSetKustomization + HelmRelease
Web UI内置丰富 UI无(依赖 CLI 或第三方)
多租户AppProject + RBAC通过 namespace + RBAC 隔离
多集群每个集群部署 Application Controller 或 Hub-Spoke每集群安装 Flux 控制器
同步模式Manual/Auto Sync + PruneContinuous Reconciliation + Prune
依赖编排Sync Waves + HooksdependsOn + Health Checks
Image UpdaterArgocd-image-updater(独立项目)image-reflector + image-automation(内置)
性能受 Application 数量和 repo-server 影响控制器解耦,水平扩展好
架构哲学Server-First(重 UI)Controller-First(CRD 即 API)

选择建议:

  • ArgoCD:需要 Web UI 给开发同学看 sync 状态,快速上手,团队 < 50 人
  • FluxCD:追求 GitOps 纯粹性(CI 完全无感集群),需要嵌入 Backstage/IDP,多集群场景 50+
  • 不建议:两套并用(增加学习成本和运维复杂度)

FluxCD 架构设计(重点):

text
                    ┌─────────────────────────┐
                    │    Git / OCI / Bucket   │
                    └───────────┬─────────────┘
                ┌──────────────────────────────┐
                │   source-controller          │  CRD: GitRepository
                │   拉源码 → 缓存 → artifact    │
                └───────────┬──────────────────┘
              ┌─────────────┴─────────────┐
              ▼                           ▼
  ┌──────────────────────┐   ┌──────────────────────┐
  │ kustomize-controller │   │   helm-controller    │
  │ CRD: Kustomization   │   │ CRD: HelmRelease     │
  │ kustomize build → apply │ │ helm install/upgrade  │
  └──────────────────────┘   └──────────────────────┘
              │                           │
              └───────────┬───────────────┘
                  ┌───────────────┐
                  │  Kubernetes   │
                  └───────────────┘

FluxCD 关键优势:

  1. 无中央 Server 单点:每个控制器独立部署,Apiserver 活着就能 reconcile
  2. CI 完全无感集群:CI 不拿 kubeconfig,只改 git(Pull-based GitOps 的极致)
  3. 水平扩展自然:每个控制器独立调 --concurrency
  4. 集成简单:上层平台只需 kubectl apply CRD,不需调 ArgoCD API

注意事项:

  • Flux 的 Kustomization 依赖 chain(dependsOn)是声明式的,Argo 的 Sync Waves 是数字排序的
  • Flux 没有 Application 的聚合状态,需要自己构建 Dashboard(如用 Weave GitOps 或自定义 Grafana)
  • 迁移成本:Argo → Flux 需要重写 Application YAML 为 Kustomization + GitRepository

题目 2:Helm vs Kustomize 配置管理#

设计需求: 管理多环境的 K8s 配置,要求:base 模板复用,环境差异通过 overlay 覆盖,配置变更可追溯。

方案对比:

维度HelmKustomize
配置方式Go template({{ .Values.xxx }})YAML Patch(strategic merge / JSON patch)
模板 vs 纯 YAML模板语言,不渲染看不到最终效果纯 YAML,可视即可得
多环境多个 values 文件overlay 目录(base + 环境 overlay)
复杂度中(学习 template 语法)低(学习 patch 语法)
发布管理Helm Release(helm install/upgrade/rollback)无原生 release 管理(依赖 GitOps)
与 GitOps 集成ArgoCD/Flux 均原生支持ArgoCD/Flux 均原生支持(Flux 更推荐 Kustomize)

选择建议:

  • Kustomize + GitOps(推荐):适合 GitOps 模式。配置即代码,base + overlay 模式清晰。kubectl 内置(kubectl apply -k)。
  • Helm + GitOps:社区 chart 生态丰富(如 kube-prometheus-stack),适合使用第三方 chart 的场景。
  • 混合模式:用 Helm 消费社区 chart,用 Kustomize 管理自定义配置(ArgoCD 和 Flux 都支持 Helm Chart + Kustomize 混合)

Kustomize Overlay 设计示例:

text
apps/frontend/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
├── overlays/
│   ├── production/
│   │   ├── kustomization.yaml    ← resources: [../../base], patches
│   │   └── replica-count.yaml    ← patch: replicas: 5
│   ├── staging/
│   │   ├── kustomization.yaml
│   │   └── resource-limits.yaml
│   └── qa/
│       ├── kustomization.yaml
│       └── ingress.yaml
└── components/
    └── monitoring/
        └── kustomization.yaml    ← 可复用组件(ServiceMonitor 等)

三大高频踩坑(来自生产经验):

  1. overlay 目录里放了 YAML 但 kustomization.yamlresources: 没列出 → 文件不被部署
  2. Patch 的 target.name 写死导致某些服务 patch 不生效 → overlay 只有一个 Deployment 时只写 kind: Deployment
  3. PR 隔离 overlay 给 Service 改了 selector,但基础 Service 的 selector 仍匹配 PR Pod → 流量反向泄漏

题目 3:多环境发布策略设计#

设计需求: 为核心服务设计一套安全发布策略,支持灰度验证和快速回滚。

三种策略对比与选择:

维度滚动发布(Rolling Update)蓝绿发布(Blue-Green)金丝雀发布(Canary)
资源成本低(复用现有节点)高(需双倍资源)中(验证节点额外资源)
风险控制中(逐步替换)低(可瞬间切回)最低(小比例验证)
回滚速度慢(反向滚动,分钟级)快(秒级切流量)快(调整流量比例)
实现复杂度低(Deployment 原生)高(管理两套环境)高(流量染色/分割)
K8s 实现Deployment RollingUpdateService selector 切换 / 两套 DeploymentArgo Rollouts / Flagger(底层 Istio VS weight 或 Gateway API 权重)
适用场景无状态、DB 向前兼容需快速验证核心服务、A/B 测试

混合策略设计:

text
发布流程:
1. 金丝雀发布(Canary 5% → 观察 15min)
   ├── Istio VS weight: baseline=95, canary=5
   ├── 监控:错误率、延迟 P99、CPU/Memory
   └── 异常 → 立即回滚(weight: canary=0)

2. 滚动发布(逐步替换)
   ├── maxSurge: 1, maxUnavailable: 0(零停机)
   ├── 新 Pod Ready 后才删旧 Pod
   └── ReadinessProbe 必须配置(否则判断不了新 Pod 是否 Ready)

3. 蓝绿切换(关键版本)
   ├── 部署 Blue(当前)、Green(新版本)两组 Deployment
   ├── Service selector 初始指向 Blue
   ├── 验证 Green 健康 → 切 Service selector 到 Green
   └── 回滚 → 切回 Blue

关键配置(零停机的完整五要素):

yaml
apiVersion: apps/v1
kind: Deployment
spec:
  # 1. 滚动策略:先起新再删旧,全程不减少可用副本
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # 最多多出 1 个 Pod
      maxUnavailable: 0     # 发布过程中始终保持所有 Pod 可用
  template:
    spec:
      # 4. 优雅关闭窗口:需 > preStop + 应用退出时间
      terminationGracePeriodSeconds: 45
      containers:
        - name: app
          # 2. readinessProbe:未 Ready 不进 Endpoints,避免打到没准备好的 Pod
          readinessProbe:
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 3
          # 3. preStop:先 sleep 让 Endpoints 摘除生效,避免"关闭中仍收到新连接"
          lifecycle:
            preStop:
              exec: { command: ["/bin/sh", "-c", "sleep 10"] }
---
# 5. PDB:滚动发布/节点维护/驱逐时,保证最小可用副本,防止被一次性打空
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb
spec:
  minAvailable: 80%        # 或 maxUnavailable,二选一
  selector:
    matchLabels: { app: my-app }

摘流时序:收到 SIGTERM 时,kubelet 与 Endpoints 摘除是并发的,若不 sleep,旧 Pod 可能在被摘除前就关闭连接 → 客户端 5xx。preStop sleep 覆盖这段传播延迟,之后应用再优雅退出(drain in-flight 请求)。

渐进式发布工具(金丝雀/蓝绿别手搓):

  • Argo Rollouts:用 Rollout CR 替代 Deployment,声明式定义 canary steps(setWeight/pause/analysis),配合 AnalysisTemplate 自动读 Prometheus 指标决定继续或回滚。
  • Flagger:在原生 Deployment 之上做自动化金丝雀,与 Istio/Linkerd/App Mesh/NGINX/Gateway API 集成,按指标自动加权与回滚。
  • 二选一即可,别与手工 Istio VS weight 混用(状态源冲突)。

注意事项:

  • 无 ReadinessProbe → 新 Pod 未 Ready 就接收流量 → 滚动发布出现 5xx
  • 数据库 Schema 变更必须向前兼容(先加字段不删字段,先双写再切新逻辑)
  • maxUnavailable: 0 + maxSurge: 1 的前提是集群有足够资源起额外 Pod
  • 金丝雀发布需要能区分 baseline 和 canary 的 metrics(如 istio_requests_total{destination_version=~"canary"},注意指标名是 istio_requests_total 带 s)

验证: 发布过程中持续压测(如 vegeta/hey)观察是否有非 200 响应;kubectl rollout status 应无中断;主动删一个 Pod 验证 PDB 拦截与优雅退出(无连接被重置)。


题目 4:PR 隔离环境设计#

设计需求: 开发者推送 PR 时自动创建隔离的测试环境,PR 合并后自动销毁。要求:PR 环境与基线环境完全隔离,不能相互影响。

方案设计:

text
PR 环境生命周期:

GitHub PR Open / Push
CI Pipeline
    ├── Build Image + Push to Registry
    ├── 生成 PR Overlay YAML → Commit to GitOps Repo
    │   └── Render template from gitops/templates/pr/{project}/{service}/
    ├── ArgoCD Sync → 创建 PR 环境
    │   ├── Namespace: pr-{pr_number}-{service}
    │   ├── Deployment: version=pr-{pr_number}-{service}
    │   ├── Service: selector: app=pr-{pr_number}-{service}
    │   ├── HTTPRoute: host=pr-{pr_number}.qa.example.com
    │   └── Istio DR/VS: subset=pr-{pr_number}
    └── 通知开发者:http://pr-{pr_number}.qa.example.com

PR Merged / Closed
    ├── 删除 GitOps 中 PR overlay 目录
    ├── ArgoCD Sync → 自动清理 PR 资源
    ├── ArgoCD prune → 删除 Namespace + 所有资源
    └── 回收 PR 号码(避免 namespace 名冲突)

关键设计点(PR 隔离 Checklist):

  1. Service Selector 完全隔离:PR Pod 的 labels.app 必须替换为 pr-{pr_number}-{service},确保基础 Service 不匹配 PR Pod
  2. HTTPRoute 隔离:PR 环境使用独立 hostname(pr-{pr_number}.qa.example.com
  3. Istio DR/VS 隔离:PR Pod 保留 app=base label(被 DR subset 识别),但 Service selector 改为 PR 专用
  4. 数据库隔离:PR 环境使用独立数据库(或测试数据库的独立 schema)
  5. 消息队列隔离:PR 环境使用独立 consumer group,防止消费生产消息
  6. 资源限制:PR Namespace 配 ResourceQuota(如 max 2CPU/4Gi),防止 PR 环境耗尽集群资源
  7. 自动清理:PR 关闭后定时任务自动清理,防止资源泄漏

注意事项(来自生产事故):

  • PR overlay 模板结构变化时,必须同步重渲染存量 overlay(否则旧 PR 下次推送 SyncFailed)
  • 基础 Service selector 加 version=baseline 会破坏 Istio DR subset 路由(PR Pod 不进 endpoints → 503)
  • Kustomize PR overlay 中 Deployment selector 变化会触发 immutable 错误(selector 不可变)

子类 5:可观测与告警体系设计#

题目 1:Prometheus + Grafana 监控架构设计#

设计需求: 为多集群(3 集群 × 100 服务)设计监控体系。需支持:指标采集、长期存储、Dashboard、告警。

方案设计:

text
多集群监控架构(Push 模式):

┌──────────────────────────────────────────────────┐
│          中央存储:VictoriaMetrics / Thanos         │
│                                                     │
│  ┌─────────────────────────────────────────────┐  │
│  │  VM Cluster (vminsert → vmstorage → vmselect) │  │
│  │  - 压缩率高(比 Prometheus 省 7 倍存储)      │  │
│  │  - 支持多租户                                  │  │
│  └─────────────────────────────────────────────┘  │
│            ▲                                       │
│            │ remote_write                          │
│  ┌─────────┴──────────┐                           │
│  │  Thanos Receive     │                           │
│  │  (备选方案)         │                           │
│  └────────────────────┘                           │
└──────────────────────────────────────────────────┘
       ▲                          ▲
       │ remote_write             │ remote_write
┌──────┴──────┐          ┌───────┴──────┐
│ Cluster A   │          │ Cluster B    │
│ Prometheus  │          │ Prometheus   │
│ (15d local) │          │ (15d local)  │
└─────────────┘          └──────────────┘

分层设计:

yaml
# 第一层:数据采集
---
- Prometheus Operator + ServiceMonitor(自动发现)
- kube-prometheus-stack(一站式部署 Prometheus + Grafana + Alertmanager)
- Node Exporter(DaemonSet,节点指标)
- kube-state-metrics(Deployment、Pod、PVC 等资源状态)

# 第二层:指标聚合
---
- Prometheus per cluster(自建,15 天本地保留)
- remote_write → VictoriaMetrics 集群(1 年保留)
- Recording Rules 预计算常用 PromQL(减少查询延迟)

# 第三层:可视化
---
- Grafana(统一 Dashboard,数据源指向 VictoriaMetrics)
  - 集群概览 Dashboard
  - 业务 SLO Dashboard
  - 成本分析 Dashboard
- Grafana Alerting(替代 Alertmanager 的 UI 管理)

# 第四层:告警
---
- PrometheusRule → Alertmanager
- Alertmanager 路由: 按 severity / team 分发到不同钉钉群
- VictoriaMetrics vmalert(作为备份评估引擎)

监控覆盖四层(采集目标,别只盯节点):

层级数据源核心指标
节点层node-exporter(DaemonSet)node_cpu_seconds_totalnode_memory_MemAvailable_bytesnode_filesystem_avail_bytes
容器层cAdvisor(kubelet 内置)container_cpu_usage_seconds_totalcontainer_memory_working_set_bytes、OOM/重启
K8s 资源层kube-state-metricskube_deployment_status_replicaskube_pod_status_phasekube_node_status_condition
应用层ServiceMonitor(自定义 /metricsQPS、延迟 P50/P99、错误率

关键组件选型:

组件选型理由
指标采集kube-prometheus-stackK8s 原生,CRD 管理,社区活跃
长期存储VictoriaMetrics压缩率高(7:1),PromQL 兼容
可视化Grafana事实标准,丰富的 Dashboard 生态
日志Loki索引少、成本低,与 Prometheus/Labels 兼容
链路追踪Tempo与 Loki/Prometheus 统一标签体系

注意事项:

  • Prometheus Remote Write 需要评估网络带宽(每样本约 20 bytes × samples_rate)
  • VictoriaMetrics 单机上限约 100 万 samples/sec,超出需用集群模式
  • Recording Rules 必须预计算(否则 Grafana 查询卡死)

题目 2:SLO/SLI 体系与 Error Budget 告警设计#

设计需求: 为 3 个核心服务定义 SLO(99.9% 可用性),设计 Error Budget 消耗告警。

方案设计:

1. SLI 指标选取(用户视角):

服务SLI 类型指标目标
API Gateway可用性HTTP 2xx/3xx 比例99.9%(月)
API Gateway延迟P99 响应时间< 500ms
订单服务可用性gRPC OK 比例99.95%(月)
支付服务延迟P99 响应时间< 200ms

2. Recording Rules(Prometheus):

yaml
# 可用性 SLI(5 分钟窗口)
- record: job:http_requests:success_rate5m
  expr: |
    sum(rate(http_requests_total{status=~"2..|3.."}[5m])) by (job)
    /
    sum(rate(http_requests_total[5m])) by (job)

# Error Budget Burn Rate(1h / 6h / 3d 多窗口)
- record: job:http_requests:error_budget_burn_rate1h
  expr: |
    (
      1 - sum(rate(http_requests_total{status=~"2..|3.."}[1h])) by (job)
      / sum(rate(http_requests_total[1h])) by (job)
    )
    / (1 - 0.999)   # 除以 (1 - SLO),SLO=99.9%

# Error Budget 剩余百分比(30 天窗口)
- record: job:http_requests:error_budget_remaining30d
  expr: |
    1 - (
      (1 - sum(rate(http_requests_total{status=~"2..|3.."}[30d])) by (job)
      / sum(rate(http_requests_total[30d])) by (job))
      / (1 - 0.999)
    )

3. 多窗口 Burn Rate 告警(Google SRE 推荐):

yaml
# P1:快速消耗(2% Error Budget 在 1 小时内烧完 → burn rate > 14.4)
- alert: SLOBurnRateCritical
  expr: |
    job:error_budget_burn_rate1h > 14.4
    AND
    job:error_budget_burn_rate5m > 14.4
  for: 2m
  labels:
    severity: critical
  annotations:
    summary: "{{ $labels.job }} Error Budget 快速消耗"
# burn rate 14.4 = 在1小时内消耗了 2% 的月度 Error Budget(14.4×1h/720h≈2%);6h 窗口 burn rate 6 → 5%,3d 窗口 burn rate 1 → 10%

# P2:中速消耗(5% Error Budget 在 6 小时内 → burn rate > 6)
- alert: SLOBurnRateHigh
  expr: |
    job:error_budget_burn_rate6h > 6
    AND
    job:error_budget_burn_rate30m > 6
  for: 15m
  labels:
    severity: warning

# P3:慢速消耗(10% Error Budget 在 3 天内 → burn rate > 1)
- alert: SLOBurnRateLow
  expr: |
    job:error_budget_burn_rate3d > 1
    AND
    job:error_budget_burn_rate6h > 1
  for: 1h
  labels:
    severity: info

多窗口交叉逻辑:

  • 长窗口(1h/6h/3d)→ 检测持续性问题,过滤短暂毛刺
  • 短窗口(5m/30m)→ 确认问题当前正在发生,过滤历史遗留的"尾巴"
  • 两个窗口 AND → 必须是"持续且当前活跃"的故障才告警

Error Budget 策略:

  • 消耗 > 50% → 冻结非紧急发布,只允许修复性发布
  • 消耗 > 80% → 所有发布暂停,SRE review 必须
  • 消耗 100% → 触发 SLO 违规复盘,改进措施必须落地

推进 SLO 文化的 3 阶段:

text
第一阶段(1-2 月):只观察不告警
├── 建立 Dashboard,让团队熟悉指标含义
└── 修正 SLI 计算逻辑

第二阶段(3-4 月):只 P1 告警
├── 每月 Error Budget 回顾会议
└── 建立 SLO 违规复盘流程

第三阶段(5 月+):发布决策集成
├── Error Budget 冻结策略
├── 发布前评估预算余量
└── 每季度调整 SLO 目标

题目 3:日志采集方案选型 — EFK vs Loki#

设计需求: 为多集群设计日志采集方案,日均日志量 500GB,保留 30 天,需要全文检索。

方案对比:

维度EFK (Elasticsearch + Fluentd + Kibana)Loki + Promtail + Grafana
索引方式全文索引(高成本)标签索引(低成本)
存储成本高(日志体积 × 1.5-2)低(日志体积 × 0.3-0.5)
全文检索强(Kibana Query DSL)弱(LogQL,标签过滤 + 内容 grep)
运维成本高(ES 集群需要调优)低(依赖对象存储)
与 Prometheus 集成同标签体系,Grafana 无缝关联

选择建议:

  • Loki + Promtail(推荐):K8s 原生场景,日志量不大,不需要复杂全文检索。标签与 Prometheus 统一,Grafana 里 Metric → Log 一键跳转。
  • EFK:需要复杂全文检索、聚合分析、复杂 Dashboard(如安全审计)
  • 混合:JVM/应用日志 走 Loki,安全审计日志走 EFK

Loki 架构设计:

text
┌──────────┐    ┌──────────┐    ┌──────────┐
│ Pod A    │    │ Pod B    │    │ Pod C    │
│ stdout   │    │ stdout   │    │ stdout   │
└────┬─────┘    └────┬─────┘    └────┬─────┘
     │               │               │
     ▼               ▼               ▼
┌──────────────────────────────────────────┐
│          Promtail (DaemonSet)             │
│  - 添加 K8s 标签(namespace/pod/container) │
│  - 推送日志到 Loki Distributor             │
└─────────────────────┬────────────────────┘
┌──────────────────────────────────────────┐
│           Loki (Distributed)              │
│  Distributor → Ingester → Object Store    │
│  (S3/GCS/OSS 做长期存储,低成本)           │
└──────────────────────────┬───────────────┘
                   ┌──────────────┐
                   │   Grafana    │  LogQL 查询 + 与 Metric 关联
                   └──────────────┘

题目 4:Alertmanager 路由与抑制规则设计#

设计需求: 统一管理多集群 Alertmanager 告警路由,实现告警分级分发、去重抑制、静默管理。

方案设计(基于实际生产经验):

Alertmanager 架构:

text
                  ┌─────────────┐
                  │ Prometheus  │  Pro集群
                  └──────┬──────┘
                         │ alerts
                  ┌─────────────┐
  Webhook Bridge  │Alertmanager │  ← 唯一收敛点
  (业务侧告警) ──→│ (主实例)    │
            ┌────────────┴────────────┐
            ▼                         ▼
     ┌─────────────┐          ┌─────────────┐
     │  Watchdog?   │          │  Routing:    │
     │  → HC.io     │          │  severity →  │
     └─────────────┘          │  team        │
                              └──────┬───────┘
            ┌────────────────────────┼────────────────────┐
            ▼                        ▼                    ▼
    ┌──────────────┐      ┌──────────────┐     ┌──────────────┐
    │ DingTalk Prod│      │DingTalk Staging│    │  Feishu P0   │
    └──────────────┘      └──────────────┘     └──────────────┘

路由规则:

yaml
# Alertmanager 路由配置
route:
  receiver: webhook-dingtalk-prod  # 默认接收器
  group_by: ['alertname', 'cluster', 'namespace']
  group_wait: 30s      # 同组告警聚合等待
  group_interval: 5m   # 同组告警重复间隔
  repeat_interval: 4h  # 未恢复告警重发间隔(太长导致遗漏,太短导致噪音)
  routes:
    # Watchdog 独立通道(永远排除在 silence 之外)
    - matchers:
        - alertname = "Watchdog"
      receiver: dead-mans-switch
      group_wait: 10s
      continue: false

    # P0 → 飞书 On-call 群(带 @所有人)
    - matchers:
        - severity = "P0"
      receiver: feishu-oncall
      group_wait: 10s
      repeat_interval: 15m
      continue: true

    # Staging/QA → 对应钉钉群
    - matchers:
        - env =~ "staging|qa"
      receiver: webhook-dingtalk-staging
      continue: false

    # 邮件备份(P0/P1)
    - matchers:
        - severity =~ "P0|P1"
      receiver: email-fallback
      continue: true

抑制规则(Inhibit Rules):

yaml
inhibit_rules:
  # 集群级故障抑制具体节点/Pod 告警
  - source_matchers:
      - alertname = "KubeAPIDown"
    target_matchers:
      - severity =~ "warning|info"
    equal: ['cluster']

  # 节点 NotReady 抑制其上 Pod 的 Restart/Pending 告警
  - source_matchers:
      - alertname = "NodeNotReady"
    target_matchers:
      - alertname =~ "Pod.*Restart|Pod.*Pending"
    equal: ['cluster', 'instance']

  # 高 severity 抑制低 severity 同名告警
  - source_matchers:
      - severity = "P0"
    target_matchers:
      - severity =~ "P1|P2"
    equal: ['alertname', 'cluster']

Silence 规范(来自生产事故教训):

bash
# 绝对禁止:alertname=~".+"(会误伤 Watchdog 心跳)
# 正确姿势:显式排除 Watchdog

# 安全 silence 脚本
amtool silence add \
  alertname!=Watchdog \
  --comment="上线窗口 silence(排除 Watchdog)" \
  --duration=2h

Watchdog 反向告警设计:

  • 一条 alert: Watchdog 规则永远 firing(expr: vector(1)
  • 走独立 receiver 推 healthchecks.io
  • 30s 无心跳 → healthchecks.io 触发反向告警到独立钉钉群
  • 主告警群 和 反向告警群 必须分开(不同群/不同机器人)

注意事项:

  • 钉钉机器人关键词必须覆盖 firing "告警" 和 resolved "恢复" 两类消息
  • Silence 用 isEqual: false 负匹配排除 Watchdog
  • 告警适配器选 config-as-data 而不是 config-as-URL(避免 URL encode 双重转义)

子类 6:成本治理与资源规划#

题目 1:FinOps 三阶段体系设计#

设计需求: 某公司 K8s 月账单 $52k,需建立 FinOps 体系统一管理成本。要求:成本可观测、可分摊、可优化。

方案设计(基于实际案例):

FinOps 三阶段:

text
阶段 1: Inform(看清花费)— 不可跳过
├── 建立标签体系(Label Schema)
├── 部署 OpenCost / Kubecost
├── 强制标签准入(Kyverno Policy)
└── Grafana 成本 Dashboard

阶段 2: Optimize(优化浪费)— 按 ROI 排序
├── 闲置资源识别(VPA Recommender)
├── 清理孤儿 PVC(无 Pod 使用的 EBS 卷)
├── 启用 Karpenter Consolidation
├── Spot 节点混合策略
└── 批量降低虚高 requests

阶段 3: Operate(固化流程)— 防止反弹
├── CI 集成成本检查(PR 改 resources → 自动估算月度影响)
├── 周度/月度自动报告
├── 超预算自动告警
└── 季度 FinOps Review(各团队 Owner 负责成本趋势)

强制标签体系:

yaml
# 必须标签(Kyverno ClusterPolicy 强制校验)
required_labels:
  - app.kubernetes.io/name  # 服务名
  - team                    # 负责团队
  - env                     # 环境
  - cost-center             # 成本中心编号

关键设计:

  • 先 Inform 后 Optimize:跳过第一步直接优化 = 优化了也不知道效果
  • 先 Showback 后 Chargeback:先给团队看成本(不扣预算),建立意识后再真扣
  • 闲置成本分摊:按实际使用比例分摊闲置资源(鼓励团队写准确 requests)

题目 2:资源 Request 优化策略#

设计需求: 集群中 60% Deployment 的 CPU request 远高于实际用量(CPU 实际用 200m 但 request 写了 2C),导致节点数过多、成本浪费严重。

优化方案:

1. 部署 VPA(仅 Recommender 模式,不自动更新):

bash
helm install vpa fairwinds-stable/vpa \
  --namespace vpa --create-namespace \
  --set updater.enabled=false \           # 不自动重启 Pod
  --set admissionController.enabled=false \
  --set recommender.enabled=true          # 只跑推荐

2. 批量生成推荐报告:

bash
# 找出 requests 虚高的 Deployment(用量 < 20% requests)
kubectl get vpa -A -o json | jq -r '
  .items[] |
  select(.status.recommendation != null) |
  .metadata.namespace as $ns |
  .metadata.name as $name |
  .status.recommendation.containerRecommendations[]? |
  {ns: $ns, name: $name, container: .containerName,
   cpu_recommended: .lowerBound.cpu,
   cpu_current: (.target.cpu // "N/A"),
   mem_recommended: .lowerBound.memory}
' | jq -s 'sort_by(.cpu_recommended)'

3. 用 Goldilocks 可视化:

bash
helm install goldilocks fairwinds-stable/goldilocks
kubectl label namespace production goldilocks.fairwinds.com/enabled=true
# Dashboard 直接展示推荐值 + 采纳后节省金额

4. 发给各团队 PR 降 requests:

不自己改 → 让团队 Owner 根据推荐报告提 PR 改 resources。配合 Infracost 估算月度节省金额(增加说服力)。


题目 3:Spot/On-Demand 混合策略设计#

设计需求: 降低 EC2 节点成本 40%,同时保证生产环境稳定性。

方案设计:

Karpenter NodePool 混合配置:

yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]  # 优先 Spot,没有时 fallback On-Demand
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]       # 多规格可选提升 Spot 可用性
      expireAfter: 720h                  # 节点最多跑 30 天(定期轮换)
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized   # v1 合法取值:WhenEmpty | WhenEmptyOrUnderutilized(旧的 WhenUnderutilized 已废弃)
    consolidateAfter: 30s
    budgets:
      - nodes: "10%"                # 每次中断不超过 10% 节点,限制爆炸半径

分层策略:

text
第一层:无状态服务
├── 全量 Spot
├── 配置 PDB(minAvailable: 1)
├── 安装 Node Termination Handler
└── 容忍 2% 中断率

第二层:有状态服务
├── 全部 On-Demand
├── annotation: karpenter.sh/do-not-disrupt: "true"
└── 0% 容忍中断

第三层:批处理/后台任务
├── Spot
├── 无 PDB(中断后自动重试)
└── 优先使用 cheapest instance

Spot 中断处理:

  • 部署 AWS Node Termination Handler(提前 2 分钟收到中断通知)
  • 收到通知 → cordon + drain 节点 → Karpenter 自动创建新节点 → Pod 在新节点启动
  • PDB 保护关键服务(至少保留 1 个副本)

题目 4:Karpenter vs Cluster Autoscaler 选型#

设计需求: 选择 K8s 集群节点自动伸缩方案。

方案对比:

维度Cluster Autoscaler (CA)Karpenter
扩缩速度分钟级秒级(直接调用 EC2 API,不经过 ASG)
节点选择固定 NodeGroup/ASG动态选择最优实例(规格/价格/AZ)
碎片整理不支持Consolidation(主动合并负载到更少节点)
Spot 支持基本支持原生优先级 + 多 fallback
容量预留支持(capacityReservation)
复杂度简单(与 ASG 集成)中(需学习 NodePool + NodeClass)
适用场景传统 ASG 模式追求极致利用率和成本优化

选择建议:

  • CA:已有 ASG 体系、节点规格固定、团队 < 5 人的中小集群
  • Karpenter:追求成本优化、需要 Consolidation、节点规格灵活的集群
  • AWS EKS 环境优先用 Karpenter(原生集成,更快更省)

多 NodePool 分工设计(按工作负载画像隔离节点池):

yaml
# 示意:不同负载用不同 NodePool,各自定制实例族与合并策略
# CPU 密集:instance-category=["c"],consolidationPolicy=WhenEmptyOrUnderutilized
# GPU 推理:instance-category=["g","p"],consolidationPolicy=WhenEmpty(加载模型贵,不轻易合并)
# 每个 NodePool 设 limits(cpu / nvidia.com/gpu)作硬上限,防误配导致成本失控

Pod 用 nodeSelector: karpenter.sh/nodepool: <name> + 对应 toleration 落到指定池。

CA 场景的碎片整理:CA 本身不做 Consolidation,需配 DeschedulerLowNodeUtilization 插件)驱逐低利用率节点上的 Pod → CA 回收空节点。Karpenter 则原生做这件事(WhenEmptyOrUnderutilized,且尊重 PDB,比手动 drain 安全)。


题目 5:OpenCost 部署与多团队费用分摊#

设计需求: 部署 OpenCost 实现 K8s 成本分摊,各团队按实际用量承担成本。

部署方案:

bash
# 安装 OpenCost(接入已有 Prometheus)
helm install opencost opencost/opencost \
  --namespace opencost --create-namespace \
  --set opencost.prometheus.external.enabled=true \
  --set opencost.prometheus.external.url=http://prometheus.monitoring:9090

分摊模型设计:

成本类型分摊方式
直接分配成本Pod 独占的 CPU/Memory → 按 team label 直接归属
共享基础设施kube-system/monitoring/ingress → 按各团队请求比例分摊
闲置成本节点买了但没用的部分 → 按各团队实际使用比例分摊(激励写准确 requests)
集群管理费用EKS 控制面费 / LB 费 → 按团队请求比例分摊

成本查询 API:

bash
# 按 team label 分摊的成本
curl -s "http://opencost.opencost:9003/allocation" \
  -d "window=lastmonth" \
  -d "aggregate=label:team" \
  -d "shareIdle=true" \
  -d "shareTenancyCosts=true" | \
  jq '.data[0] | to_entries[] | {team: .key, cost: (.value.totalCost | floor)}'

告警规则:

yaml
# 月度成本预测超预算
- alert: MonthlyCostProjectionExceeded
  expr: (sum(increase(opencost_total_cost[24h])) * 30) > 45000
  for: 1h
  labels:
    severity: warning
  annotations:
    summary: "月度成本预测 ${{ $value | printf \"%.0f\" }} 超预算"

# Namespace 成本异常翻倍(对比上周同期)
- alert: NamespaceCostAnomaly
  expr: |
    (sum by (namespace) (increase(opencost_total_cost[1h]))
    /
    sum by (namespace) (increase(opencost_total_cost[1h] offset 7d))) > 2
  for: 30m

题目 6:闲置资源巡检与治理#

设计需求: 建立周期性的闲置资源巡检机制,定期清理僵尸资源,防止成本反弹。

巡检项目清单:

巡检项脚本/命令频率清理策略
孤儿 PVC查找无 Pod 引用的 Bound PVC每周人工确认后删除
未使用 ConfigMap/Secret查找无引用者每周人工确认后删除
旧镜像/快照crictl rmi --prune / 云厂商快照 API每周删除 30 天前的快照
闲置 ELB/ALBAWS CLI 查找无 target 的 LB每月确认后删除
未关联 EIP云厂商 API每月释放
旧 EBS 快照超过保留期限的快照每月删除

孤儿 PVC 巡检脚本(CronJob):

bash
#!/bin/bash
# find-orphan-pvc.sh
kubectl get pvc -A -o json | jq -r '
  .items[] | select(.status.phase == "Bound") |
  "\(.metadata.namespace)/\(.metadata.name)"
' | while IFS='/' read ns pvc; do
  count=$(kubectl get pods -n "$ns" -o json | jq --arg pvc "$pvc" \
    '[.items[].spec.volumes[]? | select(.persistentVolumeClaim.claimName == $pvc)] | length')
  [ "$count" -eq 0 ] && echo "ORPHAN PVC: $ns/$pvc"
done

防止反弹机制:

  1. CI 集成成本检查:PR 改 resources → Infracost 自动估算月度影响
  2. 季度 FinOps Review:各团队 Owner 对 namespace 成本趋势负责
  3. Namespace 预算 Quota:ResourceQuota 设置 CPU/Memory 上限,超标 Pod 调度失败
  4. 周度成本自动报告:每周一 CronJob 跑,各 namespace 成本发到团队 Slack 频道

实际案例数据($52k → $31k):

优化措施节省投入
清理孤儿 PVC(68 个, 3.8TB)$1,200/月1 天
配置 VPC Endpoint(消除 NAT 流量费)$3,800/月1 天
关停开发环境夜间/周末节点$3,000/月半天
Karpenter Consolidation + Spot$7,000/月1 周
批量按 VPA 推荐降 Requests$6,000/月2 周集中 Sprint
合计$21,000/月

常见措施降本幅度参考(估算,因负载而异):

优化措施预期降本实施复杂度
资源 requests 优化(VPA Recommender)20-40%
Spot 实例(非关键服务)50-70%
节点合并(Karpenter Consolidation)15-25%
定时伸缩(KEDA cron / 关停非工作时段)30-50%(非工作时间)
存储卷降级(gp3 替代 io1、清理孤儿卷)20-40%

子类 7:存储、弹性与安全设计#

题目 1:有状态服务存储方案设计(StatefulSet + StorageClass + PVC 保留策略)#

设计需求: 为一个 3 副本的数据库类有状态服务设计存储方案,要求:每副本独占持久卷、Pod 重建后数据不丢、扩缩容与删除时卷的生命周期可控。

架构与关键设计点:

  1. StorageClass 定义供给策略(动态供给 + 允许扩容 + 拓扑感知):
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com               # 云上用 CSI driver(in-tree 卷插件已迁移到 CSI)
parameters:
  type: gp3
  iops: "6000"
allowVolumeExpansion: true                  # 允许在线扩容(配合 CSI + 文件系统 resize)
volumeBindingMode: WaitForFirstConsumer     # 延迟绑定,保证卷与消费它的 Pod 落在同一 AZ
reclaimPolicy: Retain                       # PV 回收策略:Retain 防误删丢数据
  1. StatefulSet 用 volumeClaimTemplates:每个副本自动生成 data-<sts>-<ordinal> 独占 PVC,Pod 重建后按序号重新绑定同一卷(稳定网络标识 + 稳定存储)。

  2. PVC 保留策略(persistentVolumeClaimRetentionPolicy,1.32 GA)

yaml
spec:
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain    # 删除 StatefulSet 时保留 PVC(数据安全)
    whenScaled: Delete     # 缩容时删除多余副本的 PVC(避免孤儿卷积累成本)

(1.32 之前删除 StatefulSet 会留下孤儿 PVC 需手动清理;GA 后可声明式控制。)

取舍:

  • WaitForFirstConsumer vs Immediate:前者避免"卷在 AZ-a、Pod 被调度到 AZ-b 挂不上",代价是绑定稍慢。跨 AZ 块存储(EBS/云盘)无法 Multi-Attach,必须拓扑对齐。
  • reclaimPolicy: Retain vs Delete:Retain 安全但会留下需人工回收的 Released PV;Delete 省心但误删即丢数据。数据库类一律 Retain。
  • 块存储(RWO、低延迟、独占)vs 文件存储(RWX、可共享、延迟高):数据库选块存储;多 Pod 共享读写才用 CephFS/NFS/EFS。

验证:

  • 删 Pod 后 kubectl get pvc 卷仍在、数据不丢;扩容 PVC 后容器内 df -h 文件系统已增大。
  • 演练 kubectl delete sts --cascade=orphan,验证 PVC 是否按 whenDeleted 策略保留。

治理: 孤儿 PVC / Released PV 纳入周度巡检(见成本治理);StorageClass 分级(fast-ssd / standard / archive),用 ResourceQuota 的 requests.storage 限制各租户用量。


题目 2:弹性伸缩体系设计(HPA v2 + KEDA + VPA + Karpenter 分工)#

设计需求: 一个集群含 Web 服务(按 QPS/CPU 伸缩)、消息消费者(按队列积压伸缩、闲时缩到 0)、Java 常驻服务(内存难估),设计一套完整弹性方案。

四层弹性分工(关键:各管一维,避免打架):

层次组件伸缩对象触发信号
Pod 水平HPA(autoscaling/v2副本数CPU/内存/自定义指标(QPS、P99)
事件驱动KEDA副本数(含 scale-to-zero)队列长度、Kafka lag、cron 等 30+ scaler
Pod 垂直VPArequests/limits历史用量推荐
节点Karpenter / CA节点数与规格待调度 Pod

关键设计点:

  1. HPA v2 支持多指标取 max,结合 behavior 控制扩缩速率(防抖):
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
  minReplicas: 3
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 70 }
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容前观察 5min,避免抖动
  1. KEDA scale-to-zero:消费者闲时缩到 0 副本,来消息时 KEDA 按 activation 阈值拉起(原生 HPA 最小只能到 1,KEDA 补足 0↔1 这一段)。

  2. VPA 与 HPA 不并用于同一资源维度:VPA Auto 模式改 CPU/内存 requests,会与基于 CPU 的 HPA 互相打架(VPA 改 request 直接影响 HPA 的利用率计算)。规避:VPA 只用 Recommender 模式出建议、人工/CI 采纳;或 VPA 管内存、HPA 管 CPU,各行其道。

取舍: 可预测的周期负载(如每天 9 点高峰)用定时扩容(KEDA cron scaler / 预热)比纯响应式 HPA 更平滑;突发流量靠 HPA + 秒级扩节点的 Karpenter。

验证: 压测打到阈值观察副本上涨、kubectl describe hpa 看 metrics 与 events;消息堆积验证 0→N,消费完回落到 0。

治理: maxReplicas 必须有上限,防止指标异常打爆集群;HPA 依赖 metrics-server / Prometheus Adapter,监控其可用性(不可用时 HPA TARGETS 显示 <unknown>、停止伸缩)。


题目 3:集群安全基线设计(RBAC 最小权限 + PSA + Secret 静态加密)#

设计需求: 为生产集群设计安全基线,覆盖:人与服务的最小权限、工作负载的安全准入、敏感数据在 etcd 中的加密。

三层安全设计:

  1. RBAC 最小权限

    • 按 namespace 授 Role/RoleBinding,跨集群只读才用 ClusterRole;禁止随手 cluster-admin
    • ServiceAccount 默认不自动挂 token(automountServiceAccountToken: false),按需显式挂载;用 kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa> 审计实际权限。
    • 特权 verb(escalatebindimpersonate*)单独评审。
  2. PSA(Pod Security Admission,1.25 GA,取代已移除的 PodSecurityPolicy)

yaml
# namespace 打标签即启用三档策略(privileged / baseline / restricted)
metadata:
  labels:
    pod-security.kubernetes.io/enforce: restricted   # 强制拦截
    pod-security.kubernetes.io/audit: restricted     # 审计日志
    pod-security.kubernetes.io/warn: restricted      # 客户端告警
  • restricted 要求 runAsNonRoot、drop ALL capabilities、seccompProfile=RuntimeDefault、禁 hostNetwork/hostPID/privileged。
  • 镜像来源、签名校验等 PSA 覆盖不到的维度,用 Kyverno / OPA Gatekeeper 补充。
  1. Secret 静态加密(默认不加密!)
    • K8s 默认 Secret 在 etcd 中仅 base64 编码,并非加密。需在 API Server 配置 EncryptionConfigurationapiserver.config.k8s.io/v1)手动开启:
yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources: ["secrets"]
    providers:
      - kms:                 # 生产首选 KMS v2(1.29 GA),密钥托管在外部 KMS、支持轮转
          apiVersion: v2
          name: aws-kms
          endpoint: unix:///var/run/kmsplugin/socket.sock
      - identity: {}         # 兜底:允许读取历史未加密数据
  • 开启后需 kubectl get secrets -A -o json | kubectl replace -f - 重写存量 Secret,使其落盘加密。
  • 更进一步:敏感凭据用外部密钥系统(Vault / External Secrets Operator)托管,K8s 内只存引用。

取舍: identity provider 放第一位=不加密;放最后=加密写、兼容读旧数据。KMS v2 比静态 aescbc 密钥更安全(密钥不落配置文件、可轮转),但引入 KMS 依赖(KMS 挂了 API Server 无法解密 Secret)。

验证: 直接从 etcd 读取校验密文:etcdctl get /registry/secrets/<ns>/<name> 应看到 k8s:enc:kms:v2: 前缀而非明文。

治理: 定期轮转 KMS 密钥并重写 Secret;RBAC 与 PSA 策略纳入 GitOps 版本管理;准入策略变更走审计与评审。


附录:面试答题框架#

  1. 方案题回答结构:明确约束条件 → 架构/分层 → 关键设计点(YAML/命令示例)→ 取舍 → 验证 → 治理与风险
  2. 不要直接给方案:先问清楚规模(集群数/服务数/Pod 数)、SLA 要求、已有技术栈、团队规模
  3. 展示取舍意识:每个方案都有代价,能说出"为什么选 A 不选 B"比直接给方案更有说服力
  4. 踩坑意识:补充 1-2 个真实的坑点/注意事项,体现生产经验
  5. 量化思维:成本题和性能题中引用数字(如"合并后可降低 15-25% 节点数")
  6. API 版本要跟上:别用废弃组(autoscaling/v2beta*extensions/v1beta1 Ingress、PSP);新场景优先 Gateway API、PSA、Karpenter v1、KMS v2(详见开头速查)

注:可观测/成本/存储/RBAC/PSA 等的排查型题目见同目录 4-场景排查型.md,本文件只收"方案设计",两者不重复。