Building clusters with Kubespray and Terraform
failed=0 is only the start — checking a Kubespray cluster layer by layer
한국어 원문으로 표시합니다.
한 줄 요약
kubespray 로 세운 클러스터는 kubeadm 클러스터와 겉은 같지만 etcd·DNS·인증서 세 곳이 다르게 놓여 있어서, 검증도 그 세 곳을 따로 봐야 합니다.
왜 이게 필요했나
설치가 끝나면 사람들은 kubectl get nodes 한 줄을 보고 Ready 면 끝냅니다. 그런데 노드 Ready 는 kubelet 이 API 서버에 상태를 보고하고 CNI 설정 파일이 있다는 뜻일 뿐입니다. 파드가 이미지를 받을 수 있는지, 서비스 IP 로 요청이 가는지, 이름이 풀리는지, 1년 뒤에 무엇이 멈추는지는 그 한 줄에 없습니다. 게다가 kubespray 는 kubeadm 기본값과 다른 선택을 몇 가지 합니다. 그 차이를 모르면 kubeadm 문서의 점검 절차를 그대로 따라 하다가 정작 중요한 곳을 건너뜁니다.
어떻게 동작하나
노드와 테인트. kubeadm 은 컨트롤 플레인 노드에 node-role.kubernetes.io/control-plane:NoSchedule 테인트를 붙입니다. kubespray 는 인벤토리에서 그 노드가 kube_node 에도 들어 있으면 "Remove taint for control plane node with node role" 작업으로 이 테인트를 지웁니다. 그래서 노드 한 대짜리 kubespray 클러스터는 따로 손대지 않아도 일반 파드를 받습니다. 인벤토리의 그룹 배치가 곧 스케줄링 정책이 되는 셈입니다.
etcd 는 파드가 아닙니다. group_vars/all/etcd.yml 의 etcd_deployment_type 기본값이 host 라서, etcd 는 kubespray 가 받은 바이너리로 호스트의 etcd.service 로 뜹니다. kube-system 을 아무리 봐도 etcd 파드는 없고, 상태는 systemctl status etcd 와 /etc/etcd.env 에서 봅니다. API 서버는 이 etcd 를 "외부 etcd" 로 붙습니다.
인증서가 두 갈래입니다. kubeadm 이 만드는 것(API 서버, 컨트롤러·스케줄러 kubeconfig 등)은 kubespray 에서 /etc/kubernetes/ssl 에 있고, 잎 인증서 1년·CA 10년입니다. 이 VM 에서 kubeadm certs check-expiration 은 잎 364일·CA 9년을 보였고 etcd 는 목록에 없었습니다 — 외부 etcd 이기 때문입니다. etcd 인증서는 kubespray 의 make-ssl-etcd.sh 가 openssl 로 만들고, 기간은 certificates_duration(기본 36500일, 약 100년)입니다. 어느 쪽이 먼저 만료되는지 보면, 1년 안에 할 일은 kubeadm 쪽 갱신이라는 것이 분명해집니다.
DNS 는 두 단입니다. kubespray 는 기본으로 nodelocaldns 를 켭니다. 노드마다 DaemonSet 이 링크 로컬 주소(기본 169.254.25.10)에서 캐시 DNS 를 돌리고, kubelet 의 clusterDNS 가 그 주소를 파드에게 알려 줍니다. 캐시가 모르는 이름만 CoreDNS 로 넘어갑니다. 그래서 "DNS 가 된다" 를 확인하려면 CoreDNS 서비스 주소와 nodelocaldns 주소 둘 다에 물어봐야 하고, 파드가 실제로 쓰는 쪽은 뒤의 것입니다. 쿠버네티스 문서의 NodeLocal DNSCache 설명대로, 이 배치는 conntrack 경합과 CoreDNS 부하를 줄이려는 것입니다.
설치의 기록. kubespray 는 kubeadm 을 부를 때 쓴 /etc/kubernetes/kubeadm-config.yaml, etcd 의 /etc/etcd.env, 받은 바이너리 캐시 /tmp/releases(local_release_dir)를 노드에 남깁니다. 석 달 뒤 "이 클러스터는 어떤 값으로 세웠나" 를 물을 때 인벤토리 다음으로 보는 1차 자료입니다.
현장에서 만나는 모습
이 코스의 실측 클러스터(1.35.8, calico)에서 kube-system 에는 calico-kube-controllers, calico-node, coredns, dns-autoscaler, kube-apiserver, kube-controller-manager, kube-proxy, kube-scheduler, nodelocaldns 가 떴습니다. CoreDNS 는 한 개였는데, 레플리카 수를 dns-autoscaler 가 노드·코어 수에 맞춰 정하기 때문입니다. 노드가 늘면 CoreDNS 도 늘어납니다.
현장에서 가장 흔한 착각은 인증서입니다. 모니터링이 kubeadm certs check-expiration 결과만 긁고 있으면 etcd 인증서는 영영 감시되지 않습니다. 이번 배치에서는 etcd 쪽이 100년이라 문제가 되지 않지만, 누군가 certificates_duration 을 줄여 두었거나 etcd 를 kubeadm 배치로 바꿨다면 이야기가 달라집니다. 점검표에는 "어느 도구가 어느 인증서를 만들었나" 가 먼저 와야 합니다.
마지막 증거는 워크로드입니다. 파드 두 개짜리 Deployment 와 서비스 하나에 요청을 보내 두 파드 이름이 모두 돌아오면, 레지스트리 이그레스·스케줄링·파드 네트워크·kube-proxy 가 한 번에 확인됩니다. 초록불 여러 개보다 요청 한 번이 더 많은 것을 말해 줍니다.
다음 실습에서 할 것
클러스터를 세운 뒤 노드의 역할과 테인트를 읽고, 코어 파드 목록에서 etcd 가 빠져 있는 이유를 systemd 에서 확인합니다. nodelocaldns 와 CoreDNS 에 각각 이름을 물어 두 단의 DNS 를 확인하고, kubeadm 인증서와 etcd 인증서의 만료일을 openssl 로 읽습니다. kubespray 가 남긴 설정 파일을 확인한 뒤, 작은 워크로드에 실제 요청을 보내 마무리합니다.