报错1
有一套老环境,集群版本是1.14,集群的ca证书要过期了,更换了集群的ca证书,重新生成相关证书文件,证书名叫Kubernetes
,重启etcd,apiserver,controller-manager,scheduler,kube-proxy,kubelet后,node节点变为NotReady
状态,所有node节点的kubelet都有如下的报错:
error getting node "1.2.3.4": Get https://127.0.0.1:10250/api/v1/nodes/1.2.3.4?resourceVersion=0&timeout=10s: x509:certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "Kubernetes")
apiserver报错:
http: TLS handshake error from 1.2.3.4:12345: remote error: tls: unknown certificate authority
etcd报错:
rejected connection from "1.2.3.4:33333" (error "remote error: tls: bad certificate", ServerName "")
解决
上面etcd的报错中拒绝连接的都是node节点的连接。etcd是只会连接apiserver的,不会连接node节点。但日志中显示有node节点的连接,这是为什么呢?查看集群的网络组件是calico,猜测calico是否使用了etcd为后端存储,然后节点的calico-node
连到了etcd上。
kubectl get cm -n kube-system calico-config -o yaml
发现calico果然使用了etcd为后端存储。那就需要修改calico的secret中的ca证书。
kubectl get secret -n kube-system calico-etcd-secrets -o yaml
cat ca.pem | base64 -w 0 > etcd-ca
cat etcd.pem | base64 -w 0 > etcd-cert
cat etcd-key.pem | base64 -w 0 > etcd-key
kubectl edit secret -n kube-system calico-etcd-secrets
重启calico-node,pod处于pending状态,集群还是同样的报错没有恢复。说明还是kubelet的问题。
查看节点的kubelet配置。
ps aux |grep kubelet
cat /srv/kubernetes/10.conf
现在kubelet连接apiserver异常,无法更新节点状态。上面的certificate-authority-data
即ca证书已经手动更新了,那问题就出现在下面的kubelet客户端证书kubelet-client-current.pem
。这个证书用于确保apiserver在与kubelet通信时能够证明自己的身份。可以通过kube-controller-manager
自动续签也可以手动更新。由于还没过期所以手动更新证书。
cd /var/lib/kubelet/pki
mv kubelet-client-current.pem ..
systemctl restart kubelet
移走后证书并没有自动生成。查看kube-controller-manager
已经启用了RotateKubeletServerCertificate=true
。这里就涉及到k8s的证书管理机制了。k8s使用 CSR(Certificate Signing Request)机制来管理节点和组件的证书。查看是否有csr请求。发现果然有一个,审批后节点的kubelet日志恢复正常,节点状态变为Ready。
kubectl certificate approve <csr-name>
同时kubelet日志中会有如下输出,证明kubelet已经使用了新的证书。
certificate rotation detected ,shutting down client connections to start using new credentials
问题2
所有节点的状态恢复Ready后,calico-node和controller状态都变为Running了,但是查看coreDNS日志仍然有证书报错。
想起来sa会自动生成一个secret,这个secret中会包含ca证书,但这个secret如果没有删除不会自动刷新,也就是说coreDNS仍然使用的旧的ca。手动删除这个secret让它自动生成即可。
kubectl get sa -n kube-system coredns -o yaml
kubectl get secret -n kube-system coredns-token-hqqnv -o yaml
kubectl delete secret -n kube-system coredns-token-hqqnv
secret重新生成后,重启coreDNS的pod,恢复正常。其他有同样的报错的也需要删除sa相关的secret,重启pod。
问题3
使用kubectl logs查看pod日志会报证书错误,但是在主机上查看容器日志没有报错。
解决
容器日志没有问题说明不是容器的问题,而且有多个pod都有同样的输出,那就还是kubelet的问题。
上面kubelet-client-current.pem
的目录pki中还有一个文件:kubelet-server-current.pem
该文件用于kubelet服务器端,与其他组件如apiserver、节点上的其他服务进行安全通信。
使用kubectl logs
命令时会发送到apiserver,然后apiserver会发送请求到pod节点上的kubelet服务,然后kubelet通过CRI接口从容器的文件系统中获取日志再返回给apiserver。
kubelet接收到apiserver的请求后会使用kubelet-server-current.pem
来证明自己的身份,并加密通信内容由于证书中的ca证书未更新导致无法证明自己的身份。所以需要更新该证书。具体步骤同上,删除证书,重启kubelet,批准csr,重启pod即可。