LabHub
开始
学习 学习路径 课程

用 Kubespray 与 Terraform 搭建集群

换掉文件与用上新证书 — 续期与重置

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

한 줄 요약

인증서 갱신은 파일을 바꾸고 그 파일을 읽는 프로세스를 다시 띄우는 두 단계이고, kubespray 의 타이머는 만료가 가까울 때만 그 두 단계를 대신하며, reset.yml 은 클러스터를 지우지만 받은 파일과 몇 가지 흔적은 남깁니다.

왜 이게 필요했나

kubeadm 인증서 관리 문서에 따르면 kubeadm 이 만든 클라이언트 인증서는 1년 뒤 만료되고, 컨트롤 플레인을 업그레이드할 때 kubeadm 이 모두 갱신합니다. 문서는 그래서 "자주 업그레이드하는 것이 가장 좋은 방법" 이라고 적습니다. 그런데 현장의 클러스터는 1년 넘게 판을 고정해 두는 일이 흔하고, 그런 클러스터는 설치 1년이 되는 날 API 서버와 컨트롤러 사이의 인증이 한꺼번에 실패합니다. 알림이 없으면 원인을 찾는 데만 한참 걸립니다.

어떻게 동작하나

kubeadm 인증서는 kubespray 에서 /etc/kubernetes/ssl 에 있습니다. kubeadm 기본은 /etc/kubernetes/pki 인데 kubespray 는 kube_cert_dir 을 ssl 로 두고 pki 를 그쪽으로 링크합니다. kubeadm certs check-expiration 은 잎 인증서(apiserver, apiserver-kubelet-client, front-proxy-client, 그리고 admin.conf·controller-manager.conf·scheduler.conf·super-admin.conf 안의 클라이언트 인증서)와 CA 를 보여 주고, 외부 etcd 인 이 배치에서 etcd 인증서는 보여 주지 않습니다(4모듈).

갱신은 두 단계입니다. kubeadm certs renew all 은 CA 로 잎 인증서를 다시 서명해 파일과 kubeconfig 를 바꿉니다. 그리고 "kube-apiserver, kube-controller-manager, kube-scheduler, etcd 를 재시작해야 새 인증서를 쓴다" 고 출력합니다. 실측해 보면 API 서버의 서빙 인증서는 파일이 바뀌자 재시작 전에도 6443 에서 새 serial 로 나왔습니다 — kube-apiserver 가 서빙 인증서 파일을 다시 읽기 때문입니다. 하지만 controller-manager 와 scheduler 는 kubeconfig 안의 클라이언트 인증서를 시작할 때 읽습니다. 그래서 kubespray 의 k8s-certs-renew.sh 는 갱신 뒤 crictl rmp 로 세 정적 파드의 샌드박스를 지우고(kubelet 이 매니페스트를 보고 다시 띄운다), /root/.kube/config 를 새 admin.conf 로 바꾸고, 6443 이 다시 열릴 때까지 기다립니다. 실측에서 샌드박스를 지우고 /readyz 가 돌아오기까지 6초였습니다.

타이머는 만료가 가까울 때만 움직입니다. auto_renew_certificates: true 를 두면 컨트롤 플레인 역할이 k8s-certs-renew.timer 를 깝니다. 기본 달력은 Mon *-*-1,2,3,4,5,6,7 03:00:00, 즉 매달 첫 월요일 새벽 3시입니다. 스크립트는 "다음 타이머 시각 + 7일" 보다 먼저 만료되는 인증서가 있을 때만 갱신하고 재시작합니다. 방금 갱신한 인증서로 서비스를 돌리면 ## Skip cert renew and K8S container restart, since all residualTimes are beyond threshold ## 로 끝납니다. 매달 컨트롤 플레인을 흔들지 않으면서, 만료 한 달 전쯤 한 번만 재시작하게 설계한 것입니다.

reset.yml 은 되돌릴 수 없습니다. 그래서 reset_confirmation=yes 를 주지 않으면 프롬프트에서 멈춥니다. 역할은 서비스(kubelet·containerd·etcd)를 멈추고, 컨테이너와 파드를 지우고, iptables 와 IPVS 규칙을 비우고, 긴 목록의 파일과 디렉터리를 지웁니다 — /etc/kubernetes, /var/lib/kubelet, etcd 데이터, containerd 저장소, /etc/cni, ~/.kube, kubespray 가 깐 바이너리들. 이 삭제 작업은 ignore_errors 라서 하나가 실패해도 나머지를 계속 지웁니다. 반대로 목록에 없는 것은 남습니다. 실측에서 받은 파일 캐시 /tmp/releases(543MB)와 /usr/local/bin/etcdutl, 그리고 kubespray 가 바꾼 호스트 이름이 남았습니다. 받은 파일이 남는 것은 의도된 편의라 재설치가 빨라지고(실측 326초), etcdutl 은 삭제 목록에 빠진 것입니다.

현장에서 만나는 모습

1년 차 장애의 전형적인 순서는 이렇습니다. 어느 날 kubectl 이 x509: certificate has expired 로 거절되고, 조금 뒤 컨트롤러가 멈춰 새 파드가 만들어지지 않습니다. 급히 kubeadm certs renew all 을 돌렸는데 여전히 이상합니다 — 파일은 새것인데 controller-manager 는 옛 kubeconfig 로 떠 있고, 운영자의 ~/.kube/config 도 옛 인증서 그대로입니다. 두 번째 단계(재시작과 kubeconfig 배포)까지 해야 끝납니다. 이 코스의 권장은 단순합니다. 업그레이드를 1년 안에 한 번은 하고, 그러지 못할 클러스터라면 auto_renew_certificates 를 켜 두고 check-expiration 결과를 모니터링에 넣습니다.

reset 은 두 경우에 씁니다. 3모듈에서 본 것처럼 첫 설치가 CNI 앞에서 멈춰 다시 돌려도 이어지지 않을 때, 그리고 설치 뒤 바꾸기 어려운 값(네트워크 플러그인, 파드·서비스 대역)을 바꿔야 할 때입니다. 둘 다 "지우고 같은 인벤토리로 다시" 가 가장 빠른 길이고, 인벤토리가 선언으로 남아 있기 때문에 가능한 선택입니다.

다음 실습에서 할 것

클러스터를 세우고 인증서 serial 을 기록한 뒤, 손으로 갱신하고 정적 파드를 다시 띄워 새 인증서가 쓰이는지 확인합니다. 자동 갱신 타이머를 켜고 지금 한 번 돌려 스크립트가 왜 갱신하지 않는지 봅니다. reset.yml 로 지운 뒤 남은 것을 적고, 같은 인벤토리로 다시 세워 CA 와 노드가 새것인지 확인합니다.