先弄坏,再修好
目标
亲手制造并修复实际工作中最常遇到的五类故障,在实践中掌握从症状逐步定位根因的排查顺序。
为什么重要
故障排查占 CKA 分值的 30%,是占比最大的领域。但仅仅查看已经修复好的结果无法真正学会排障。因此,本实验按照由学员制造故障状态、将症状保存到文件,然后再进行修复的顺序设计。每一步的评分不仅检查修复后的结果,还会同时检查故障确实曾经存在的证据。
养成记录症状的习惯本身就是一项实务技能。故障结束后,证据就会消失。若要在之后说明根因,必须保留故障发生当时的事件和状态。
前面步骤中形成的集群状态(已 cordon 的节点、带污点的节点)会一直保留到后续步骤。最后一题需要准确记住这些状态才能完成。
步骤
- 创建命名空间
cka-broken,并创建 Deploymentweb(副本数 2),使用镜像nginx:1.99-nonexistent。将能看到该错误镜像标签的输出保存到/root/cka-broken/bad-image.txt,然后把镜像替换为nginx:1.27,使其达到 2/2 Ready。不要删除 Deployment,只修复镜像。 - 创建 Pod
heavy(镜像nginx:1.27),将 requests 设为cpu: 500、memory: 2000Gi。确认它进入 Pending,并将包含原因的输出保存到/root/cka-broken/pending.txt。保留heavy,不要删除;再创建 Deploymentheavy-fixed(副本数 1、镜像nginx:1.27、requests 为cpu: 500m、memory: 2000Mi),使其达到 1/1 Ready。 - 创建 Service
api-svc(选择器app=api,端口 80),再创建 Deploymentapi,并故意将 Pod 标签和选择器错误地设为app=api-v2。把api-svc端点为空的状态保存到/root/cka-broken/svc-before.txt,然后将api修正为标签app=api,使 2 个副本均达到 Ready。Service 的选择器保持app=api不变。 - 创建命名空间
cka-broken-quota,并创建 ResourceQuotacka-quota,设置为pods: "2"、requests.cpu: "1"。创建 Deploymentq-app(副本数 4、镜像nginx:1.27、requests 为cpu: 200m)后,只会有部分 Pod 启动。将显示exceeded quota的事件保存到/root/cka-broken/quota.txt,然后把配额的pods提高到5,使其达到 4/4 Ready。 - 在
cka-broken中创建 Deploymentcritical(副本数 2、镜像nginx:1.27、Pod 标签app=critical)和 PDBcritical-pdb(选择器app=critical、minAvailable: 2)。尝试 drainlab-node-2,将阻止操作的消息保存到/root/cka-broken/pdb.txt;然后把minAvailable降为1,对lab-node-2执行 cordon + drain,将其完全清空。 - 为
lab-node-0添加标签disktype=ssd和污点maintenance=true:NoSchedule。创建 Podneeds-toleration(镜像nginx:1.27、nodeSelector 为disktype=ssd、无容忍),确认其处于 Pending,并将原因保存到/root/cka-broken/taint.txt。保留needs-toleration,再创建 Podneeds-toleration-fixed,使用相同的 nodeSelector 并添加容忍,将其调度到lab-node-0。 - 创建 Pod
data-app(镜像nginx:1.27),使其将 PVCapp-data挂载到/data。此时 PVC 尚不存在,将 Pod 无法启动的原因保存到/root/cka-broken/pvc.txt;然后创建 PVcka-fix-pv(1Gi、RWO、storageClassNamecka-fix、hostPath/mnt/cka-fix)和 PVCapp-data(1Gi、RWO、cka-fix),使其变为 Bound,并让data-app进入 Running。 - 创建 Deployment
recovered(副本数 4、镜像nginx:1.27、Pod 标签app=recovered),将其部署到cka-broken中。requests 设置为cpu: 100m、memory: 128Mi,添加maintenance=true:NoSchedule容忍;topologySpreadConstraints 设置为 maxSkew 1 / topologyKeykubernetes.io/hostname/ whenUnsatisfiableScheduleAnyway/ labelSelectorapp=recovered。使其达到 4/4 Ready,并把已修复的五类问题整理到/root/cka-broken/summary.md。该文件必须包含image、taint、selector、quota、pdb这五个词。
参考
- 调度失败的原因位于
kubectl describe pod <이름> -n cka-broken输出的 Events 部分。 - 超出配额的信息不会出现在 Pod 上,而会显示在
kubectl describe rs或kubectl get events -n cka-broken-quota中。 - 执行 drain 时添加
--ignore-daemonsets --delete-emptydir-data --force --timeout=60s会更顺利。 - 常见错误 1:还没保存证据文件就先修复了问题。操作顺序本身就是评分项。
- 常见错误 2:在第 8 步忘记添加容忍。
lab-node-2已被 cordon,lab-node-0带有污点,因此可用节点只剩一个。
错误的镜像标签
创建命名空间 cka-broken,并创建 Deployment web(副本数 2),使用镜像 nginx:1.99-nonexistent。将能看到该错误镜像标签的输出保存到 /root/cka-broken/bad-image.txt,然后把镜像替换为 nginx:1.27,使其达到 2/2 Ready。不要删除 Deployment,只修复镜像。
先使用错误标签创建资源并留下证据,然后只替换镜像。如果删除并重新创建 Deployment,故障版本记录会消失,评分将无法通过。
资源请求单位错误
创建 Pod heavy(镜像 nginx:1.27),将 requests 设为 cpu: 500、memory: 2000Gi。确认它进入 Pending,并将包含原因的输出保存到 /root/cka-broken/pending.txt。保留 heavy,不要删除;再创建 Deployment heavy-fixed(副本数 1、镜像 nginx:1.27、requests 为 cpu: 500m、memory: 2000Mi),使其达到 1/1 Ready。
cpu 值中漏写 m 时,单位就不是毫核,而是核。describe 输出的 Events 部分会原样说明调度器失败的原因。
Service 与标签不匹配的 Deployment
创建 Service api-svc(选择器 app=api,端口 80),再创建 Deployment api,并故意将 Pod 标签和选择器错误地设为 app=api-v2。把 api-svc 端点为空的状态保存到 /root/cka-broken/svc-before.txt,然后将 api 修正为标签 app=api,使 2 个副本均达到 Ready。Service 的选择器保持 app=api 不变。
Deployment 的 spec.selector 不可变。如果最初创建错误,就必须重新创建,而不能直接修改。不要改动 Service 一侧的选择器。
超出 ResourceQuota
创建命名空间 cka-broken-quota,并创建 ResourceQuota cka-quota,设置为 pods: "2"、requests.cpu: "1"。创建 Deployment q-app(副本数 4、镜像 nginx:1.27、requests 为 cpu: 200m)后,只会有部分 Pod 启动。将显示 exceeded quota 的事件保存到 /root/cka-broken/quota.txt,然后把配额的 pods 提高到 5,使其达到 4/4 Ready。
受配额限制的 Pod 会以 ReplicaSet 事件的形式出现,而不是 Pod 事件。提高配额之前,先保存该事件。
被 PDB 阻止的 drain
在 cka-broken 中创建 Deployment critical(副本数 2、镜像 nginx:1.27、Pod 标签 app=critical)和 PDB critical-pdb(选择器 app=critical、minAvailable: 2)。尝试 drain lab-node-2,将阻止操作的消息保存到 /root/cka-broken/pdb.txt;然后把 minAvailable 降为 1,对 lab-node-2 执行 cordon + drain,将其完全清空。
当副本数为 2 且 minAvailable 为 2 时,一个 Pod 也无法驱逐。不要用 --force 强行执行,而应重新计算 PDB 要保护的可用数量。
缺少容忍
为 lab-node-0 添加标签 disktype=ssd 和污点 maintenance=true:NoSchedule。创建 Pod needs-toleration(镜像 nginx:1.27、nodeSelector 为 disktype=ssd、无容忍),确认其处于 Pending,并将原因保存到 /root/cka-broken/taint.txt。保留 needs-toleration,再创建 Pod needs-toleration-fixed,使用相同的 nodeSelector 并添加容忍,将其调度到 lab-node-0。
NoSchedule 污点只会阻止新 Pod,不会影响已经运行的 Pod。不要删除故障 Pod,请将其保留下来。
不存在的 PVC
创建 Pod data-app(镜像 nginx:1.27),使其将 PVC app-data 挂载到 /data。此时 PVC 尚不存在,将 Pod 无法启动的原因保存到 /root/cka-broken/pvc.txt;然后创建 PV cka-fix-pv(1Gi、RWO、storageClassName cka-fix、hostPath /mnt/cka-fix)和 PVC app-data(1Gi、RWO、cka-fix),使其变为 Bound,并让 data-app 进入 Running。
先创建 Pod 并确认失败,再创建卷。PVC 绑定后,调度器会重新尝试调度该 Pod,稍等片刻即可。
综合:在保留现状的集群中部署恢复后的应用
创建 Deployment recovered(副本数 4、镜像 nginx:1.27、Pod 标签 app=recovered),将其部署到 cka-broken 中。requests 设置为 cpu: 100m、memory: 128Mi,添加 maintenance=true:NoSchedule 容忍;topologySpreadConstraints 设置为 maxSkew 1 / topologyKey kubernetes.io/hostname / whenUnsatisfiable ScheduleAnyway / labelSelector app=recovered。使其达到 4/4 Ready,并把已修复的五类问题整理到 /root/cka-broken/summary.md。该文件必须包含 image、taint、selector、quota、pdb 这五个词。
当前集群中分别有一个已 cordon 的节点和一个带污点的节点。先判断若要使用其中某个节点需要满足什么条件,再进行部署。