这是两个月前公司的图片AI训练模型集群出现的一个生产问题,是这样的:
well-known, Python项目因为GIL普遍使用多进程代替多线程,使得container中存在1号进程之外的其他进程。
- 算法组的同学曾在群里反馈模型服务并没有问题,但多次跑出来的数据有缺失
- 开始运维方任务是算法代码问题,并没有在意,但随手发现相关的Pod内存曲线有断崖下降并且没有再回升
- 直觉告诉内部有进程挂了,在算法同学允许下重跑了一边服务,ps aux命令观察了一下果然若干小时候被强退,预计OOMKilled了
- 但主要问题是,监控系统并没有抓取到这一事件,无法发出OOMKilled告警
一、container以及Pod的状态
1. container的异常指标
总所周知,这个异常指标可以用过kube-state-metrics获得
kube_pod_container_status_terminated_reason{ container="nginx", namespace="default", node="xxxx", pod="nginx-dep-123", reason="OOMKilled", service="kube-state-metrics"}
解读一下:意思是pod nginx-dep-123中的某个容器 nginx 的状态是terminated,并且它进入terminated状态的reason原因是因为OOMKilled
值得注意的是,kubectl get展示的status即可能是容器也可能是pod的状态。
具体可以参考这两个官方文档容器状态和Pod阶段
容器状态只有三种:
- Waiting(等待)处于Waiting状态的容器仍在运行它完成启动所需要的操作:例如从某个容器镜像仓库拉取容器镜像,或者向容器应用Secret数据等等
- Running(运行中) 状态表明容器正在执行状态并且没有问题发生
- Terminated(已终止) 处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。
kubectl get
打印的源码可以在kubernetes\pkg\printers\internalversion\printers.go这里看printPod()
方法
2. containerd如何获取容器状态的
我们都知道的Pod状态均来自于CRI,kubelet的pleg会通过cri接口获取containerd的状态信息,pleg是个大坑回头有精力可以讲。
可以直接定位到pod.Status.Reason获取的位置kubernetes\pkg\kubelet\pleg\generic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| func (g *GenericPLEG) updateCache(ctx context.Context, pod *kubecontainer.Pod, pid types.UID) (error, bool) {
if pod == nil {
klog.V(4).InfoS("PLEG: Delete status for pod", "podUID", string(pid))
g.cache.Delete(pid)
return nil, true
}
g.podCacheMutex.Lock()
defer g.podCacheMutex.Unlock()
timestamp := g.clock.Now()
// 这里是pleg的非常重的逻辑就不展开了
// 1. 用m.runtimeService.PodSandboxStatus获取sandbox的网络容器状态
// 2. 再通过m.getPodContainerStatuses(uid, name, namespace)获取业务容器状态
// a. 这里回去调用对应的CRI GRPC接口,即(r *remoteRuntimeService) ContainerStatus(containerID string)
// 3. 最后拼装为&kubecontainer.PodStatus
status, err := g.runtime.GetPodStatus(ctx, pod.ID, pod.Name, pod.Namespace)
if err != nil {
} else {
// ...
status.IPs = g.getPodIPs(pid, status)
}
// ...
return err, g.cache.Set(pod.ID, status, err, timestamp)
}
|