AI Infra 训练营
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
  • Day 0 · 环境与硬件

    • Day 0 新手现场接管 Runbook:先看懂,再动手
    • Day 0:5 节点裸 Ubuntu → K8s 装机基线
  • Week 1:K8s 内核 + 周边基础设施

    • Day 1:3 CP HA 集群 + CNI 选型 + DNS 调优
    • Day 2:控制面 deep dive + etcd 内核 + chaos drill
    • Day 3:CRD + Operator (kubebuilder 从 0 写)
    • Day 4:Longhorn 存储 + Cilium 二探(Hubble / NetworkPolicy / L7)
    • Day 5:PVC 在线扩容 + K8s 安全基线(RBAC / PSA / Secret 加密 / Kyverno)
    • Day 6:调度策略 + Prometheus / Loki 观测栈
    • Day 7:Harbor 私有镜像 + ArgoCD GitOps + Cilium WireGuard
  • Week 2:制品 + GitOps + AI Infra + 综合

    • Day 8:k3s 单节点 + NVIDIA Device Plugin + vLLM 跑 Qwen2.5-3B
    • Day 8(attempt 1):跨 WAN GPU 加入主集群(失败复盘)
    • Day 8:AlertManager 真接入 + PrometheusRule 实战
    • Day 8:集群内 CI 闭环 — Gitea + Jenkins + Kaniko
    • Day 9:Triton 多框架推理 + DCGM 跨集群可观测 + vLLM 实测
    • Day 10:MIG 硬切片 + AWQ 量化 + HPA Custom Metrics
    • Day 11:AI 业务端到端 —— chainlit + GitOps + 跨 WAN vLLM
    • Day 12:灾难恢复 + 生产事故注入
    • Day 13:LLM Operator + 多集群联邦 + Ambient Mesh + RAG
    • Day 14:CKA / CKS 真题演练 + 14 天技术栈横向汇总

Day 2:控制面 deep dive + etcd 内核 + chaos drill

Day 1 把 5 节点 K8s 集群拉到 Ready,但「Ready」离「敢动」还差一截。Day 2 干三件事:

  • 打开 apiserver 的 audit log,记住每个改过 Secret 的人
  • 把 etcd 的 5 个核心概念(raft / MVCC / compact / defrag / snapshot)逐个跑一遍真实命令
  • 故意把 etcd 杀掉看 K8s 怎么挂、怎么救 —— 包括从 snapshot restore 的灾难恢复演练

整个 Day 2 的隐藏主线是:控制面崩了,数据面(worker 上跑的业务 Pod)会不会跟着崩?这一题的答案直接决定面试里你对 K8s 架构理解的深度。


A. apiserver 启用 audit

kubeadm 拉起来的集群默认不开 audit log,apiserver 既不知道谁删了 Secret,也不知道哪个 SA 在轮询整个集群。生产合规(PCI / SOC2 / HIPAA)这一项必过,自己排查 incident 也得靠它。

A.1 写 audit policy

audit 有 4 个 level,从轻到重:

level记什么用在哪
None什么都不记高频低价值 noise 过滤(configmap / events / leases 的 get/list/watch)
Metadatauser / verb / resource / name / namespace / response code默认级别,最常用
Request上面 + request body改写类操作,但 GET 看不到回参
RequestResponse上面 + response bodySecret 写这种高敏感操作,占盘最大

策略写法是先排除 noise,再单点抬高 Secret 的级别,最后全局兜底 Metadata:

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages: ["RequestReceived"]   # 只记 ResponseStarted/Complete,省一半行数
rules:
# 1. 高频低价值 noise 不记
- level: None
  resources:
  - group: ""
    resources: ["configmaps", "endpoints", "events"]
  - group: "coordination.k8s.io"
    resources: ["leases"]
  verbs: ["get", "list", "watch"]

# 2. 系统 SA 的自查不记
- level: None
  users: ["system:kube-proxy", "system:kube-scheduler", "system:kube-controller-manager"]
  verbs: ["get", "list", "watch"]

