Çoğu ekip bir noktada birden fazla Kubernetes cluster'ına sahip oluyor, ardından paylaşılan servisler geliyor: auth, registry cache, feature flag servisi. Her cluster kendi kopyasını çalıştırıyor. Bir kopya düştüğünde o cluster'daki bütün uygulamalar servisi kaybediyor, aynı servis yan cluster'da boşta beklerken. Bu yazıda Cilium Cluster Mesh'in ne olduğuna, neyi çözdüğüne ve ne kazandırdığına bakıyorum; sonra bir cluster'da servisi 0'a indirdiğim ve client'ların diğer cluster'dan cevap almaya devam ettiği lab'ı gösteriyorum. Birkaç yerde patladı; gerçek mesajlarıyla sonda.
Cilium Cluster Mesh nedir?
Cilium Cluster Mesh, network eklentisi (CNI) olarak Cilium çalıştıran birden fazla Kubernetes cluster'ının ağlarını birbirine bağlıyor.
Cilium kendi cluster'ındaki her pod'u, her servisi ve her kimliği zaten biliyor, çünkü ağın kendisi o. Cluster Mesh bu bilgiyi cluster'lar arasında paylaşıyor. Sonrasında:
- Bir cluster'daki pod, başka bir cluster'daki pod'a doğrudan, node'dan node'a ulaşabiliyor.
- Birden fazla cluster'da aynı isimle duran bir Service, hepsinden backend alan tek bir global service olabiliyor.
- Bir network policy trafiğe cluster adına göre izin verebiliyor ya da engelleyebiliyor.
Merkezi bir control plane yok. Her cluster küçük bir clustermesh-apiserver çalıştırıyor, diğer cluster'ların Cilium agent'ları da ondan okuyor.
Neyi çözüyor?
Cluster başına bir kopya, ödünç alma yok. Dört cluster varsa her paylaşılan servisin dört kopyası var. Biri düştüğünde o cluster'ın elinde hiçbir şey kalmıyor, diğer üç kopya da yardım edemiyor, çünkü bir cluster sadece kendi pod'larını görüyor.
Cluster'ları bağlamak için fazladan parçalar. Bilinen cevap cluster'lar arası bir VPN, global bir load balancer ve servis başına bir DNS kaydı. Bu, her yeni cluster için ayarlanacak, hepsi Kubernetes dışında üç bileşen daha demek.
Policy'ler cluster sınırında bitiyor. Trafik bir cluster'dan diğerine geçiyorsa, normal bir network policy "buna izin ver ama sadece şu cluster'dan" diyemiyor.
Cluster Mesh ne kazandırıyor?
| Kazanım | Pratikte anlamı | Lab'da |
|---|---|---|
| Cluster'lar birbirini görüyor | Tek komut iki tarafı bağlıyor; agent'lar diğer cluster'ın node'larını ekliyor | All 2 nodes are connected to all clusters, iki yönde |
| Global service | Tek annotation; her cluster'da aynı isim ve namespace | Servis tablosunda 4 backend, cluster başına 2 |
| DNS'siz failover | affinity=local: yerelde kal, yerel pod'lar bitince karşıya geç |
0'a indirince: 3'te 3 cevap diğer cluster'dan, 0 hata |
| Cluster'a göre policy | CiliumNetworkPolicy içinde io.cilium.k8s.policy.cluster |
x-wing rebel-base'e sadece mesh-2'de ulaştı |
| Yeni datapath yok | Cluster'lar arasında gateway, proxy ya da NAT yok | Paketler doğrudan node'dan node'a gidiyor |
Karar vermeden önce neyi almadığınızı bilin:
| İhtiyaç | Cluster Mesh |
|---|---|
| Cilium çalıştırmayan cluster'lar | Katılamıyor. Her cluster'da Cilium olmalı. |
| Çakışan pod ağları | İzin yok. Pod ve service CIDR'ları her cluster'da farklı olmalı. |
| Sonradan değiştirilebilen cluster id | cluster.id (1–255) kurulumda veriliyor; değiştirmek bütün workload'ları yeniden başlatmak demek. |
| Ağ erişimi | Sizden: bütün cluster'lardaki node'lar birbirine ulaşmalı (aynı ağ, VPN ya da route edilen özel ağ). |
Nasıl çalışıyor?

