Cilium ClusterMesh vs Submariner, 뭘 쓸까
멀티클러스터 네트워킹 붙일 일이 생겼다. 처음엔 별 생각 없었는데, 막상 후보를 놓고 보니 결정이 애매했다. Cilium ClusterMesh랑 Submariner. 둘 다 CNCF 프로젝트고, 둘 다 "서비스가 클러스터 경계를 넘어서 통신하게 해준다"는 결과물은 비슷하다.
근데 실제로 붙여보면 완전 다른 물건이다. 우리 팀은 결국 ClusterMesh로 갔지만, 그게 정답이라고는 못 하겠다. 상황에 따라 다르다.
왜 이 결정을 해야 했나
우리 쪽은 EKS 두 개 리전에 걸쳐 있다. 서울 + 도쿄. 원래는 리전간 통신이 필요 없었는데, 이번에 특정 서비스(주문/결제 쪽)를 DR 목적으로 양쪽에 띄우기로 하면서 상황이 바뀌었다.
요구사항이 이랬다:
- 서비스가 다른 리전 클러스터의 파드도 endpoint로 인식해야 함
- 지역 우선(topology-aware) 라우팅 필요. 서울에서 뜬 파드는 웬만하면 서울 파드로만 감
- NetworkPolicy가 리전 경계 넘어서도 먹혀야 함
- Istio는 이미 걷어내고 있는 상태라, 추가 sidecar 없이 가고 싶었다
이 조건들을 놓고 Cilium ClusterMesh랑 Submariner를 비교했다.
아키텍처 차이가 결정타
이게 사실 제일 큰 차이인데, 문서만 훑어보면 잘 안 보인다. 실제로 각각 붙여보고 나서야 감이 왔다.
Submariner는 broker 기반이다. 별도 broker 클러스터(또는 기존 클러스터 중 하나)를 두고, 각 클러스터의 gateway 노드가 broker와 통신하면서 cluster 정보를 교환한다. 트래픽은 gateway 노드를 통해 IPsec 또는 WireGuard 터널을 타고 넘어간다. CNI에 독립적이다. Calico 클러스터 하나, Cilium 클러스터 하나 붙이는 것도 된다.
Cilium ClusterMesh는 gateway가 없다. 각 클러스터가 clustermesh-apiserver를 통해 서로의 파드 IP, 정책 정보를 직접 공유한다. 트래픽은 파드에서 다른 클러스터 파드로 직접 간다. 대신 모든 클러스터가 Cilium을 CNI로 써야 한다.
이걸 표로 정리하면 이런 느낌:
| 항목 | Cilium ClusterMesh | Submariner |
|---|---|---|
| CNI 요구사항 | Cilium 필수 | 무관 (Calico/Flannel/Cilium 다 됨) |
| 데이터플레인 | 파드 직결 (eBPF) | Gateway 노드 경유 (IPsec/WireGuard) |
| 컨트롤플레인 | 클러스터별 apiserver | 중앙 broker |
| 정책 전파 | CiliumNetworkPolicy 자동 확장 | 별도 (SubmarinerPolicy 없음, CNI 정책에 의존) |
| 홉 수 | 1홉 | 2홉 이상 (gw → gw) |
우리는 이미 두 클러스터 다 Cilium이었다. 그래서 첫 조건은 문제 없었다.
그런데 문제는 성능
솔직히 처음엔 Submariner가 좋아 보였다. CNI 독립적이라는 게 매력적이었다. 나중에 CNI 바꾸더라도 그대로 쓸 수 있으니까.
근데 성능 테스트를 하고 나서 마음이 바뀌었다.
서울 ↔ 도쿄 리전간 baseline RTT가 약 33ms. 여기서 Submariner를 태우면 gateway 노드에서 IPsec으로 감싸고 다시 도쿄 gateway에서 풀고 목적지 파드로 가는 흐름이 된다. 실측해보니:
- baseline (VPC peering, 직결): 33ms
- Submariner (WireGuard 모드): 38~42ms
- Cilium ClusterMesh (VXLAN 위에 파드 직결): 34~36ms
수치 자체는 크지 않다. 근데 특정 API는 리전간 왕복이 한 요청에 서너 번 일어나는 케이스가 있었고, 이게 누적되니 P99가 눈에 띄게 벌어졌다.
그리고 throughput. gateway 노드가 병목이 됐다. 우리는 gateway를 2개로 이중화했는데도 특정 시간대에 CPU가 60%를 넘겨서 결국 노드 사양을 올려야 했다. ClusterMesh는 이런 병목 지점 자체가 없다.
그럼 Submariner는 언제 쓰나
이걸 뒤집어서 보면 Submariner 쓸 이유도 명확해진다.
서로 다른 CNI를 쓰는 클러스터를 붙여야 할 때. 예를 들어 OpenShift(OpenShift SDN)랑 EKS(VPC CNI)를 같이 붙이는 상황이라면 ClusterMesh는 답이 없다. Submariner가 유일한 실용 선택지다.
On-prem이랑 클라우드 섞을 때. On-prem은 Calico, 클라우드는 Cilium 같은 하이브리드 환경도 마찬가지.
단순 서비스 디스커버리만 필요할 때. endpoint를 클러스터 전체에 걸쳐 로드밸런싱까지 할 필요 없고, "다른 클러스터에 있는 서비스 하나 부르기"만 되면 되는 케이스도 있다. 이럴 땐 Submariner의 Lighthouse가 딱이다. 대신 한 서비스의 endpoint가 여러 클러스터에 흩어져 있는 상황은 Submariner에선 잘 안 다뤄진다. 원격 서비스 discovery는 되는데 endpoint 분산은 지원이 약하다.
보안 요구가 강할 때. Submariner는 기본이 IPsec 터널이라 리전간/클러스터간 트래픽이 자동으로 암호화된다. ClusterMesh는 WireGuard 옵션을 켜야 암호화가 붙는다. 기본은 평문(underlay 신뢰). VPC peering 안에서만 돈다면 별문제 없지만, 인터넷 구간을 넘으면 별도 설정이 필요하다.
우리 팀 선택과 그 이후
우리는 결국 Cilium ClusterMesh로 갔다. 이유는:
1. 이미 양쪽 다 Cilium이었다
2. gateway 노드라는 추가 관리 대상이 부담스러웠다. Submariner gateway는 노드 스케줄링, HA, 업그레이드 다 별개로 관리해야 한다
3. CiliumNetworkPolicy를 리전 경계 넘어서 그대로 쓸 수 있다는 게 컸다. 정책 이중 관리를 피할 수 있었다
4. 성능 수치가 유의미하게 유리했다
붙이는 과정은 생각보다 단순했다. cilium clustermesh enable → cilium clustermesh connect 두 줄이다. 근데 방심하면 안 되는 게, 두 클러스터의 pod CIDR이 겹치면 안 된다. 서울 클러스터가 10.100.0.0/16이었고 도쿄도 우연히 같은 대역이라 pod CIDR을 재설계해야 했다. 이거 미리 확인 안 하고 들어가면 롤백만 며칠 걸린다.
topology-aware routing은 service.kubernetes.io/topology-mode: Auto 로 켰다. 대부분의 경우 로컬 클러스터 endpoint로 붙고, 로컬이 죽으면 자동으로 원격 fallback. DR 시나리오 테스트에서 fallback까지 약 5초 걸렸다. 이 정도면 우리 SLA엔 충분.
한 달쯤 운영해 본 결론: 좋다. 근데 몇 가지 잔소리는 있다.
- clustermesh-apiserver가 은근히 리소스를 쓴다. 큰 클러스터에선 replica를 늘려야 한다
- 두 클러스터의 Cilium 버전이 크게 벌어지면 곤란하다. 우리는 minor 하나 이내로 유지하는 걸 룰로 정했다
- 트러블슈팅이 좀 낯설다.
cilium-dbg troubleshoot clustermesh같은 커맨드에 익숙해져야 한다
정리하면
결국 이 결정은 "이미 CNI를 뭘 쓰고 있느냐"가 8할이다. Cilium 통일 환경이면 ClusterMesh가 성능/운영 면에서 우세하고, CNI가 섞여 있으면 Submariner 외에 답이 없다.
우리 팀 케이스에선 ClusterMesh가 맞았다. 그런데 만약 우리가 on-prem OpenShift + AWS 하이브리드였다면 그날로 Submariner를 골랐을 거다. 이건 옳고 그름의 문제가 아니라 환경의 문제다.
혹시 이미 이 조합으로 운영 중이신 분들 계시면 어떤 함정을 밟았는지 궁금하다. 특히 ClusterMesh에서 클러스터 3개 이상 mesh 구성해본 경험담이 있으면 공유 부탁드린다.
태그: Cilium, Submariner, Kubernetes, 멀티클러스터, ClusterMesh, DevOps, 네트워킹