단일 컨트롤 플레인은 구성이 간단하지만 해당 노드가 멈추면 API 서버도 함께 멈춥니다. 운영 환경에서는 컨트롤 플레인을 홀수 개로 두고, 앞단의 로드밸런서 주소를 모든 노드가 공통 API 엔드포인트로 사용하게 구성할 수 있습니다.
이 글은 컨트롤 플레인 3대와 워커 3대, HAProxy 1대를 사용하는 stacked etcd 구성을 기준으로 합니다. 각 컨트롤 플레인에 etcd 멤버가 함께 배치되는 방식입니다.

구성 예시
| 역할 | 주소 |
|---|---|
| control-plane-1~3 | 10.10.10.11~13 |
| worker-1~3 | 10.10.10.21~23 |
| HAProxy | 10.10.10.10:6443 |
| Pod CIDR | 10.244.0.0/16 |
모든 노드에 같은 주 버전의 kubeadm·kubelet과 정상 동작하는 컨테이너 런타임이 설치돼 있어야 합니다. 로드밸런서는 각 API 서버의 TCP 6443 포트에 접근할 수 있어야 합니다.
HAProxy 설정
HAProxy 노드의 /etc/haproxy/haproxy.cfg에 API 서버용 프런트엔드와 백엔드를 추가합니다.
frontend kubernetes-api
bind 10.10.10.10:6443
mode tcp
option tcplog
default_backend kubernetes-control-planes
backend kubernetes-control-planes
mode tcp
balance roundrobin
option tcp-check
server cp1 10.10.10.11:6443 check
server cp2 10.10.10.12:6443 check
server cp3 10.10.10.13:6443 check
haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl restart haproxy
nc -zv -w 2 10.10.10.10 6443
API 서버를 올리기 전에는 Connection refused가 나올 수 있습니다. timeout이면 HAProxy와 컨트롤 플레인 사이의 방화벽·라우팅부터 확인해야 합니다.
첫 컨트롤 플레인 초기화
첫 노드에서 공통 엔드포인트와 Pod CIDR을 지정합니다.
sudo kubeadm init \
--control-plane-endpoint "10.10.10.10:6443" \
--pod-network-cidr "10.244.0.0/16" \
--upload-certs
--upload-certs는 다른 컨트롤 플레인이 인증서를 내려받을 수 있게 암호화해 임시 Secret에 올립니다. 출력되는 certificate-key는 민감정보이며 기본적으로 2시간 후 만료되므로 안전하게 보관하고 바로 조인하는 편이 좋습니다.
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown "$(id -u):$(id -g)" $HOME/.kube/config
사용할 CNI를 설치합니다. Flannel을 사용한다면 위 Pod CIDR과 맞춰야 합니다.
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
나머지 노드 조인
추가 컨트롤 플레인은 --control-plane과 인증서 키가 포함된 명령으로 한 대씩 조인합니다.
sudo kubeadm join 10.10.10.10:6443 \
--token [TOKEN] \
--discovery-token-ca-cert-hash sha256:[HASH] \
--control-plane \
--certificate-key [CERTIFICATE_KEY]
워커는 --control-plane과 --certificate-key 없이 조인합니다. 명령을 잃어버렸다면 기존 컨트롤 플레인에서 다시 만들 수 있습니다.
kubeadm token create --print-join-command
sudo kubeadm init phase upload-certs --upload-certs
장애 전환 확인
구축 완료만 확인하고 끝내면 HA 구성이 실제로 동작하는지 알 수 없습니다.
kubectl get nodes -o wide
kubectl -n kube-system get pods -o wide
kubectl -n kube-system rollout restart deployment coredns
컨트롤 플레인 한 대의 kubelet을 잠시 중지한 상태에서도 로드밸런서 주소를 통한 kubectl get nodes가 되는지 확인합니다. etcd는 투표 정족수가 필요하므로 세 멤버 중 두 멤버를 동시에 중단하면 안 됩니다. 스냅샷 절차는 ETCD 백업과 복원에서 이어집니다.