- Paylaşım: her cluster'ın
clustermesh-apiserver'ı o cluster'ın node, kimlik, endpoint ve global service bilgisini tutan küçük bir etcd taşıyor. Diğer cluster'ın agent'ları ona mTLS ile bağlanıyor; bu yüzden iki cluster tek bir sertifika otoritesini (CA) paylaşmalı. - Datapath: pod trafiği node'lar arasında zaten bir tünelde (VXLAN) akıyor. Diğer cluster'ın node'ları tünel uçları listesine ekleniyor, karşıdaki bir pod'a giden paket doğrudan onun node'una gidiyor.
- Servis ve policy:
service.cilium.io/global: "true"annotation'ı olan bir Service, diğer cluster'ın pod'larını da backend olarak alıyor. Kimlikler cluster adını taşıyor, policy bunu seçebiliyor.
Lab: ne kurdum?
Her şey bir MacBook'ta kind üzerinde (Colima, 4 CPU / 8 GB): mesh-1 ve mesh-2 adında, ikişer node'lu iki cluster, Kubernetes 1.37 ve Cilium 1.20.2. Pod ağları çakışmıyor (10.244.0.0/16 ve 10.245.0.0/16), mesh-1'in cilium-ca secret'ı Cilium kurulmadan önce mesh-2'ye kopyalanıyor, böylece ikisi tek CA paylaşıyor. Demo Cilium'un kendi örneği: rebel-base çalıştığı cluster'ın adıyla cevap veriyor, mesh-1'deki x-wing onu çağırıyor. Bütün lab yaklaşık 8 dakika sürdü, çoğu iki cluster'ı oluşturmakla geçti.
Adım 1: İki cluster'ı bağla
Tek komut, cilium clustermesh connect, iki tarafı da ayarladı. 110 saniye sürdü, neredeyse tamamı clustermesh-apiserver pod'larının açılmasını beklemekle geçti (hatalar bölümünde anlatıyorum). Sonrasında her cluster diğerinin iki node'unu gördü.

Agent seviyesinde değişen şu: mesh-1'deki bir agent artık mesh-2'nin node'larını Source: clustermesh ile listeliyor. 10.245.x'teki bir pod'a giden paket doğrudan 172.20.0.5 ya da .6'ya gidiyor. Mesh'in datapath tarafı bundan ibaret.

Adım 2: Tek servis, iki cluster
Aynı rebel-base Service'i iki cluster'a da service.cilium.io/global: "true" annotation'ıyla gidiyor. Kural basit: aynı isim, aynı namespace, iki tarafta da annotation. mesh-1'deki x-wing, rebel-base ismini altı kez çağırdı: 4 cevap Cluster-1'den, 2 cevap Cluster-2'den geldi. DNS değişmedi, client değişmedi. Agent'ın servis tablosunda her cluster'dan ikişer olmak üzere dört backend vardı, o kadar.

Adım 3: affinity=local ile failover
Rastgele dağılım genelde istenen şey değil. Trafik kendi cluster'ında kalmalı, ancak yerel pod'lar bitince karşıya geçmeli. Bu ikinci bir annotation: service.cilium.io/affinity: local. Sonra mesh-1'deki rebel-base'i 0'a indirdim.

Yerel kopya yokken 3'te 3 cevap diğer cluster'dan, dönünce 3'te 3 evden, 0 başarısız istek, bütün tur 11 saniye. "Bir kopya düşüyor, diğerleri boşta bekliyor" sorununun çözümü bu, DNS'e dokunmadan.
Adım 4: Diğer cluster'ı adıyla anan policy
Network policy'ler hâlâ cluster başına çalışıyor: name: rebel-base seçen bir CiliumNetworkPolicy sadece kendi cluster'ındaki pod'ları seçiyor. Diğer cluster'a ulaşmak için onu io.cilium.k8s.policy.cluster label'ıyla anmanız gerekiyor. x-wing'in rebel-base'e sadece mesh-2'de ulaşmasına izin veren bir policy yazdım ve affinity'yi kaldırdım; Service istekleri yine dört backend'e dağıttı.

8 isteğin 5'i zaman aşımına düştü. Service hâlâ dört backend'den birini seçiyordu, policy de yerel iki tanesini engelliyordu. Hubble sebebini gösterdi: x-wing'den yerel rebel-base'e giden SYN EGRESS DENIED. Policy servisi değil pod'u seçiyor. Cluster label'ında operator: Exists ile ("herhangi bir cluster'daki rebel-base") 8 isteğin hepsi iki cluster'dan, 3 ile 20 ms arasında cevap aldı.

Hubble her akışın hangi cluster'a gittiğini de gösteriyor, çünkü akışlar iki tarafta da cluster adını taşıyor.

Son kontrol

Nerede patladı: 3 gerçek hata
1. clustermesh-apiserver Init:0/1'de kaldı: configmap "clustermesh-remote-users" not found
Cilium'u kurduktan hemen sonra clustermesh-apiserver pod'u hiç açılmadı, cilium status --wait de 5 dakika sonra pes etti (ilk koşumda 361 saniye). Event, clustermesh-remote-users adında bir ConfigMap beklediğini söylüyor. Helm chart'ında onu oluşturan bir şey yok, cilium clustermesh connect oluşturuyor. Yani sıra şu: sadece Cilium agent'larını bekle, connect'i çalıştır, apiserver kendiliğinden açılsın. Lab'ın kurulum script'i agent'ları bekliyor, apiserver'ı connect'e bırakıyor.

