Cilium Cluster Mesh Nedir? Neyi Çözer, Kazanımları ve İki kind Cluster'lı Failover Lab'ı

Cilium Cluster Mesh'i bir lab'la anlatıyorum: bir cluster'da 0'a inen servis diğerinden cevap verdi, 3'te 3. Global service ve cluster'lar arası policy.

Yazan: Mirac Can Yılmaz 11 dk okuma
Cilium Cluster Mesh Nedir? Neyi Çözer, Kazanımları ve İki kind Cluster'lı Failover Lab'ı - platform-mühendisliği yazısının kapak görseli

Ç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?

Diyagram: solda cluster başına bir kopya, mesh-1'deki kopya 0 pod'da ve mesh-2'deki boşta; sağda Cluster Mesh, aynı durum ama mesh-2 affinity local'lı global Service üzerinden cevap veriyor. Altta lab'dan dört sonuç: iki yönde 2'de 2 node bağlı, global service 2 cluster'da 4 backend, failover mesh-2'den 3'te 3, policy 8'de 5 zaman aşımı

  • 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ü.

make connect: Connected cluster kind-mesh-1 ve kind-mesh-2, yaklaşık bir dakika bekledikten sonra apiserver hazır, All 2 nodes are connected to all clusters, iki cluster'ın durumunda da 2/2 configured, 2/2 connected

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.

mesh-1'deki bir agent'tan cilium-dbg node list: dört node, mesh-2'nin iki node'u 10.245.0.0/24 ve 10.245.1.0/24 endpoint CIDR'ları ve Source clustermesh ile

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.

make demo: 6 istek, 2'sine Cluster-2, 4'üne Cluster-1 cevap verdi; rebel-base'in BPF servis tablosunda 4 backend, ikisi yerel 10.244.1.x, ikisi mesh-2'den 10.245.1.x

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.

make failover: affinity local ile 3'te 3 cevap Cluster-1'den; mesh-1 rebel-base 0'a inince 3'te 3 Cluster-2'den; replica'lar dönünce yine 3'te 3 Cluster-1'den

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ı.

Sadece mesh-2'deki rebel-base'e izin veren policy: 8 isteğin 5'i 3 saniyede zaman aşımına düştü, 3'üne 4 ile 12 ms arasında Cluster-2 cevap verdi; Hubble yerel rebel-base pod'una giden SYN için policy-verdict none EGRESS DENIED ve Policy denied DROPPED gösteriyor

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ı.

io.cilium.k8s.policy.cluster Exists olan policy: 8'de 8 cevap, 4'ü Cluster-1, 4'ü Cluster-2, 3 ile 20 ms

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

make hubble: mesh-1'deki x-wing'in son akışları hedefe göre gruplanmış; mesh-2'deki iki rebel-base pod'una 59 ve 37, mesh-1'dekilere 12 ve 12, hepsi FORWARDED

Son kontrol

make verify: clustermesh-apiserver hazır, bütün node'lar ve KVStoreMesh bağlı, mesh-2 2/2 connected, servis tablosunda iki cluster'dan 4 backend ve mesh-2'nin iki node'u Source clustermesh ile

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.

make up'tan sonra, connect'ten önce: clustermesh-apiserver 0/3 Init:0/1; event'ler FailedScheduling untolerated taint, ardından FailedMount configmap clustermesh-remote-users not found

Ü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.

connect'in ilk dakikası: Waiting for deployment clustermesh-apiserver, only 0 of 2 replicas available; eski pod 0/3 Terminating, yeni pod 3/3 Running

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 connect komutu 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=local ile 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 Exists ile 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

Hayatta en hakiki mürşit ilimdir.
Mustafa Kemal Atatürk