问题现象
kubernetes集群中,发生部分pod应用不可用的告警
问题排查
基于这种情况,根据经验判断,怀疑是对应的某个节点出现问题。
-
找到其中一个pod,kubectl get pod -o wide|grep pod-xxx 查看其在哪个节点上
-
通过kubectl describe node xxxx 查看该node上的信息,发现该节点上的pod都出现上在了不可用的应用清单中。另外还观察到了一条warning信息
- 通过其ip地址,登录服务器,发现已经无法登录了。
- 查看node节点监控,看能否发现一些端倪。监控数据却没有异常。初步确认是底层服务器问题,赶紧反馈给云厂商。
- 排查影响范围,通过kubectl get node -o wide ,发现一个很奇怪的现象,node节点处于ready状态,但是os-image字段显示unknow状态
- 将其unknow状态的节点逐一测试,发现都无法登录。
其实问题通过上面一顿操作,可以得到一个基本结论,出现了unknown状态的node存在问题,导致该节点上的pod都不可用。具体原因还要看云厂商给出结论。从目前得到的信息推断应该是物理机磁盘出现问题,导致文件系统io出现错误。所以后面的分析也是基于这个结论去分析的。
事情到这里,我们还是有些问题要去反思的。
- 服务器上的pod都不可用了,且服务器也无法登录了,而k8s的出问题的node节点为什么状态还是Ready?
- 服务器不可用了,监控为什么还是正常的?
- 问题节点的os-image的信息为什么是unknown的状态?
问题解惑
要弄清上面的问题,我们要先看下kubelet的状态上报机制是怎样的。或许能够解答第一个和第三个问题。
kubelet的状态上报机制
在 v1.13 之前的版本中,节点的心跳只有 NodeStatus,从 v1.13 开始,NodeLease feature 作为 alpha 特性引入。当启用 NodeLease feature 时,每个节点在“kube-node-lease”名称空间中都有一个关联的“Lease”对象,该对象由节点定期更新,NodeStatus 和 NodeLease 都被视为来自节点的心跳。NodeLease 会频繁更新,而只有在 NodeStatus 发生改变或者超过了一定时间(默认值为1分钟,node-monitor-grace-period 的默认值为 40s),才会将 NodeStatus 上报给 master。由于 NodeLease 比 NodeStatus 更轻量级,该特性在集群规模扩展性和性能上有明显提升。
上传信息
状态的信息的心跳我么依靠nodelease来实现,减少apiserver的压力。其上传的信息相对于node的信息少很多,比较轻量级。
// kubernetes/pkg/kubelet/kubelet.go
func (kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate) {
...
if kl.kubeClient != nil {
// Start syncing node status immediately, this may set up things the runtime needs to run.
// 通过node的状态信息
go wait.Until(kl.syncNodeStatus, kl.nodeStatusUpdateFrequency, wait.NeverStop)
// 更新node的缓存信息
go kl.fastStatusUpdateOnce()
// start syncing lease
// 开启同步lease信息
go kl.nodeLeaseController.Run(wait.NeverStop)
}
...
}
NodeLease
通过一下代码我们可以看到,只是上传一个很简单数据。
// retryUpdateLease attempts to update the lease for maxUpdateRetries,
// call this once you're sure the lease has been created
func (c *controller) retryUpdateLease(base *coordinationv1.Lease) error {
// 上传重试机制
for i := 0; i < maxUpdateRetries; i++ {
// 生成新的lease
leaseToUpdate, _ := c.newLease(base)
// 更新apiserver的信息
lease, err := c.leaseClient.Update(context.TODO(), leaseToUpdate, metav1.UpdateOptions{
<