k8s-[排查记录]解决节点无法查看pod日志

解决k8s某节点无法查看pod日志问题

问题描述

生产环境:

  • k8s版本:v1.17.9
  • 集群:三台master,一台worker,使用kubeadm部署

问题现象:

master执行 kubectl logs 出现下面错误:

error: You must be logged in to the server (the server has asked for the client to provide credentials (pods/log xxx))

通过k8sClient请求apiserver /api/v1/namespaces/{namespace}/pods/{name}/log 时,同样不行。

但是执行 kubectl get pods 或者 请求 GET /api/v1/namespaces/{namespace}/pods 能正常返回结果。

换个节点,在master2上执行 kubectl logs ,能正常返回。

排查过程

首先盲猜大概率就是该节点证书的问题。

但不久前集群证书已经通过 kubeadm alpha certs renew all 更新过了,再次通过 kubeadm alpha certs check-expiration 查看证书日志,是没问题的。

难道是该节点的kubectl config没更新,于是在出错节点更新config cp -f /etc/kubernetes/admin.conf ${HOME}/.kube/config,网上还有些说使用 export KUBECONFIG=/etc/kubernetes/admin.conf 来更新。

发现还是没用。

仔细想想,这个跟kubectl确实是没关系的,因为绕过kubectl直接请求api时也出现了问题。

所以问题应该就是在 kubelet与api-server 交互上。

  • 检查kubelet日志 systemctl status kubelet,虽然有一些错误日志,但没看到一些有用的关键信息。

  • 那可能就是 kube-apiserver 服务证书没更新,于是找到对应节点的 apiserver 的pod,执行:

    kubectl -n kube-system delete pod kube-apiserver-xxxx
    

很奇怪,还是不行?而且重启后这个pod看似重启了,但数据好像没更新(我看到该pod的重启次数没刷新)。

那就直接使用docker查看 docker ps |grep kube-apiserver,果然,该容器的UP时间都没刷新。

最终杀手锏,暴力重启 docker restart containerID

问题就解决了!

原因分析

排查了我老半天,而且是带着半信半疑排查解决的,总结一下这个问题:

为什么获取pod列表就可以,获取pod日志就不行?

  • 首先无论是kubectl还是使用k8sClient,实质都是请求apiserver进行交互的,认证信息都在~/.kube/config里。

  • 为了缓解各模块对API Server的访问压力,kubelet会定期从从 API Server 获取指定的资源对象信息(LIST/WATCH方法)保存到etcd。

  • 获取pod列表实际是通过apiserver访问etcd里的数据;而查看pod日志需要通过 apiserver -> kubelet -> CRI(containerd)。中间apiserver与kubelet的交互需要证书验证。

为什么直接删掉kube-apiserver pod达不到重启的效果,需要docker restart

  • 默认情况下kubelet是会定时扫描/etc/kubernetes/manifests(kubeadm默认目录,或通过 --pod-manifest-path 来指定目录),然后根据这个文件夹下的 YAML/JSON 文件来创建/删除静态 Pod。

  • 也就是说,执行 kubectl delete pod kube-apiserver 时,不是通过apiserver,而是通过Kubelet来删除。

  • kubelet监听到删除事件,只是将mirror pod(annotations里有kubernetes.io/config.mirror的key)标记删除,仅仅删除etcd里的信息,随后又会自动上传static pod信息并重新生成pod。

所以直接删掉kube-apiserver pod是不会重启真正的容器的。

为什么证书刚更新过,还需要删除kube-apiserver container证书才能正常?

  • 证书过期了,k8s调度没有问题,只是apiserver与kubelet之间通信的证书没有生效。
  • controller-manager和schduler都是利用的client-go去调用apiserver,是利用kubernetes 的配置文件/etc/kubernetes/路径下的controller-manager.conf和scheduler.conf来进行安全通信。
  • 而apiserver调用kubelet,是通过读取apiserver初始化的配置缓存信息,获取kubelet 的client证书,再进行https的安全通信。
  • 实际上这些k8s组件都没有自动加载证书的功能,但恰巧controller-manager和schduler都重启过。
  • 此时apiserver容器里的证书刚好过期,与 kubelet交互认证失败,所以获取 pod log 或者 exec 会失败。

所以出现创建、查看和删除资源是没问题;获取pod日志时,apiserver调用kubelet接口时才有问题。

总结

更新证书后,除了重启控制节点的kubelet,还需要手动重启 kube-apiserver、kube-controller、kube-scheduler、etcd 这4个容器。

docker ps | grep -v pause | grep -E "etcd|scheduler|controller|apiserver" | awk '{print $1}' | xargs docker restart

参考资料

kubelet之cri演变史

Kubectl exec 背后到底发生了什么?

关于Kubernetes证书的那点事

原文地址:https://www.cnblogs.com/wzs5800/p/15085193.html