# 3. Secret 写操作 full RequestResponse(含 body)
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets"]
  verbs: ["create", "update", "patch", "delete"]

# 4. 兜底 Metadata
- level: Metadata

A.2 patch apiserver static pod manifest

apiserver 是 static pod,配置文件在 /etc/kubernetes/manifests/kube-apiserver.yaml。加 4 个 flag + 1 个 hostPath volume mount:

spec:
  containers:
  - command:
    - kube-apiserver
    # ... 原有 flag
    - --audit-policy-file=/etc/kubernetes/audit-policy.yaml
    - --audit-log-path=/var/log/kubernetes/audit.log
    - --audit-log-maxage=7        # 保留 7 天
    - --audit-log-maxbackup=3     # rotate 3 个
    - --audit-log-maxsize=100     # 单文件 100MB 切
    volumeMounts:
    - mountPath: /etc/kubernetes/audit-policy.yaml
      name: audit-policy
      readOnly: true
    - mountPath: /var/log/kubernetes
      name: audit-log
  volumes:
  - hostPath:
      path: /etc/kubernetes/audit-policy.yaml
      type: File
    name: audit-policy
  - hostPath:
      path: /var/log/kubernetes
      type: DirectoryOrCreate
    name: audit-log

改完 不需要 systemctl restart kubelet。kubelet inotify-watch 着 /etc/kubernetes/manifests/ 目录,文件修改 ~10s 内自动 reconcile 重起 apiserver pod。

A.3 为什么这么写

决策不做的后果
omitStages 排掉 RequestReceived每个请求两条日志(接收 + 完成),盘量翻倍
configmap/event/lease 的 get/list/watch 不记controller-manager / kubelet 每秒几十次轮询,单机几小时就上 GB
Secret 写 RequestResponse 含 body不记 body 出事时只知道「有人改过」,不知道改成了什么
log rotate 100MB × 3 + 7 天audit.log 长成几十 GB 把 /var 撑爆,整个节点 NotReady
--audit-log-maxsize 是单位 MB 不是 byte写 100 = 100MB,写 100000000 当字面值用反而立刻切

真坑:system:anonymous 高频 get 暴露 anonymous auth 默认开

audit.log 滚起来后 grep 关键字:

jq -r 'select(.user.username == "system:anonymous") | .verb + " " + .objectRef.resource' \
  /var/log/kubernetes/audit.log | sort | uniq -c | sort -rn | head

输出有几百行 get healthz、get readyz 来自 system:anonymous:HAProxy 健康检查、Cilium operator probe 都没带 token,K8s 默认开 anonymous auth,把这些请求当匿名用户放行。

不算严重漏洞但属于潜在隐患 —— anonymous 在某些版本能列到 /api discovery 信息。生产关掉:

- --anonymous-auth=false

关之前先把 HAProxy 健康检查改成带 token 的,否则 LB 把 apiserver 全标 unhealthy。教训:

  1. kubeadm 默认不开 audit + 默认开 anonymous auth,两条都是面试常问的「默认值不安全」题
  2. 改 static pod manifest 后不要 restart kubelet,kubelet 自动 reconcile;手动 restart 反而让 apiserver 冷启动多停 30 秒
  3. 生产 audit 进阶:fluent-bit 把 audit.log 转发到 Elasticsearch / Splunk 做长期查询,本地落盘只 short retention(盘量 / IO 都顶不住几年)
  4. 高 QPS 集群下 audit 写盘吃 IO 5-10%,audit 盘单独挂 SSD,不要跟 etcd 抢

B. etcd 内核 5 概念

etcd 是 K8s 唯一的真实状态存储,理解它就等于理解了 K8s 的 ACID 边界。这一段把 5 个核心概念逐个跑一遍真命令。

先把 etcdctl 别名定下,下面所有命令都用它:

ETCDCTL='kubectl -n kube-system exec etcd-k8s-cp-1 -- etcdctl
  --cacert=/etc/kubernetes/pki/etcd/ca.crt
  --cert=/etc/kubernetes/pki/etcd/server.crt
  --key=/etc/kubernetes/pki/etcd/server.key
  --endpoints=https://127.0.0.1:2379'

