Kubernetes: Flannel Ağ Yapısı

flannel

Kubernetes Ağ Modeli

Aşağıdaki grafik kubernetes kümesinin basit bir görünümü:

k8s

Kubernetes, bir ana Linux makinesini (AWS EC2 veya fiziksel sunucular gibi cloud VM olabilir) yönetir, her bir ana makinede, Kubernetes birden fazla Pod çalıştırabilir, her bir Pod’da birden fazla konteyner bulunabilir. Kullanıcının uygulaması bu konteynerlerden birinde çalışıyor. Kubernetes için, Pod minimum yönetim birimidir ve bir Pod içindeki tüm konteynerler aynı ağ ad alanını paylaşır; bu, aynı ağ arayüzüne sahip oldukları ve localhost kullanarak birbirleriyle bağlantı kurabilecekleri anlamına geliyor.

Kubernetes dokümanında ağ modelinin aşağıdakileri gerektirdiğini belirtiyor:

Temel olarak, tüm Pod’ların kümedeki diğer Pod’larla, farklı ana bilgisayarlarda olsalar bile, özgürce iletişim kurabilmeleri gerektiği ve aynı ana bilgisayarın bulunmadığında birbirlerini kendi IP adresleriyle tanıdıkları anlamına gelir. Ayrıca, ana bilgisayar, herhangi bir adres çevirisi olmadan, kendi IP adresiyle herhangi bir Pod ile iletişim kurabilmelidir.

Kubernetes herhangi bir varsayılan ağ uygulaması sağlamaz, yalnızca modeli tanımlar ve uygulamak işini diğer araçlara bırakır.

Overlay Ağı

Flannel, Kubernetes ağı için CoreOS tarafından geliştirilmiştir, ayrıca başka amaçlar için genel bir yazılım tanımlı ağ çözümü olarak da kullanılabilir.

Kubernetesin ağ gereksinimlerini karşılamak için flannel’in çözümü basit: ana bilgisayar ağının üzerinde çalışan başka bir düz ağ oluşturmak, buna overlay ağı denir. Bu overlay ağında tüm kapsayıcılara (Pod) bir ip adresi atanır, birbirlerinin doğrudan IP adresini arayarak birbirleriyle iletişim kurarlar. Açıklamak için,

Aşağıdaki kümede 3 Kubernetes düğümü var:

k8s-network-graph

Yukarıdaki kümede 3 ağ var:

VPC (Virtual Private Cloud) ağı: tüm örnekler tek bir VPC alt ağında bulunur 172.20.32.0/19. Bu aralıkta ip adresleri atanmış, tüm LAN’lar aynı LAN’da oldukları için birbirlerine bağlanabilir.

Flannel kaplama ağı: Flannel başka bir ağ oluşturdu 100.96.0.0/16, 2¹⁶ (65536) adres alabilen daha büyük bir ağ ve tüm kubernetes düğümlerinde, her poda bu aralıkta bir adres verilecek.

