on
Kubernetes: Flannel Ağ Yapısı
Kubernetes Ağ Modeli
Aşağıdaki grafik kubernetes kümesinin basit bir görünümü:
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:
- tüm konteynerler NAT olmadan diğer tüm konteynerlerle iletişim kurabilir,
- tüm düğümler NAT olmadan tüm konteynerlerle (ve tersi) iletişim kurabilir,
- bir kabın kendisini gördüğü IP, diğerlerinin gördüğü IP ile aynı olmalı.
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:
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.
İ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:
- IP paketini
flannel0
cihazına yazdığında, paket doğrudan çekirdeğe gönderilecek ve çekirdek, paketiroute
tablosuna göre yönlendirecektir. - Bir IP paketi çekirdeğe ulaştığında ve
route
tablolarıflannel0
cihaza yönlendirilmesi gerektiğini söylediğinde, çekirdek, paketi doğrudan bu cihazı oluşturan veflanneld
yönlendirme servisi olan sürece gönderir.
Ç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:
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.