B.1 raft:谁是 leader,term 多少

$ETCDCTL endpoint status --cluster -w table
$ETCDCTL member list -w table

输出:

| ENDPOINT     | ID    | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
| cp-1:2379    | e4dd  | 12 MB   | false     | 23        | 156162     |
| cp-2:2379    | c144  | 12 MB   | false     | 23        | 156162     |
| cp-3:2379    | 953b  | 12 MB   | true      | 23        | 156162     |

记住 3 件事:

  • quorum = N/2 + 1。3 节点 quorum=2,容忍 1 故障;5 节点 quorum=3,容忍 2;7 节点 quorum=4,容忍 3
  • leader 接所有写,follower 同步。读默认也走 leader(linearizable read),可以加 --consistency=s 退到 serializable read 直接从本地 follower 读
  • term 在每次选举时 +1,是判断「这之间发生过 leader 变更」的最直接信号

raft 选主关键 timeout(etcd 默认值):

参数默认含义
heartbeat-interval100msleader 发心跳间隔
election-timeout1000msfollower 多久收不到心跳就发起选举

这就是 Day 0 装 chrony 的原因:节点间时差 > 1s,follower 误判 leader 失联反复选主,集群整天不稳定。

B.2 MVCC:每次写都产生新 revision

etcd 不覆盖写,每个 key 的每次修改产生一个新 revision,revision 是 cluster-wide 单调递增 int64。

# 当前 revision
$ETCDCTL endpoint status -w json | jq '.[0].Status.header.revision'
# 126876

# 看某个 key 的所有历史 revision
$ETCDCTL get /registry/configmaps/default/foo --rev=126800 --keys-only

K8s 把 etcd revision 直接当 resourceVersion 用:

  • kubectl get pods --watch 拿到 resourceVersion=126876
  • watch 中断 → 用这个 rv 重连 → etcd 从 rev 126877 开始重放变更
  • 这就是 K8s informer / list-watch 一致性的内核来源

B.3 compact:删历史,逻辑空间释放

历史 revision 不清理,DB 会无限涨。kube-apiserver 默认每 5 分钟跑一次 auto-compact(--etcd-compaction-interval=5m),手动跑:

CURRENT_REV=$($ETCDCTL endpoint status -w json | jq -r '.[0].Status.header.revision')
$ETCDCTL compact $CURRENT_REV
# compacted revision 126876

效果:删 rev 126876 之前的所有历史版本,释放 ~90% logical 空间。但 du 看磁盘文件没变 —— BoltDB 只是内部标记为 free,不还盘。

B.4 defrag:物理重组,把盘真的还回去

# 看 logical vs physical
$ETCDCTL endpoint status --cluster -w table
# DB SIZE 12 MB ← 物理文件
# DB SIZE IN USE 2.1 MB ← compact 后逻辑占用

$ETCDCTL defrag --cluster
# Finished defragmenting etcd member[https://10.0.24.31:2379]
# Finished defragmenting etcd member[https://10.0.24.29:2379]
# Finished defragmenting etcd member[https://10.0.24.32:2379]

实测物理回收 ~30%(12MB → 8MB)。

defrag 是阻塞操作:单个 member 期间不响应读写,3 节点集群被串行处理,每节点 1-3s(大集群可能 1-5 分钟)。期间 raft 可能把 leader 切走。

操作影响何时跑
compact删 logical history,不阻塞,不还盘apiserver 自动跑,无需关心
defrag物理重组文件,阻塞写,还盘手动 / cron 错峰,一次一个 member

记住口诀:先 compact 再 defrag 才有用。defrag 不会去清还没 compact 掉的 history。

B.5 snapshot save:冷备

$ETCDCTL snapshot save /var/lib/etcd/snapshot-day2.db
$ETCDCTL snapshot status /var/lib/etcd/snapshot-day2.db -w table
# | HASH     | REVISION | TOTAL KEYS | TOTAL SIZE |
# | ae0dc55f | 126876   | 521        | 2.1 MB     |