Ana bilgisayar içi docker ağı: Her ana bilgisayarın içinde, Flannel bu ana bilgisayardaki tüm podlara 100.96.x.0/24 ağı atadı, 2⁸(256) adres tutabilir. *docker bridge interface docker0`, yeni konteynerler oluşturmak için bu ağı kullanır.

Bu tasarıma göre, her bir konteynerin kendi IP adresi vardır, hepsi üst üste overlay alt ağına 100.96.0.0/16 girer. Aynı ana bilgisayarın içindeki konteynerler, docker bridge docker0 ile birbirleriyle iletişim kurabilir. Ana ağlar arasında overlay ağındaki diğer konteynerlerle iletişim kurmak için, Flannel, kernel route table ve bunu elde etmek için UDP kapsüllemesi kullanır.

Ana Bilgisayarlar Arası Konteyner Iletişimi

100.96.1.2 IP adresine sahip olan Düğüm 1’deki konteyner, 100.96.2.3 IP adresi ile 2. Düğümde bulunan konteynere bağlanmak istiyor. overlay ağının paketlerin geçmesini nasıl sağladığına bakalım.

cross-host-com

İlk konteyner, src: 100.96.1.2 -> dst: 100.96.2.3 olan bir IP paketi yaratır, paket konteynerin ağ geçidi olduğu gibi docker0 köprü ağına gider.

Her ana bilgisayarda, Flannel, Flannel adında bir daemon işlemi gerçekleştirir, çekirdeğin route tablosunda bazı route kuralları oluşturur, Düğüm 1’in route tablosu şöyle görünür:

$ ip route
default via 172.20.32.1 dev eth0
100.96.0.0/16 dev flannel0  proto kernel  scope link  src 100.96.1.0
100.96.1.0/24 dev docker0  proto kernel  scope link  src 100.96.1.1
172.20.32.0/19 dev eth0  proto kernel  scope link  src 172.20.33.102

Göründüğü gibi, paketin hedef adresi 100.96.2.3 daha büyük overlay ağına (100.96.0.0/16) düşüyor, bu yüzden ikinci kurala uyuyor, artık çekirdek paketin flannel0‘a gönderilmesi gerektiğini biliyor.

flannel0, flanneld arka plan servisi işlemimiz tarafından yaratılan bir TUN aygıtıdır, TUN linux çekirdeğinde uygulanan bir yazılım arabirimidir, kullanıcı programı ile çekirdek arasında ham ip paketini geçirebilir. İki yönde çalışır:

Çekirdek, TUN cihazına paket gönderirken doğrudan flanneld işlemine gidecektir, hedef adresin 100.96.2.3 olduğunu görür, ancak bu adresin Düğüm 2’de çalışan bir konteynere ait olduğunu şemadan görebiliriz, peki Flannel bunu nasıl biliyor.

Bu nedenle, Flannel, bazı bilgileri etcd adlı bir anahtar-değer depolama hizmetinde saklar.

$ etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/100.96.1.0-24
/coreos.com/network/subnets/100.96.2.0-24
/coreos.com/network/subnets/100.96.3.0-24

$ etcdctl get /coreos.com/network/subnets/100.96.2.0-24
{"PublicIP":"172.20.54.98"}

Bu nedenle, her Flannel işlemi, her bir alt ağın hangi ana bilgisayara ait olduğunu bilmek için etcd’yi sorgular ve hedef ip adresini, etcd içinde depolanan tüm alt ağ anahtarlarıyla karşılaştırır. Bizim durumumuzda, 100.96.2.3 adresi, 100.96.2.0-24 alt ağıyla eşleşecek ve bu anahtarlarda depolanan değerin gördüğümüz gibi düğümünün IP adresinin 172.20.54.98 olduğunu söylüyor.

Artık flanneld hedef adresini biliyor, orijinal IP paketini bir UDP paketine, kendi ana bilgisayarının kaynak adres olarak IP’sini ve hedef ana bilgisayarın IP’sini hedef adres olarak ayarlar. Her ana bilgisayarda, flanneld işlemi, varsayılan bir UDP bağlantı noktasını dinler: 8285. Bu yüzden sadece UDP paketinin hedef portunu 8285‘e ayarlamanız ve göndermeniz yeterli.

UDP paketi hedef ana bilgisayara ulaştıktan sonra, çekirdeğin IP yığını, paketi UDP bağlantı noktasında dinleyen kullanıcı işlemi olduğu için paketi flanneld işlemine gönderir. Ardından flanneld, orijinal konteyner tarafından üretilen orijinal IP paketi olan UDP paketinin yükünü alacaktır, bu paketi sadece TUN cihazı flannel0‘a yazılır, ardından paket TUN’un çalışma şekliyle doğrudan çekirdeğe geçecektir.

Düğüm 2 route tablosu:

ip route
default via 172.20.32.1 dev eth0
100.96.0.0/16 dev flannel0  proto kernel  scope link  src 100.96.2.0
100.96.2.0/24 dev docker0  proto kernel  scope link  src 100.96.2.1
172.20.32.0/19 dev eth0  proto kernel  scope link  src 172.20.54.98

IP paketinin hedef adresi 100.96.2.3‘tür, çekirdek üçüncü kural olan eşleşmeyi alacaktır. Paket docker0‘a gönderilecektir. docker0 bir köprü aracı olduğundan ve bu ana bilgisayardaki tüm konteynerler bu köprüye bağlı olduğundan, paket hedef konteyner-2 tarafından görülecek ve alınacaktır.

Sonunda paket hedefe giden tek yönlü geçişi tamamlar, konteyner-2 paketi konteyner-1’e geri gönderdiğinde, ters rota tam olarak aynı şekilde çalışacaktır. Ana bilgisayar konteyner iletişimi bu şekilde çalışır.

Docker Ağı Yapılandırma

Docker’ı 100.96.x.0/24 gibi daha küçük bir alt ağ kullanacak şekilde yapılandırmak için flanneld, alt ağ bilgilerini ana bilgisayardaki bir dosyaya yazar:

$ cat /run/flannel/subnet.env
FLANNEL_NETWORK=100.96.0.0/16
FLANNEL_SUBNET=100.96.1.1/24
FLANNEL_MTU=8973
FLANNEL_IPMASQ=true
dockerd --bip=$FLANNEL_SUBNET --mtu=$FLANNEL_MTU

Paket Kopyalama ve Performans

Flannel’in yeni versiyonu, UDP kapsüllemesi kullanılmasını önermiyor, sadece hata ayıklama ve test amaçlı kullanılması gerektiğini söylüyor. Bunun bir nedeni performans.

flannel0 TUN cihazı çekirdeğin içinden paket almak ve göndermek için basit bir yol sağlasa da, performans dezavantajı var: paketin kullanıcı alanından çekirdek alanına kadar ileri geri kopyalanması gerekir:

flannel-packet-copy

Yukarıdaki gibi, orijinal konteyner işlem gönderme paketinden, kullanıcı alanı ile çekirdek alanı arasında 3 kez kopyalanması gerekir, bu ağ yükünü önemli ölçüde arttıracaktır, bu nedenle mümkünse UDP kullanmaktan kaçınmalısınız.

Kaynak 1 - Kaynak 2 - Kaynak 3 - Kaynak 4 - Kaynak 5