Keepalived와 HAProxy를 사용한 HA K8s 클러스터

발행: (2026년 1월 9일 오후 11:59 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

번역을 진행하려면 실제 본문 텍스트가 필요합니다.
해당 글의 내용을 복사해서 제공해 주시면, 마크다운 형식과 코드 블록, URL은 그대로 유지하면서 한국어로 번역해 드리겠습니다.

Source:

개요

스택형 HA 클러스터는 etcd가 제공하는 분산 데이터 저장소 클러스터가 kubeadm으로 관리되는 노드들로 구성된 클러스터 위에 겹쳐진 토폴로지를 말합니다. 이 클러스터는 컨트롤 플레인 컴포넌트를 실행하는 노드들로 구성됩니다.

각 컨트롤 플레인 노드는 kube‑apiserver, kube‑scheduler, kube‑controller‑manager 인스턴스를 실행합니다. kube‑apiserver는 로드 밸런서를 통해 워커 노드에 노출됩니다.

각 컨트롤 플레인 노드는 로컬 etcd 멤버를 생성하며, 이 etcd 멤버는 동일한 노드의 kube‑apiserver와만 통신합니다. 로컬 kube‑controller‑manager와 kube‑scheduler 인스턴스도 마찬가지입니다.

Diagram

이 토폴로지는 컨트롤 플레인과 etcd 멤버를 같은 노드에 결합합니다. 외부 etcd 노드가 있는 클러스터보다 설정이 간단하고 복제 관리도 더 쉬워집니다.

3노드 스택형 클러스터에서 일어나는 일

각 컨트롤 플레인 노드는 다음을 실행합니다:

  • etcd 멤버
  • kube‑apiserver, scheduler, controller‑manager

따라서 구성은 다음과 같습니다:

  • 3개의 etcd 멤버 → 쿼럼 = 2
  • 3개의 API 서버 → 로드밸런싱 (1개가 다운돼도 처리 가능)

노드 하나가 실패하면 여전히 다음을 유지합니다:

  • 2개의 etcd 멤버 → 쿼럼 유지
  • 2개의 컨트롤 플레인 인스턴스 → 여전히 사용 가능

이는 kubeadm이 배포하는 기본 토폴로지입니다. kubeadm initkubeadm join --control-plane을 사용할 때 컨트롤 플레인 노드에 로컬 etcd 멤버가 자동으로 생성됩니다.

전제 조건: 이 문서는 클러스터 부트스트래핑 과정을 자세히 다루지 않으므로, 이전에 kubeadm으로 클러스터를 부트스트랩한 경험이 있다고 가정합니다.

Source:

머신 설정하기

HAProxy + Keepalived를 사용해 3개의 마스터 노드와 가상 IP(VIP)를 갖는 Kubernetes 고가용성(HA) 환경을 구축하려면 다음과 같은 구조화된 접근 방식을 따르세요.

마스터

  • 10.238.40.162
  • 10.238.40.163
  • 10.238.40.164

VIP: 10.238.40.166

모든 마스터에 HAProxy와 Keepalived 설치

sudo apt update
sudo apt install -y haproxy keepalived

HAProxy 설정

세 대의 마스터 노드 모두에서 /etc/haproxy/haproxy.cfg 파일을 편집합니다:

global
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    option httplog
    option dontlognull

frontend kubernetes-apiserver
    bind *:8443
    mode tcp
    option tcplog
    default_backend kubernetes-apiserver

backend kubernetes-apiserver
    mode tcp
    balance roundrobin
    option tcp-check
    server master1 10.238.40.162:6443 check fall 3 rise 2
    server master2 10.238.40.163:6443 check fall 3 rise 2
    server master3 10.238.40.164:6443 check fall 3 rise 2

Keepalived 설정

한 번에 하나의 노드만 VIP를 “소유”하게 되며(Keepalived가 관리), 설정 파일은 모든 노드에 존재합니다.

각 마스터 노드에서 /etc/keepalived/keepalived.conf 파일을 편집합니다.
주의: 각 노드의 priority 값을 아래 표와 같이 조정하세요.

노드Priority역할
Master1110MASTER
Master2100BACKUP
Master390BACKUP
global_defs {
    router_id LVS_DEVEL
    script_user root
    enable_script_security
}

vrrp_script chk_haproxy {
    script "/bin/curl -f http://localhost:6443/healthz || exit 1"
    interval 2
    weight -2
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface enp19s0
    virtual_router_id 51
    priority 110          # 위 표에 따라 노드별로 변경
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass k8s-ha-cluster
    }
    virtual_ipaddress {
        10.238.40.166/24
    }
    track_script {
        chk_haproxy
    }
}

서비스 재시작