snapshot save 在 line consistency 下导出整个 keyspace,在 leader 上跑最快(避免 cross-node 流量)。落地一份 + scp 到本地一份,restore 时用。

生产实践:cron 每天 + 异地存储(S3 / OSS),跟集群 etcd 数据完全解耦的物理位置。

真坑:etcd db 默认上限 2GB,超了拒写

$ETCDCTL endpoint status --cluster -w table
# 某个 member DB SIZE: 1.9 GB ← 接近上限

--quota-backend-bytes 默认 2GB。超了之后 etcd 进入 alarm: NOSPACE 状态,拒所有写,apiserver 全集群只读。kubectl 报:

etcdserver: mvcc: database space exceeded

排查:

$ETCDCTL alarm list
# memberID:e4dd alarm:NOSPACE

修复:

# 1. 强制 compact 到当前 rev
CUR=$($ETCDCTL endpoint status -w json | jq -r '.[0].Status.header.revision')
$ETCDCTL compact $CUR

# 2. defrag 物理回收
$ETCDCTL defrag --cluster

# 3. 解除 alarm
$ETCDCTL alarm disarm

教训:

  1. 大集群(>500 节点 / 万级 Pod)必须把 --quota-backend-bytes 调到 8GB,同时把 --etcd-compaction-interval 调短(默认 5m,可以 2m)
  2. K8s Event 资源是 etcd 大户(大量短命 event 频繁写),生产建议把 event 分流到独立 etcd 集群(--etcd-servers-overrides=/events#...)
  3. 监控必加 etcd db_size 指标,到 80% 报警,不要等到 NOSPACE 才发现

C. chaos drill:杀 etcd 看集群怎么挂、怎么救

kubeadm 的 etcd 是 stacked 模式(etcd 跟 apiserver 同节点跑 static pod)。杀 etcd 的姿势就是把 manifest 文件移走:

# kubelet 10s 内检测到 manifest 不见,停 pod
mv /etc/kubernetes/manifests/etcd.yaml /root/etcd.bak

# 恢复
mv /root/etcd.bak /etc/kubernetes/manifests/etcd.yaml

这比 systemd 单元的 stop 更干净 —— kubelet 完全不知道你想干啥,按 manifest 状态 reconcile。

C.1 三阶段演练

阶段动作etcd upquorumapiserver 行为
0baseline3/3OKkubectl 正常
1kill cp-1 etcd2/3OK(2 ≥ 2)kubectl 仍正常
2再 kill cp-2 etcd1/3LOSS(1 < 2)kubectl get nodes → etcdserver: request timed out
3恢复 cp-1 + cp-23/3OKkubectl 全恢复,raft term +1

阶段 2 的关键观察:

kubectl get nodes
# Error: etcdserver: request timed out

# 但 worker 上业务 Pod 完全正常
kubectl exec -it test-pod -- ps  # 这条 exec 会卡(要经过 apiserver)
ssh m4 'crictl ps'                # 但直接到节点看,Pod 全在跑

这就是 K8s 控制面 vs 数据面解耦:

  • 控制面挂(apiserver 拒写)= 不能调度新 Pod、不能 kubectl 操作、controller 不能 reconcile
  • 数据面(业务 Pod 流量)完全不受影响,因为 kubelet 本地缓存了 Pod spec,CNI / kube-proxy 的 dataplane 也在节点本地

阶段 3 恢复后 raft term: 24(baseline 是 23),+1 是因为期间没 leader 触发了一次重选。

真坑:quorum loss 时千万别 force-new-cluster

阶段 2 quorum loss 时,新手第一反应是「赶紧把单节点改成 force-new-cluster 救起来」。别这么做。

正确处理顺序:

  1. 先尝试恢复 etcd member:重启 pod / 修网络 / 把 manifest 移回来
  2. 真的全恢复不了 → 才走 snapshot restore 灾难恢复流程
  3. 期间 apiserver 写 unavailable 但 worker 上的 Pod 继续跑,业务流量不受影响

如果直接 force-new-cluster 把单节点跑起来当新 cluster,等其他 member 网络恢复回来,会出现两个独立的 etcd cluster 互相不认 —— split-brain 数据分叉,比 quorum loss 还难救。

C.2 灾难恢复:3 个 etcd 全挂,从 snapshot restore

最坏情况:3 节点 etcd 数据目录全损坏(盘炸 / 误删 / ransomware)。流程:

# 1. 在某节点 etcdctl snapshot restore(生成新 data dir)
etcdctl snapshot restore /backup/snapshot-day2.db \
  --name k8s-cp-1 \
  --initial-cluster k8s-cp-1=https://10.0.24.31:2380 \
  --initial-advertise-peer-urls https://10.0.24.31:2380 \
  --data-dir /var/lib/etcd-restored

# 2. 改 etcd manifest 指向新 data dir + 单节点 initial-cluster
#    /etc/kubernetes/manifests/etcd.yaml 里改两处:
#      --data-dir=/var/lib/etcd-restored
#      --initial-cluster=k8s-cp-1=https://10.0.24.31:2380

# 3. 把 hostPath volume 挂到 /var/lib/etcd-restored

# 4. kubelet reconcile 起单节点 etcd,验证 apiserver 能连
kubectl get nodes  # 应该能拉到 snapshot 里的所有 node 信息

# 5. 加 cp-2 / cp-3 作为新 member
etcdctl member add k8s-cp-2 --peer-urls=https://10.0.24.29:2380
# 然后在 cp-2 上跑同样的 manifest 调整,带 --initial-cluster-state=existing

这个流程的关键是「单节点 restore → 验证 → 再加 member」,不要试图一次 restore 出 3 节点 cluster。

snapshot save/restore vs etcd member remove 的边界

场景用什么
1 个 member 数据坏了,其他 2 个 OKetcdctl member remove + 重新 add,从 leader 同步
1 个 member ghost / unstarted 状态etcdctl member remove 清掉 ghost
2 个以上 member 数据坏了,quorum loss 且救不回来snapshot restore + 重建 cluster
整个 etcd 数据被误删 / ransomwaresnapshot restore,没其他路

记住边界:有 quorum 时永远不用 snapshot restore,损失 snapshot 到现在之间的所有变更。

Lesson

  1. kubeadm + static pod 让杀 etcd 极简:移走 manifest 就行,不像 systemd 要 stop。面试常问「K8s static pod 是什么」→ kubelet 直接管理、不通过 apiserver、manifest 在 /etc/kubernetes/manifests/、kubelet inotify watch 这个目录
  2. 3 节点 etcd 是真 HA 起步:容忍 1 失败 + 留运维空间(滚动升级一台一台来)。5 节点容忍 2 但同步开销大、写延迟变高,不是默认推荐
  3. 数据面不依赖 etcd:worker 上的 Pod 在 control plane 全挂时继续跑,这是 K8s 设计的精髓和面试金句
  4. snapshot save 必须冷备:跟集群完全解耦的物理位置(S3 / OSS / 异地)。snapshot 跟 etcd 在同一台机器等于没备份

面试常见题

Q1:apiserver / etcd / kubelet 启动顺序是什么?谁依赖谁?

stacked 模式的启动链:

  1. kubelet 是 systemd 服务,先起。它扫 /etc/kubernetes/manifests/ 发现 4 个 static pod manifest
  2. 拉起 etcd static pod(先于 apiserver,因为 apiserver 启动要连 etcd)
  3. 拉起 apiserver static pod,apiserver --etcd-servers=https://127.0.0.1:2379,连本机 etcd
  4. 拉起 controller-manager + scheduler(这两个连 apiserver,不直连 etcd)

故事性追问:为什么 health probe 失败重启 apiserver 不影响 etcd? —— static pod 互相独立,apiserver crash kubelet 只重起 apiserver,etcd pod 不动。这是 stacked 模式抗故障的关键设计。

Q2:etcd raft 选主 timeout 默认多少?为什么 K8s 节点必须装 chrony?

  • heartbeat-interval 默认 100ms,leader 给 follower 发心跳的间隔
  • election-timeout 默认 1000ms(1s),follower 多久收不到心跳就发起选举

节点之间时差 > election-timeout,follower 会误判 leader 失联触发重新选主。生产见过节点时间漂移 5 秒导致 etcd 反复选主、apiserver 几小时不稳定。chrony 是 Day 0 装机第一天就装好不能省的原因。

故事性追问:为什么不用 systemd-timesyncd? —— 只支持 SNTP 无 drift 校准,VM 时间易漂移环境不稳。

Q3:MVCC、compact、defrag 是什么关系?

三层:

概念干啥阻塞?还盘?
MVCC每次写产生新 revision,不覆盖否—
compact删某 rev 之前所有历史,释放 logical 空间否否(BoltDB 内部 free)
defrag物理重组 BoltDB 文件是,单 member 1-5min是

口诀:先 compact 再 defrag 才有用。defrag --cluster 串行处理 3 个 member,每次 raft 可能切 leader。

故事性追问:etcd db 涨到 2GB 怎么救? —— alarm list 看到 NOSPACE → compact 到当前 rev → defrag → alarm disarm 解锁写。生产把 quota 调到 8GB + event 分流到独立 etcd。

Q4:3 个 etcd 全挂了怎么救?K8s 集群数据丢吗?

如果有 snapshot:

  1. etcdctl snapshot restore 到新 data dir,单节点 --initial-cluster
  2. 改 etcd manifest 指新 data dir,kubelet 拉起单节点 etcd
  3. apiserver 连上验证 kubectl get nodes 拉得到 snapshot 里的状态
  4. etcdctl member add 把 cp-2 / cp-3 加回来,从 leader sync
  5. 数据只丢 snapshot 到挂前之间的写,业务 Pod 完全不受影响(kubelet 缓存 spec 继续跑)

如果没 snapshot:完蛋,整个 K8s 状态丢失,要从头 kubeadm init。所以 snapshot save 是 K8s 运维第一公民,cron 每天 + 异地存储不可省。

故事性追问:quorum loss 时能不能 force-new-cluster 救起来? —— 千万不要。其他 member 网络恢复后会形成两个独立 cluster,split-brain 比 quorum loss 还难救。正确顺序是先尝试恢复 member,真的救不回来再走 snapshot restore。

Q5:K8s 控制面全挂,业务 Pod 会挂吗?

不会。这是 K8s 设计的精髓:

  • 控制面(apiserver / controller-manager / scheduler / etcd)挂 → 不能调度新 Pod、不能 kubectl 操作、controller 不 reconcile
  • 数据面(业务 Pod 流量)完全不受影响:
    • kubelet 本地缓存 Pod spec,按缓存继续保活
    • CNI dataplane(Cilium eBPF / Calico iptables)在节点本地,不查 apiserver
    • kube-proxy 维护的 Service rule 已经下发到节点 iptables/ipvs,新的 Service 改不了但旧的还在工作

故事性追问:那 chaos 时 kubectl exec 进 Pod 看为什么会卡? —— 因为 exec 要经过 apiserver 中转,apiserver 挂了 exec 通道断了。直接 ssh 到节点 crictl exec 进容器看,业务进程全在跑。这是区分「Pod 真挂了」vs「只是看不见」的关键。


下一步

Day 2 结束后集群多了 3 件事:apiserver 写入了 audit 链路、etcd 5 个核心命令都跑过真数据、snapshot 在异地存了一份且演练过 restore 流程。下一步进 Day 3 看调度器:scheduler 怎么选节点、taint/toleration / nodeAffinity / topologySpreadConstraints 各自的边界,以及 descheduler 怎么处理「调度结果过时」的问题。

在 GitHub 上编辑此页
Prev
Day 1:3 CP HA 集群 + CNI 选型 + DNS 调优
Next
Day 3:CRD + Operator (kubebuilder 从 0 写)