Üstündeki FailedScheduling: untolerated taint satırı zararsız: ilk dakika Cilium açılana kadar node'larda not-ready taint'i var.
2. connect'ten hemen sonra: iki apiserver pod'u ve "0 of 2 replicas"
connect'ten sonraki yaklaşık bir dakika her cluster iki clustermesh-apiserver pod'u gösteriyor, connect de only 0 of 2 replicas are available yazıp duruyor. connect pod'u değiştiren bir Helm upgrade çalıştırıyor, eski takılı pod'un yanında yenisi açılıyor. Yenisi 3/3 oluyor, eskisi siliniyor. O dakikada cilium status'a bakarsanız hata görürsünüz, aslında bir sorun yok. Deployment clustermesh-apiserver is ready satırını bekleyin.

3. Failover policy'ye takıldı
Bu yine Adım 4, ama production'da insanların düştüğü hata bu. Global service'i ve failover'ı kuruyorsunuz, policy olmadan test ediyorsunuz, çalışıyor. Sonra her zamanki default-deny policy'lerinizi uyguluyorsunuz (network policy yazısı) ve failover bozuluyor, çünkü rebel-base'e izin veren kural sadece yerel rebel-base'i seçiyor. Çözüm cluster label'ını Exists ile seçmek; böylece yeni bir cluster policy değişikliği gerektirmiyor.
Lab dosyaları önlediği için yaşamadıklarım: çakışan pod CIDR'ları (iki kind config'i de podSubnet veriyor), eksik cluster.id (her cluster'ın values dosyasında duruyor) ve CA uyuşmazlığı (script ikinci kurulumdan önce cilium-ca'yı kopyalıyor ve same CA kontrol ediyor). Belgelenmiş belirtileri cluster ID must be set to a value between 1 and 255 ve x509: certificate signed by unknown authority.
Ne zaman kullanmalı, ne zaman değil?
| Durum | Seçim |
|---|---|
| Bütün cluster'larınız Cilium çalıştırıyor ve aralarında failover'lı paylaşılan servis istiyorsunuz | Cluster Mesh. Datapath'te yeni bileşen yok. |
| Bazı cluster'lar başka bir CNI kullanıyor | Submariner (CNI'dan bağımsız, gateway node'ları) ya da multi-cluster destekli bir service mesh. |
| Zaten Istio çalıştırıyorsunuz ve cluster'lar arası mTLS ile retry lazım | Istio multi-cluster. Cluster Mesh uygulama seviyesinde mTLS eklemiyor. |
| Farklı bulutlarda ya da veri merkezlerinde, aralarında özel bağlantı olmayan cluster'lar | Önce ağı kurun (VPN ya da route edilen bağlantı). Cluster Mesh node'dan node'a erişim istiyor. |
| Bir cluster paylaşılan servisleri kullansın ama kendininkini sunmasın | O cluster'ın Service'inde service.cilium.io/shared: "false" ile Cluster Mesh. |
Özet
- Cilium Cluster Mesh, Cilium çalıştıran cluster'ların ağlarını gateway ya da merkezi control plane olmadan bağlıyor.
- Tek bir
connectkomutu iki tarafı da ayarladı; sonrasında her agent diğer cluster'ın node'larını listeledi. - Tek annotation bir Service'i iki cluster'dan backend alan global bir servise çevirdi.
affinity=localile bir cluster'da 0'a indirilen servis diğerinden cevap vermeye devam etti: 3'te 3, 0 hata.- Policy'ler pod'ları hâlâ cluster başına seçiyor: policy
Existsile herhangi bir cluster'a izin verene kadar 8 isteğin 5'i zaman aşımına düştü.
Kaynaklar: Cilium dokümanları Setting up Cluster Mesh, Load-balancing & Service Discovery (global service, affinity), Multi-cluster network policy; Cilium 1.20 Helm referansı (clustermesh.*); Cilium'un rebel-base / x-wing cluster mesh örneği.
Serinin devamı
Bu yazı Cilium Uçtan Uca serisinin altıncısı. Sıradaki: Tetragon Nedir? Neyi Çözer, Kazanımları ve Bir Secret'ı Okumadan Süreci Öldüren Kubernetes Lab'ı. Önceki yazı: Sidecar'sız Service Mesh Nedir? Neyi Çözer, Kazanımları ve WireGuard ile Mutual Auth'lu Bir Cilium Lab'ı.
Bu lab'ın kodu (iki kind config'i, ortak ve cluster'a özel values dosyaları, global service demosu, iki policy, connect/failover/policy/Hubble script'leri ve Makefile) Buy Me a Coffee'deki Lab Access üyeleriyle paylaşılıyor; katıldıktan sonra repo daveti e-postayla geliyor: https://buymeacoffee.com/miraccanyilmaz/membership