膽戰心驚的一天
今天突然收到告警,k8s的節點NotReady,我靠!嚇了一身冷汗,遂遠程登錄上去查看,果然都是notready!這一嚇真是不輕啊,要知道所有node節點掛掉,等於整個集羣掛掉了,線上的服務都不能訪問。當時要是採訪我當時在想什麼,我只能高冷的回答你:“啥都沒想”,當時真是腦袋一片空白。
不過呢,辛好留了一手,使用k8s之前,也用虛擬機把k8s上的服務也部署了一遍,就是防止這種現象出現,當時也考慮到k8s集羣會有坑,沒想到這麼深,直接導致整個集羣不可用。部署的時候在想最好不要用到,果不其然,天不遂人願,竟然真的用到了。所以說多做些應急準備工作,就顯得非常有必要了。
既然對客戶訪問和使用不會造成影響,心裏如釋重負,壓力不是很大了。開始着手排查問題。
一、問題現象
Kubernetes 集羣日誌中出現
Apr 08 17:22:36 beta-k8s-master-1 kube-apiserver[1020]: E0408 17:22:36.857055 1020 authentication.go:64] Unable to authenticate the request due to an error: [x509: certificate has expired or is not yet valid, x509: certificate has expired or is not yet valid]
還有以下日誌信息
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.194226 3969 kubelet_node_status.go:383] Error updating node status, will retry: error getting node "node02": Unauthorized
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.195088 3969 kubelet_node_status.go:383] Error updating node status, will retry: error getting node "node02": Unauthorized
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.195961 3969 kubelet_node_status.go:383] Error updating node status, will retry: error getting node "node02": Unauthorized
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.196918 3969 kubelet_node_status.go:383] Error updating node status, will retry: error getting node "node02": Unauthorized
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.197846 3969 kubelet_node_status.go:383] Error updating node status, will retry: error getting node "node02": Unauthorized
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.197870 3969 kubelet_node_status.go:375] Unable to update node status: update node status exceeds retry count
Apr 08 15:34:25 node02 kubelet[3969]: E0408 15:34:25.220090 3969 reflector.go:205] k8s.io/kubernetes/pkg/kubelet/config/apiserver.go:47: Failed to list *v1.Pod: Unauthorized
以上信息顯示證書過期了
二、排查思路
1.服務器時間不對,導致證書過期:登上k8s節點查看日誌,發現時間都是北京時間,分秒不差。。。
2.確實證書過期了:
我的集羣是自己手動搭建的,並沒有通過kubeadm安裝,證書也是手動一個個作的。
$ openssl x509 -in /root/cfssl/kubernetes/kubernetes-root-ca.pem -noout -text |grep ' Not '
Not Before: Apr 3 09:17:00 2018 GMT
Not After : Apr 2 09:17:00 2023 GMT
$ openssl x509 -in /root/cfssl/kubernetes/kubernetes-client-proxy.pem -noout -text |grep ' Not '
Not Before: Apr 4 07:52:00 2018 GMT
Not After : Apr 3 07:52:00 2023 GMT
$ openssl x509 -in /root/cfssl/kubernetes/kubernetes-client-kubectl.pem -noout -text |grep ' Not '
Not Before: Apr 3 09:29:00 2018 GMT
Not After : Apr 2 09:29:00 2023 GMT
發現證書有效期是5年,還差好幾年呢,日誌怎麼會報證書過期呢?
集羣分爲兩種證書:
1.用於集羣 Master、Etcd等通信的證書。
2.用於集羣 Kubelet 組件證書。
這時坑位出現了:
我們在搭建 Kubernetes 集羣時,一般只聲明用於集羣 Master、Etcd等通信的證書 爲 10年 或者 更久,但未聲明集羣 Kubelet 組件證書 ,Kubelet 組件證書 默認有效期爲1年。集羣運行1年以後就會導致報 certificate has expired or is not yet valid 錯誤,導致集羣 Node不能於集羣 Master正常通信,node顯示是NotReady狀態。
三、解決問題
分兩種解決方案:
1.臨時解決證書問題:
重啓node節點上kube-proxy 和 kubelet 服務,
systemctl restart kubelet && systemctl restart kube-proxy
刪除NotReady節點重新加入k8s集羣
$ kubectl delete node beta-k8s-node-1 beta-k8s-node-2 beta-k8s-node-3
$ kubectl get csr
$ kubectl certificate approve node-csr-T4t2IpJvE73djBPsqq-xx3FnMWOLTFyPNK-sQ
$ kubectl certificate approve node-csr-_FaAvAIsXGZ4_vYfbT43xxwX9kMJCKDElfsRwA
$ kubectl certificate approve node-csr-nHBw2mUbjxK9ZZLvxpOx_gxxx9VYBDlUCKybW6Y8D4
最後查看弄的狀態都已經是ready了。服務也恢復正常
2.永久性解決證書問題(配置證書自動重載、輪轉)
添加參數:
修改 kubelet 組件配置,具體添加下面參數
--feature-gates=RotateKubeletServerCertificate=true
--feature-gates=RotateKubeletClientCertificate=true
# 1.8版本以上包含1.8都支持證書更換自動重載,以下版本只能手動重啓服務
--rotate-certificates
修改 controller-manager 組件配置,具體添加下面參數
# 證書有效期爲10年
--experimental-cluster-signing-duration=87600h0m0s
--feature-gates=RotateKubeletServerCertificate=true
創建自動批准相關 CSR 請求的 ClusterRole
vim tls-instructs-csr.yaml && kubectl apply -f tls-instructs-csr.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeserver
rules:
- apiGroups: ["certificates.k8s.io"]
resources: ["certificatesigningrequests/selfnodeserver"]
verbs: ["create"]
自動批准 kubelet-bootstrap 用戶 TLS bootstrapping 首次申請證書的 CSR 請求
kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=system:certificates.k8s.io:certificatesigningrequests:nodeclient --user=kubelet-bootstrap
自動批准 system:nodes 組用戶更新 kubelet 自身與 apiserver 通訊證書的 CSR 請求
kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeclient --group=system:nodes
自動批准 system:nodes 組用戶更新 kubelet 10250 api 端口證書的 CSR 請求
kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeserver --group=system:nodes
重啓kube-controller-manager 和 kubelet 服務
$ systemctl restart kube-controller-manager
# 進入到ssl配置目錄,刪除 kubelet 證書
$ rm -f kubelet-client-current.pem kubelet-client-2019-05-10-09-57-21.pem kubelet.key kubelet.crt
# 重啓啓動,啓動正常後會頒發有效期10年的ssl證書
$ systemctl restart kubelet
# 進入到ssl配置目錄,查看證書有效期
$ openssl x509 -in kubelet-client-current.pem -noout -text | grep "Not"
Not Before: May 13 02:36:00 2019 GMT
Not After : May 10 02:36:00 2029 GMT