Appearance
发布失败时按条件、事件和流量定位
同一条“服务不可用”告警可能来自尚未调度、进程反复退出、升级未完成或转发链断开。先保留 Pod UID、退出原因、Deployment revision 与时间,重建 Pod 后再取日志往往已经失去现场。以下命令都在目标实验 namespace 执行,POD、DEP、SVC 替换成实际名字。
| 症状 | 检查命令与判断依据 | 修改和复验 |
|---|---|---|
| Pending | kubectl describe pod POD 看 PodScheduled=False、FailedScheduling 原文 | 改不可能满足的 request/硬标签;等待绑定,再确认 Ready |
| CrashLoopBackOff | kubectl logs POD --previous 配合 describe 里的 lastState/exitCode | 修启动参数、缺配置或依赖;等 rollout 完成,检查重启数不再增长 |
| OOMKilled | describe 里 terminated.reason 与 limits.memory;kubectl top pod POD 只反映当前采样 | 短时调整限额、对照 heap 排除长期滞留;用相同负载观察多个周期 |
| ImagePullBackOff | Events 的 denied、manifest unknown 或超时指向不同原因 | 核对仓库身份、镜像标签/架构或出网;等新 Pod 拉取成功 |
| Service 不通 | kubectl get endpointslice -l kubernetes.io/service-name=SVC -o yaml,再核对 selector 和端口 | 修后验证实际客户端经 Service 发请求;仅 curl localhost 不能证明链路正常 |
| DNS 错误 | 客户端容器内 cat /etc/resolv.conf,能否解析同 namespace 与带 namespace 的服务名 | 排除搜索域、DNS Service、出站策略;复测同一域名和请求 |
| 控制器停止收敛 | kubectl logs deploy/modeldock-controller --since=10m;看 forbidden、conflict、领导租约和 generation | 修 Role 或对象归属,观测 status;不能只重启进程就算修复 |
Rolling Update 和节点故障为什么要预留余量
maxSurge 决定新旧版本最多能多占多少副本,maxUnavailable 限制更新时允许不可用的数量。GPU 已用满而 surge>0,新副本可能一直 Pending,同时旧副本因可用性约束不能先停。选择预留余量、分批腾挪或允许短时降级,需由服务目标决定。PDB 管经 eviction API 的自愿中断,不能阻止机器断电。节点失联时,Pod 被替换不证明旧设备已停止运算,资源回收见账本补偿。
伸缩不是同一个控制器做完的
HPA 根据指标调整工作负载的期望副本;KEDA 将外部指标暴露给 HPA 并管理激活;Cluster Autoscaler 才能在支持的环境增减节点。Kind 没有云节点池。新增 Pod 卡住时先看指标是否触发,再看 Pod 创建、过滤失败和节点供给。
sh
kubectl -n modeldock-lab get deploy,rs,pods,hpa
kubectl -n modeldock-lab rollout history deploy/chart-demo
kubectl -n modeldock-lab get events --sort-by=.metadata.creationTimestamp
helm -n modeldock-lab history handbook本项目 Deployment 受 ModelService 管理,直接 rollout undo 可能被控制器纠正;应回滚产生 spec 的声明或 chart。练习:把调度实验的两个 Pending 放进表格,先做出不同判断,再核对 Events。
回滚后还有旧 Pod,该判成功还是失败?
滚动发布时旧 Pod 短时存在很正常;只看 Pod 数既不能判断成功,也不能判断泄漏。先确认回滚改变了哪一个声明对象,再比较 Deployment 的 generation 与 observedGeneration、新 revision 的 updatedReplicas 与 availableReplicas。最后用原来的请求身份走一遍网关。若回滚直接写了受 ModelService 管理的 Deployment,下一次 Reconcile 会按照上层声明再改回去。这里真正该回滚的是声明来源。