LabHub

CCA — 실리움 인증 어소시에이트 · ClusterMesh 와 외부 워크로드 · 이론

클러스터를 늘리기 전에 끝내야 하는 설계

LabHub 에서 이어서 보기

한 줄 요약

ClusterMesh 는 여러 클러스터의 아이덴티티와 서비스를 동기화해 단일 클러스터와 같은 정책 모델을 유지합니다. 다만 CIDR 과 CA 설계는 나중에 바꾸기가 거의 불가능하므로 처음에 끝내야 합니다.

왜 이게 필요했나

클러스터가 둘 이상이 되면 곧바로 질문이 생깁니다. 리전 장애 시 다른 클러스터로 넘길 수 있는가, 클러스터 간 호출에 같은 보안 정책을 적용할 수 있는가. 서비스 메시로 풀 수도 있지만 그러면 프록시 계층이 하나 더 얹힙니다.

ClusterMesh 의 접근은 다릅니다. 데이터 평면에 추가 홉을 만들지 않고 컨트롤 플레인만 연결합니다. 각 클러스터가 clustermesh-apiserver 로 자기 서비스·아이덴티티·엔드포인트를 노출하고, 상대 클러스터의 에이전트가 그것을 watch 합니다. 동기화가 끝나면 패킷은 기존 라우팅 모드로 직접 흐릅니다. 중앙 게이트웨이도 단일 장애점도 없습니다.

어떻게 동작하나

전제 조건이 곧 설계 결정입니다.

동기화되는 것은 서비스(글로벌로 표시된 것), 아이덴티티, 그리고 ipcache 입니다. 아이덴티티가 경계를 넘어 의미를 유지하는 것이 핵심입니다. 클러스터 B 의 app=backend 파드 아이덴티티가 클러스터 A 의 ipcache 에도 전파되므로, 멀티클러스터 정책이 단일 클러스터와 똑같은 라벨 문법으로 동작합니다.

글로벌 서비스는 애너테이션으로 만듭니다.

| 애너테이션 | 값 | 동작 |
| --- | --- | --- |
| service.cilium.io/global | "true" | 클러스터 간 백엔드를 합산 |
| service.cilium.io/affinity | local | 로컬 백엔드 우선, 전멸 시 원격 |
| service.cilium.io/affinity | remote | 원격 우선 (드레인·카나리) |
| service.cilium.io/affinity | none | 전 클러스터 균등 분산 |

실무 표준은 affinity: local 입니다. 평상시에는 클러스터 안에서 처리해 레이턴시를 아끼고, 로컬 백엔드가 전부 unhealthy 가 되면 원격으로 넘어갑니다. 그런데 여기에 숨은 의존성이 있습니다. "unhealthy 판정"은 readiness 기반입니다. readinessProbe 가 엉성하면(예: 프로세스가 살아 있기만 하면 Ready) 사실상 고장 난 백엔드가 계속 Ready 로 남아 페일오버가 일어나지 않습니다. 엉성한 readinessProbe 는 엉성한 페일오버가 됩니다.

정책 쪽 함정도 하나 있습니다. ClusterMesh 환경에서 라벨 셀렉터에 io.cilium.k8s.policy.cluster 를 빼면 양쪽 클러스터의 같은 라벨 파드가 모두 매칭됩니다. "DB 는 자기 클러스터의 앱에서만 접근 가능"을 의도했는데 원격 클러스터의 동명 워크로드까지 열리는 사고가 여기서 납니다.

운영 규칙도 몇 가지 있습니다. 연결된 클러스터 간 Cilium 버전 스큐는 마이너 1단계까지만 지원되므로 "한 클러스터씩 올리고, 전부 같은 버전이 되기 전에는 다음 마이너로 넘어가지 않기"가 원칙입니다. 클러스터를 제거할 때는 글로벌 서비스 의존부터 정리해야 합니다. affinity: none 으로 원격에 의존하던 서비스가 있으면 disconnect 순간 백엔드가 줄어듭니다. 그리고 clustermesh-apiserver 가 죽어도 이미 동기화된 서비스와 아이덴티티로 트래픽은 계속 흐릅니다. 멈추는 것은 새 변경의 전파입니다.

외부 워크로드(External Workloads) 기능은 VM 이나 베어메탈에 에이전트를 설치해 클러스터에 참여시키는 것입니다. 그 워크로드도 아이덴티티를 받으므로 같은 라벨 기반 정책이 적용됩니다.

현장에서 만나는 모습

저자의 홈랩은 아직 단일 클러스터지만, 3노드에서 7노드로 확장하면서 정확히 같은 종류의 교훈을 얻었습니다.

컨트롤 플레인을 3대로 늘려 etcd 멤버 3개를 확보했으니 HA 가 됐다고 생각했는데, 아니었습니다. kubeadm-configcontrolPlaneEndpoint 가 VIP 나 DNS 가 아니라 cp-1 의 물리 IP 10.0.0.120 이었고, 그 주소가 7개 노드의 kubelet 설정과 모든 kubeconfig, 그리고 apiserver 인증서 SAN 에 박혀 있었습니다. cp-1 이 죽으면 etcd 쿼럼은 2/3 로 멀쩡하고 나머지 apiserver 프로세스도 정상인데 아무도 문을 찾지 못하는 상태가 됩니다.

이 사례가 ClusterMesh 설계에 그대로 대응됩니다. 컨트롤 플레인의 데이터 가용성과 접근 가용성은 별개 문제이고, 엔드포인트·CIDR·CA 같은 값은 클러스터 생성 후 바꾸기가 몹시 고통스러운 몇 안 되는 설정입니다. 그래서 클러스터를 하나만 쓸 계획이더라도 PodCIDR 을 겹치지 않게 잡고 CA 설계를 미리 해 두는 편이 미래의 자신을 구합니다. 같은 홈랩에서 WireGuard 암호화는 Peers: 2, 포트 51871 로 노드 간 터널이 맺혀 있는데, 이 전송 암호화 계층은 클러스터를 넘어가도 같은 방식으로 확장됩니다.

다음 퀴즈에서 확인할 것

ClusterMesh 는 클러스터가 둘 이상이어야 실습할 수 있으므로 이 모듈은 개념과 퀴즈로 마무리합니다. 클러스터 ID 범위, CIDR 과 CA 전제, 글로벌 서비스 어피니티와 readiness 의존, 그리고 정책에서 클러스터 라벨을 빠뜨렸을 때의 함정을 점검하세요.