sudo systemctl restart haproxy keepalived
sudo systemctl enable haproxy keepalived

VIP 확인

ip addr show | grep 10.238.40.166

VIP verification screenshot

서비스 상태 확인

sudo systemctl status haproxy
sudo systemctl status keepalived

클러스터 부트스트랩

첫 번째 마스터 노드에 kubeadm-config.yaml 파일을 생성합니다.
VIP를 control‑plane 엔드포인트로 사용하고 apiServer.certSANs에 포함시킵니다.

중요: InitConfigurationadvertiseAddress 필드를 각 마스터 노드의 IP 주소에 맞게 변경하십시오.

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.32.6
apiServer:
  certSANs:
    - "10.238.40.166"      # VIP
    - "127.0.0.1"          # localhost
    - "0.0.0.0"            # wildcard
    - "10.96.0.1"          # Kubernetes service IP
    - "10.238.40.162"
    - "10.238.40.163"
    - "10.238.40.164"
  extraArgs:
    # (add any extra arguments you need here)

일반적인 kubeadm init / kubeadm join 절차를 진행하되, VIP(10.238.40.166)를 control‑plane 엔드포인트로 지정합니다.

Source:

kubeadm 구성

horization-mode: Node,RBAC
certificatesDir: /etc/kubernetes/pki
clusterName: pcai
controlPlaneEndpoint: "10.238.40.166:8443"
controllerManager:
  extraArgs:
    bind-address: 0.0.0.0
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
networking:
  dnsDomain: cluster.local
  podSubnet: "172.20.0.0/16"
  serviceSubnet: "172.30.0.0/16"
scheduler:
  extraArgs:
    bind-address: 0.0.0.0
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "10.238.40.162"
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

클러스터 초기화

kubeadm init --upload-certs --config kubeadm-config.yaml -v=5

참고: 출력 결과를 저장하세요! 여기에는 컨트롤 플레인 및 워커 노드용 조인 명령이 포함됩니다.

kubectl 접근 설정

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

네트워킹 솔루션 설치 (Calico)

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml

네트워킹 파드가 준비될 때까지 대기

kubectl wait --for=condition=ready pod -l k8s-app=calico-node -n kube-system --timeout=300s

추가 컨트롤 플레인 노드 조인

다른 마스터 노드에서 ( kubeadm init 출력에 있는) 컨트롤 플레인 조인 명령을 실행합니다:

kubeadm join 10.238.40.166:8443 --token  \
  --discovery-token-ca-cert-hash sha256: \
  --control-plane --certificate-key 

참고: 인증서 키는 2시간만 유효합니다. 만료될 경우 새 키를 생성하세요:

kubeadm init phase upload-certs --upload-certs

검증 및 상태 확인

모든 노드가 준비되었는지 확인

kubectl get nodes -o wide

control‑plane 구성 요소 확인

kubectl get pods -n kube-system

etcd 클러스터 상태 확인

kubectl exec -n kube-system etcd- -- etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  member list

VIP 장애 조치 테스트

# VIP를 보유한 마스터 노드에서 keepalived 중지
sudo systemctl stop keepalived

# VIP가 다른 노드로 이동했는지 확인
ip addr show | grep 10.238.40.166

# VIP를 통한 API 접근 테스트
curl -k https://10.238.40.166:8443/healthz

# keepalived 재시작
sudo systemctl start keepalived

결론

축하합니다! HAProxy와 Keepalived를 사용한 스택형 etcd 토폴로지를 통해 고가용성 Kubernetes 클러스터를 성공적으로 배포했습니다. 이 설정은 다음과 같은 장점을 제공합니다:

주요 이점

  • 고가용성: 단일 장애 지점 없이 자동 페일오버
  • 로드 분산: HAProxy를 통해 모든 API 서버에 트래픽이 고르게 분산
  • 자동 복구: Keepalived가 몇 초 안에 VIP 페일오버를 처리
  • 단순화된 아키텍처: 외부 etcd 대비 스택형 토폴로지가 복잡성을 감소

클러스터 기능

이 3‑마스터 노드 구성에서는:

  • 1개의 노드 장애를 견디면서도 클러스터 전체 기능 유지
  • 3개 중 2개의 멤버가 남아 etcd 쿼럼 유지
  • 남은 정상 마스터를 통해 API 요청 지속 제공
  • VIP를 정상 작동 중인 노드로 자동 페일오버
Back to Blog

관련 글

더 보기 »

안녕, 뉴비 여기요.

안녕! 나는 다시 S.T.E.M. 분야로 돌아가고 있어. 에너지 시스템, 과학, 기술, 공학, 그리고 수학을 배우는 것을 즐겨. 내가 진행하고 있는 프로젝트 중 하나는...