오랫동안 쿠버네티스를 사용하지 않아, 쿠버네티스(Kubernetes) 가 사용 불능상태에 있었다. 원인은 인증서 만료 때문이었는데, 어떻게 다시 인증서를 업데이트하고 사용가능 상태로 만드는지 기록해 둔다.
증상
증상은 다음과 같다.
|
1 2 3 4 5 6 7 |
]$ kubectl get nodes E0920 02:32:18.797873 3109 memcache.go:265] couldn't get current server API group list: Get "https://192.168.96.23:6443/api?timeout=32s": dial tcp 192.168.96.23:6443: connect: connection refused E0920 02:32:18.798045 3109 memcache.go:265] couldn't get current server API group list: Get "https://192.168.96.23:6443/api?timeout=32s": dial tcp 192.168.96.23:6443: connect: connection refused E0920 02:32:18.799277 3109 memcache.go:265] couldn't get current server API group list: Get "https://192.168.96.23:6443/api?timeout=32s": dial tcp 192.168.96.23:6443: connect: connection refused E0920 02:32:18.799423 3109 memcache.go:265] couldn't get current server API group list: Get "https://192.168.96.23:6443/api?timeout=32s": dial tcp 192.168.96.23:6443: connect: connection refused E0920 02:32:18.800621 3109 memcache.go:265] couldn't get current server API group list: Get "https://192.168.96.23:6443/api?timeout=32s": dial tcp 192.168.96.23:6443: connect: connection refused The connection to the server 192.168.96.23:6443 was refused - did you specify the right host or port? |
kube-apiserver 의 로그는 다음과 같다.
|
1 2 3 4 |
9월 20 02:42:25 kmaster kubelet[3769]: E0920 02:42:25.403235 3769 bootstrap.go:266] part of the existing bootstrap client certificate in /etc/kubernetes/kubelet.conf is expired: 2024-07-10 16:20:05 +0000 UTC 9월 20 02:42:25 kmaster kubelet[3769]: E0920 02:42:25.403257 3769 run.go:74] "command failed" err="failed to run Kubelet: unable to load bootstrap kubeconfig: stat /etc/kubernetes/bootstrap-kubelet.conf: no such file or directory" 9월 20 02:42:25 kmaster systemd[1]: kubelet.service: Main process exited, code=exited, status=1/FAILURE 9월 20 02:42:25 kmaster systemd[1]: kubelet.service: Failed with result 'exit-code'. |
해결책
마스터 노드 복구
인증서를 갱신해주면 된다. 다음과 같이 확인과 갱신을 할 수 있다.
|
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 현재 인증서 만료일 상태 확인 $ sudo kubeadm certs check-expiration [check-expiration] Reading configuration from the cluster... [check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [check-expiration] Error reading configuration from the Cluster. Falling back to default configuration CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED admin.conf Apr 30, 2025 16:50 UTC <invalid> ca no apiserver Apr 30, 2025 16:48 UTC <invalid> ca no apiserver-etcd-client Apr 30, 2025 16:48 UTC <invalid> etcd-ca no apiserver-kubelet-client Apr 30, 2025 16:48 UTC <invalid> ca no controller-manager.conf Apr 30, 2025 16:49 UTC <invalid> ca no etcd-healthcheck-client Apr 30, 2025 13:27 UTC <invalid> etcd-ca no etcd-peer Apr 30, 2025 13:27 UTC <invalid> etcd-ca no etcd-server Apr 30, 2025 13:27 UTC <invalid> etcd-ca no front-proxy-client Apr 30, 2025 16:48 UTC <invalid> front-proxy-ca no scheduler.conf Apr 30, 2025 16:49 UTC <invalid> ca no super-admin.conf Apr 30, 2025 16:50 UTC <invalid> ca no CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED ca Feb 25, 2032 16:06 UTC 5y no etcd-ca Feb 25, 2032 16:07 UTC 5y no front-proxy-ca Feb 25, 2032 16:06 UTC 5y no # 모든 컨트롤 플레인 인증서 갱신 $sudo kubeadm certs renew all [renew] Reading configuration from the cluster... [renew] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [renew] Error reading configuration from the Cluster. Falling back to default configuration certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed certificate for serving the Kubernetes API renewed certificate the apiserver uses to access etcd renewed certificate for the API server to connect to kubelet renewed certificate embedded in the kubeconfig file for the controller manager to use renewed certificate for liveness probes to healthcheck etcd renewed certificate for etcd nodes to communicate with each other renewed certificate for serving etcd renewed certificate for the front proxy client renewed certificate embedded in the kubeconfig file for the scheduler manager to use renewed certificate embedded in the kubeconfig file for the super-admin renewed Done renewing certificates. You must restart the kube-apiserver, kube-controller-manager, kube-scheduler and etcd, so that they can use the new certificates. |
이걸로 끝이 아니다.
K8S 는 각종 설정 파일에 인증서를 포함시켜놨다. 그래서 이 설정 파일들도 재 생성을 해야 한다.
|
1 2 3 4 5 6 7 |
# 기존 설정 파일 백업 sudo mv /etc/kubernetes/admin.conf /etc/kubernetes/admin.conf.bak sudo mv /etc/kubernetes/kubelet.conf /etc/kubernetes/kubelet.conf.bak # 새 설정 파일 생성 sudo kubeadm init phase kubeconfig admin sudo kubeadm init phase kubeconfig kubelet |
이제 kubectl 명령어가 사용하는 config 파일을 갱신해준다.
|
1 2 3 |
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config |
마스터 노드의 기존 PKI 캐시 정리 및 Kubelet 재시작해줘야 한다. 마스터 노드 내부에 남아 있는 구형 인증서 캐시를 날려주어야 새 인증서를 정상적으로 물고 살아난다.
|
1 2 |
sudo rm -rf /var/lib/kubelet/pki/* sudo systemctl restart kubelet |
워커 노드 복구
워커 노드도 인증서가 만료되어서 작동이 되지 않고 있다. 이를 처리하기 위해서는 Pod 를 제외한 kubelet 을 초기화 하고 worker 노드를 재가입시키는 방법을 적용 한다.
다음과 같이 워커 노드 서비스 중지 및 찌꺼기 강제 삭제 (각 워커 노드에서 실행)를 해준다.
|
1 2 3 4 5 6 7 8 |
# kubelet 및 컨테이너 런타임 제어 sudo systemctl stop kubelet sudo systemctl stop containerd sudo systemctl start containerd # 기존 쿠버네티스 설정 및 인증서 잔여물 강제 삭제 sudo rm -rf /etc/kubernetes/* sudo rm -rf /var/lib/kubelet/* |
다음으로 네트워크 및 iptables 찌꺼기 초기화를 해준다. 단, 이거는 선택사항이다. iptables 과 cni 인터페이스가 상태를 봐가면서해야 한다. 필자의 경우에는 아무것도 없어서 해줄게 없었다.
|
1 2 3 |
sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X sudo ip link set cni0 down 2>/dev/null || true sudo ip link delete cni0 2>/dev/null || true |
이제 마스터 노드에서 새 Join 명령어 발급해준다. 마치 처음 worker 노드를 추가하는 것과 같다. 마스터 노드에서 실행해줘야 한다.
|
1 |
kubeadm token create --print-join-command |
출력되는 ‘kubeadm join ... --token ... --discovery-token-ca-cert-hash ...‘ 명령어 복사해 준다.
다음으로 워커 노드에서 클러스터 재참여(Join) 수행해준다.
|
1 |
sudo kubeadm join <마스터_IP>:6443 --token <토큰값> --discovery-token-ca-cert-hash sha256:<해시값> --cri-socket unix:///run/containerd/containerd.sock |
혹시 대기중인 CSR 이 있는지를 확인하고 승인해 준다.
|
1 2 |
kubectl get csr kubectl certificate approve <csr_이름> |
확인
다음과 같이 노드(Node)가 살아 있는지를 확인해 본다.
|
1 2 3 4 |
$ kubectl get nodes NAME STATUS ROLES AGE VERSION kmaster Ready control-plane 4y205d v1.30.0 kworker1 Ready <none> 4y205d v1.30.0 |