1. 글을 작성하게 된 계기
운영 중인 Kubernetes 클러스터에서 갑작스럽게 kubectl 명령어가 동작하지 않는 문제가 발생했다.
단순한 노드 이슈 정도로 생각했지만, 원인은 바로 Kubernetes TLS 인증서 만료였다.
kubeadm 기반 클러스터에서 인증서 만료는 생각보다 흔하지만, 매뉴얼을 보지 않으면 대응이 어렵다.
이 글에서는 장애가 어떻게 발생했고, 어떤 방식으로 문제를 해결했는지 실제 사례 기반으로 정리한다.
2. 증상
평소처럼 kubectl get nodes 를 입력했는데, 다음 에러가 출력되었다.
tls: failed to verify certificate: x509: certificate has expired
current time 2025-12-02... is after 2025-11-30...
즉, API Server의 인증서가 만료되어 클라이언트가 인증을 거부한 상태였다.
이후 다른 명령들도 정상적으로 동작하지 않았다.
- kubectl 명령어 전반이 실패
- Pod가 Terminating 상태에서 계속 멈춤
- Deployment가 새로운 Pod를 생성하지 않음
Pod는 종료되었지만 Controller Manager가 작동하지 않아 새 Pod를 재생성하지 못하는 상황이었다.
3. 원인 분석
kubeadm 기반 인증서의 구조
kubeadm으로 초기화된 클러스터는 인증서 유효기간이 다음과 같다.
| apiserver.crt | 1년 |
| apiserver-kubelet-client.crt | 1년 |
| controller-manager.conf, scheduler.conf, admin.conf | 1년 |
| etcd 관련 cert | 1년 |
| CA (ca.crt) | 10년 |
즉:
TLS 인증서는 1년마다 만료되지만 자동 갱신되지 않는다.
실제로 클러스터의 인증서 만료 상태를 확인해보니, 거의 모든 주요 인증서가 만료되어 있었다.
sudo kubeadm certs check-expiration
...
apiserver <invalid>
apiserver-kubelet-client <invalid>
controller-manager.conf <invalid>
scheduler.conf <invalid>
...
API Server–Controller Manager–Scheduler–ETCD 간 TLS 통신이 끊기면서
컨트롤 플레인이 사실상 기능을 잃은 상태였던 것이다.
4. 해결 과정
4.1 인증서 갱신
먼저 인증서를 전체 갱신한다.
sudo kubeadm certs renew all
sudo systemctl restart kubelet
이 작업은 인증서 파일을 새로 생성하지만, 기존 static pod들은 여전히 만료된 인증서를 메모리에 가지고 실행 중이기 때문에
컨트롤 플레인 기능은 완전히 복구되지 않는다.
4.2 static pod 재기동
(이번 장애 해결의 핵심 단계)
kubeadm 환경의 컨트롤 플레인은 /etc/kubernetes/manifests 디렉토리의 yaml을 기반으로 kubelet이 static pod 형태로 관리한다.
따라서 이 yaml 파일들을 잠시 다른 디렉토리로 옮기면 관련 프로세스가 내려가고,
다시 되돌리면 새로운 인증서를 사용해 static pod가 재생성된다.
정리 디렉토리 생성
sudo mkdir -p /root/k8s-manifests-bak
manifests 파일 이동 → 컨트롤 플레인 종료
sudo mv /etc/kubernetes/manifests/*.yaml /root/k8s-manifests-bak/
(여기서 mv: cannot stat 같은 glob 이슈가 있을 경우, 개별 파일을 옮기면 된다.)
이 시점에서 apiserver, controller-manager, scheduler, etcd가 내려가며
kubectl은 몇십 초 동안 응답하지 않는다.
파일 복구 → static pod 재생성
sudo mv /root/k8s-manifests-bak/*.yaml /etc/kubernetes/manifests/
kubelet이 다시 static pod들을 읽고 새 TLS 인증서 기반으로 기동한다.
복구 상태 확인
kubectl get pods -n kube-system | egrep 'apiserver|controller|scheduler|etcd'
정상적으로 Running이 뜨면 컨트롤 플레인은 완전히 복구된 것이다.
5. Deployment 및 서비스 정상화 확인
컨트롤 플레인이 정상화되자 ReplicaSet이 정상적으로 새 Pod를 만들기 시작했다.
kubectl get pods -n dev-auw-ai -l app=dev-translator-paraphrasing
NAME READY STATUS RESTARTS AGE
dev-translator-paraphrasing-xxxxxx 1/1 Running 0 5m
새 Pod가 정상적으로 생성되어 서비스가 정상 복구되었다.
6. 이번 장애가 남긴 교훈
- kubeadm 인증서는 매년 만료된다
이 장애는 Kubernetes 자체의 고장이 아니라 인증서 주기의 특성 때문에 반드시 발생하는 이벤트였다.
kubeadm 기반 클러스터를 운영한다면, 인증서 만료는 피할 수 없다.
- static pod 재기동을 반드시 해야 한다
kubeadm certs renew all 만으로는 문제가 해결되지 않는다.
항상 apiserver, controller-manager, scheduler, etcd 를 재기동해야 새 인증서가 적용된다.
- 워커 노드는 크게 문제되지 않는다
컨트롤 플레인이 죽어도, 이미 실행 중인 Pod는 정상적으로 동작한다는 것도 확인했다.
(다만 새 Pod 생성/스케줄링은 중단된다.)
7. 재발 방지 방안
- 인증서 만료 모니터링
정기적으로 아래 명령으로 만료일을 확인한다.
sudo kubeadm certs check-expiration
- 연 1회 필수 작업
운영팀 캘린더에 매년 다음 작업을 넣어두면 안전하다.
sudo kubeadm certs renew all sudo systemctl restart kubelet
- 자동화
cron job 또는 systemd timer 을 활용해 인증서 만료 30일 전 자동 갱신도 가능하다.
'Come on IT > DevOps' 카테고리의 다른 글
| prometheus-kube-prometheus-kube-controller-manager/0 해결방법 (0) | 2025.02.26 |
|---|---|
| Prometheus exporter 에서 수집이 안되는 경우 (feat. grafana) (0) | 2025.02.26 |
| K8s 워커노드 추가하는 방법 (0) | 2025.02.14 |
| bpf_jit 증가에 따른 seccomp 오류 해결 방법 (error loading seccomp filter) (0) | 2025.01.04 |
| K8s namespace가 deleted 안될 때 (feat. monitoring) (0) | 2024.10.14 |