Docker swarm中的LB和服務(wù)發(fā)現(xiàn)詳解

Docker 提供了 overlay driver,使用戶可以創(chuàng)建基于 VxLAN 的 overlay 網(wǎng)絡(luò)。VxLAN 可將二層數(shù)據(jù)封裝到 UDP 進行傳輸,VxLAN 提供與 VLAN 相同的以太網(wǎng)二層服務(wù),但是擁有更強的擴展性和靈活性。linux下是使用了net namespace來隔離docker創(chuàng)建的overlay網(wǎng)絡(luò)。

Docker 網(wǎng)絡(luò)模型如下:

image.png

Sandbox

一個Sandbox包含了一個容器網(wǎng)絡(luò)棧的配置。其中包括了對容器的網(wǎng)卡,路由表以及對DNS設(shè)置的管理。通常,一個Sandbox的實現(xiàn)可以是一個Linux Network Namespace,一個FreeBSD Jail或者其他類似的東西。一個Sandbox可以包含多個處于不同Network的Endpoint。

Endpoint

Endpoint將一個Sandbox加入一個Network。Endpoint的實現(xiàn)可以是一個veth對,一個Open vSwitch internal port或者其他類似的東西。一個Endpoint只能屬于一個Network和一個Sandbox。

Network

Network是一個能夠互相通信的Endpoint的集合。Network的實現(xiàn)可以是一個Linux網(wǎng)橋,一個VLAN等等。


Docker swarm中的服務(wù)發(fā)現(xiàn):

每一個docker容器都有一個域名解析器,用來把域名查詢請求轉(zhuǎn)發(fā)到docker engine;docker engine內(nèi)部dns的服務(wù)器收到請求后就會在發(fā)出請求的容器所在的所有網(wǎng)絡(luò)中檢查域名對應(yīng)的是不是一個容器或者是服務(wù),如果是,docker引擎就會從存儲的key-value建值對中查找這個容器名、任務(wù)名、或者服務(wù)名對應(yīng)的IP地址,并把這個IP地址或者是服務(wù)的虛擬IP地址返回給發(fā)起請求的域名解析器。如果目的容器或服務(wù)和源容器不在同一個網(wǎng)絡(luò)里面,Docker引擎會把這個DNS查詢轉(zhuǎn)發(fā)到配置的默認DNS服務(wù)。

docker-dns.png

上圖展示了task1.client請求兩個不同資源dns返回的不同結(jié)果


Docker swarm 中的LB分為兩種情況:

1. Ingress Load Balancing

2. Internal Load Balancing


簡要介紹測試環(huán)境下docker swarm中的網(wǎng)絡(luò)分布情況:

環(huán)境:
swarm-a(manager node):10.10.8.92

swarm-b(work node):10.10.8.93

swarm-c(work node):10.10.8.94

在docker swarm集群創(chuàng)建的開始,docker 會給每臺host創(chuàng)建除了docker0以外的兩個網(wǎng)絡(luò),分是bridge類型(docker_gwbridge網(wǎng)橋)和overlay類型(ingress)的網(wǎng)絡(luò),以及一個過度的命名空間ingress_sbox,我們可以使用如下命令自建overlay網(wǎng)絡(luò),結(jié)果如下:

docker network create --driver overlay mynet (后續(xù)會有用到)

1.png

  • ingress網(wǎng)絡(luò)的IPAM( IP Address Management)分配如下:
ingress-net.png
  • mynet自建的overlay會使用docker自動分配的IPAM:
mynet.png
  • 建完的overlay網(wǎng)絡(luò)的同時會在host本地創(chuàng)建對應(yīng)的Net Namespace如下:
ns.png

注意1:要是想看到容器創(chuàng)建的兩個Net Namespace需要執(zhí)行
ln -s /var/run/docker/netns /var/run/netns


1. Ingress Load Balancing

1)、部署一個service使用默認的ingress網(wǎng)絡(luò):

docker service create --name web_ingress_lb --replicas=2 --publish 8090:80 httpd

  • 部署的兩個容器分別處在a和b節(jié)點上:
ingress-1.png
  • service:web_ingress_lb的網(wǎng)絡(luò)連接結(jié)構(gòu)圖如下:
image.png

Swarm mode下,docker會創(chuàng)建一個默認的overlay網(wǎng)絡(luò)—ingress network。Docker也會為每個worker節(jié)點創(chuàng)建一個特殊的net namespace(sandbox)-- ingress_sbox。ingress_sbox有兩個endpoint,一個用于連接ingress network,另一個用于連接local bridge network docker_gwbridge。Ingress network的IP空間為10.255.0.0/16,所有router mesh的service都共用此空間。

2)、Ingress Load Balancing實現(xiàn)方式:

swarm-ingress.jpg

1>宿主機網(wǎng)絡(luò)通過worker節(jié)點IP和service published port來訪問服務(wù)。比如:上面服務(wù)定義-p 8090:80,可以通過workerIP:8090 訪問服務(wù)

2>每個節(jié)點iptables中NAT表定義規(guī)則,對于匹配published的宿主機端口(8090)的數(shù)據(jù),將其dst IP轉(zhuǎn)換成ingress_sbox中的ip:172.18.0.2。使數(shù)據(jù)包轉(zhuǎn)發(fā)到ingress_sbox的ns中交給該ns處理做下一步的轉(zhuǎn)發(fā)。

ingress-2.png

3>Ingress_sbox是swarm為每個節(jié)點默認創(chuàng)建的net namespace,用于連接ingress overlay network。此處會設(shè)置mangle表,將dst port為8090的數(shù)據(jù)做標記(fwmark)。同時做DNAT轉(zhuǎn)換成vip地址使數(shù)據(jù)包能正常轉(zhuǎn)發(fā)到ingress的ns中,該vip由ingress_sbox的ipvs做負載轉(zhuǎn)發(fā)。

ingress-3.png

4>Ingress_sbox會設(shè)置kernel中的LVS模塊,將標記fwmark的包LB到各個實際IP中,默認round-robin算法,forware為VS/NAT方式。容器底層間通過overlay網(wǎng)絡(luò)互連通信。

ingress-4.png
  • 數(shù)據(jù)包在這一步進入ingress的ns后怎么實現(xiàn)到后端真實容器上呢?我們猜想下ingress想要轉(zhuǎn)發(fā)就需要有各個節(jié)點容器對應(yīng)的ingress veth pair網(wǎng)卡的mac地址才能做轉(zhuǎn)發(fā)是吧,好的那我們來看下ingress的ns空間中的fdb(linux bridge forward db)信息。
ingress-5.png
  • 查看b節(jié)點上web_ingress_lb.1容器的mac地址信息
ingress-6.png

這樣一來即使容器的副本沒有落到host上我們?nèi)钥梢酝ㄟ^這種轉(zhuǎn)發(fā)方式來訪問到服務(wù)。這應(yīng)該就是routing mesh吧!

5>Service的各個容器會將dst port為8080的數(shù)據(jù)的dst port轉(zhuǎn)換成80,從而訪問到真實的服務(wù)。

ingress-7.png

可以看到一個請求到主機端口8090之后, 數(shù)據(jù)包的流向如下所示:
主機端口8090 => Ingress-sbox-VIP:8090 => 容器Ingress-sbox => IPVS分發(fā)到containers。
大家可以看到訪問主機之后數(shù)據(jù)包流到了一個特殊的Sandbox容器里, 這個容器和我們的容器共享一個Ingress網(wǎng)絡(luò),通過Iptables和IPVS等重定向到了最終容器之上。 達到了服務(wù)在任何一臺主機的8090端口都可達的目的。


2. Internal Load Balancing

1)、部署一個service使用我們自己創(chuàng)建的mynet網(wǎng)絡(luò):

docker service create --name web_mynet --replicas=2 --network=mynet --publish 8080:80 httpd
部署的兩個容器分別處在a和c節(jié)點上:


mynet-1.png

--publish #--在這里的用意是將容器內(nèi)部的服務(wù)暴露到host上這樣我們就可以訪問這個services,一般情況下我們在swarm中部署service后容器中的網(wǎng)絡(luò)只有一張網(wǎng)卡使用的是docker0網(wǎng)絡(luò),當我們將服務(wù)發(fā)布出去后,swarm會做如下操作:

  • 給容器添加三塊網(wǎng)卡eth0和eth1,eth2,eth0連接overlay類型網(wǎng)絡(luò)名為ingress用于在不同主機間通信,eth1連接bridge類網(wǎng)絡(luò)名為docker_gwbridge,用于讓容器能訪問外網(wǎng)。eth2連接到我們自己創(chuàng)建的mynet網(wǎng)絡(luò)
    上,同樣的作用也是用于容器之間的訪問(區(qū)別于eth2網(wǎng)絡(luò)存在dns解析即服務(wù)發(fā)現(xiàn)功能)。
  • swarm各節(jié)點會利用ingress overlay網(wǎng)絡(luò)負載均衡將服務(wù)發(fā)布到集群之外。

結(jié)合例子如下:

2)、查看web_mynet.1容器和mynet網(wǎng)絡(luò)命名空間的網(wǎng)卡情況:

mynet-2.png
$docker exec web_mynet.1.kammwchnoeend86w3e5pho88i ip add
上面的命令可以查看a節(jié)點上的容器的網(wǎng)絡(luò)有四張網(wǎng)卡eth0和eth1,eth2和lo,eth2網(wǎng)卡可以看出其
對應(yīng)的veth pair為mynet網(wǎng)絡(luò)中的veth0,eth1的網(wǎng)卡比較容易找到在host上對應(yīng)的veth pair

$ip netns exec 1-j6s2r8ahdh ip add
查看mynet網(wǎng)絡(luò)命名空間下的網(wǎng)卡情況。

$ip netns exec 1-j6s2r8ahdh brctl show
查看mynet網(wǎng)絡(luò)空間下網(wǎng)橋掛載情況可以看出veth0掛到了br0網(wǎng)橋上。

3)、查看web_mynet.1容器和ingress\ingress_sbox網(wǎng)絡(luò)命名空間的網(wǎng)卡對應(yīng)情況:

mynet-3.png
  • 獲取mynet和ingress網(wǎng)絡(luò)的vxlan-id:
## 執(zhí)行如下命令查看mynet空間下vxlan0網(wǎng)卡所帶的vlan-id:
$ip netns exec 1-j6s2r8ahdh ip -d l show vxlan0

可以看mynet網(wǎng)絡(luò)下vlan-id 為4097,ingress網(wǎng)絡(luò)空間同樣操作可以得到vlan-id為4096

mynet-4.png

swarm-c節(jié)點上的情況也是差不多就不操作了,好了我們來畫下網(wǎng)絡(luò)連接的大致圖:


image.png

可以看到這里ingress_sbox和創(chuàng)建容器的ns共用一個ingress網(wǎng)絡(luò)空間。

4)、 Internal Load Balancing實現(xiàn)方式:

有兩種實現(xiàn)方式dns rr和vip形式,在dns rr 的情況下可能會存在一定是的問題,當容器重啟后dns的解析會存在一定時間的延遲。vip則是由vip+內(nèi)核ipvs來實現(xiàn)。docker swarm默認使用的是vip,這里就以vip的形式來解析。(想要了解dns rr的可以看文章后面的參考鏈接都是大牛寫的)

VIP形式下的流量路徑:

swarm-vip.jpg

1> 同處于網(wǎng)絡(luò)mynet中的容器可以通過service域名或者VIP來訪問service;通過域名訪問時,容器會訪問docker engine中內(nèi)置的DNS服務(wù),從而獲取VIP。

2> CNM網(wǎng)絡(luò)模型中一個容器對應(yīng)一個sandbox,也即容器的net namespace。我們查web_mynet.1容器的sandbox中iptables的mangle表的配置情況:mangle表中OUTPUT鏈,將destIP==VIP的包標記fwmark。

操作流程如下:
通過busybox服務(wù)做dns解析,可以發(fā)現(xiàn)該服務(wù)后端掛載的容器和該服務(wù)對應(yīng)的
VIP地址。web_mynet服務(wù)對應(yīng)的VIP為10.0.0.6。


mynet-5.png
  • 進入web_mynet.1容器的ns:
$docker inspect container_id/container_name | grep -i sandbox
$nsenter --net=SandboxKey(/var/run/docker/netns/xxxx) sh
mynet-6.png

3>web_mynet.1的 Sandbox中會設(shè)置kernel中的LVS模塊,將標記fwmark的包LB到各個實際IP中,默認round-robin算法,VS/NAT方式。容器底層間通過overlay網(wǎng)絡(luò)互連通信。在web_mynet.1的ns中執(zhí)行如下獲取LB信息:
$ipvsadm -L

mynet-7.png
  • 簡單的來說就是在web_mynet.1容器中定義好了web_mynet服務(wù)的vip數(shù)據(jù)包的標簽和LB,然后數(shù)據(jù)包通過容器本地路由從eth2接口出去,進入到mynet的ns中:
mynet-8.png
  • 帶有具體目容器的MAC數(shù)據(jù)包進入mynet的ns后,由mynet網(wǎng)絡(luò)中的fdb來進行轉(zhuǎn)發(fā):


    mynet-9.png
mynet-10.png

總結(jié)下:

在Internal Load Balancing也就是文中我們自建的mynet overlay網(wǎng)絡(luò)中,我們會看到創(chuàng)
建的service會同時應(yīng)用到兩個網(wǎng)絡(luò)環(huán)境里面去,為何要這樣呢?

原因是swarm自帶ingress不具備有服務(wù)發(fā)現(xiàn)的功能,而容器的生命周期又是不固定的,
service每次的消亡和啟用都會改變?nèi)萜鲀?nèi)部的ip地址以及vip地址,那么集群中服務(wù)之間
的通信勢必會造成問題,這里有人會說,要使多個service之間能夠互相通信可以將所有
的service都publish出去,然后通過routing mesh 訪問,這樣是沒錯也能行得通,但是存
在一個缺點,那就是不安全,我們僅僅只需要的是將最終提供服務(wù)的端口publish即可。
那么不publish所有的service需要做到以下幾點:

  • 讓service通過簡單的方法訪問其他service

  • 當service副本的ip發(fā)生變化時,不會影響訪問該service的其他service

  • 當service的副本數(shù)發(fā)生變化時,不會影響訪問該service的其他service
    這其實就是服務(wù)發(fā)現(xiàn),docker swarm提供了這些功能將LB和服務(wù)發(fā)現(xiàn)集成在一起,通過服務(wù)發(fā)現(xiàn)service,使用者不需要知道service運行在哪里,ip是多少有多少個副本,就能實現(xiàn)集群內(nèi)service與service的通信以及LB。

這里我理解的是ingress是單單提供LB實現(xiàn)routing mesh而mynet是服務(wù)發(fā)現(xiàn)和LB的結(jié)合

所以上文中Internal Load Balancing中的數(shù)據(jù)流應(yīng)該分成兩種情景如下:

1、當一個外部請求到主機端口8080之后, 數(shù)據(jù)包的流向如下所示:
主機端口8080 => Ingress-sbox-VIP:8080 => 容器Ingress-sbox => IPVS分發(fā)到containers。

2、處于 同mynet網(wǎng)絡(luò)的service內(nèi)部通信時:
處于 同mynet網(wǎng)絡(luò)的test service(busybox容器)發(fā)起訪問web_mynet域名的請求=>請求轉(zhuǎn)發(fā)到docker engine內(nèi)置的DNS解析web_mynet的vip=>web_mynet(容器)在其ns中將
VIP數(shù)據(jù)包打上標簽,并通過ipvs來負載到后端對應(yīng)的容器=>數(shù)據(jù)包通過vip地址路由到
mynet的ns,由mynet中的fdb來做轉(zhuǎn)發(fā)走tunnel出去。

文章中存在不足之處希望路過的大牛多踩踩^^!

參考:

https://zhuanlan.zhihu.com/p/25954203

http://www.lxweimin.com/p/4433f4c70cf0

https://docs.docker.com/network/overlay/

http://julyerr.club/2018/03/20/docker-swarm/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 記事起,我便生活在桃莊,卻從沒見過自己的爹娘。 那日,一片片嫩綠的芳草探出了小腦瓜,幾只燕子飛來飛去忙著筑巢。和煦...
    桃源漁歌閱讀 651評論 32 15
  • 喜歡一個人靜靜地發(fā)呆到天荒地老 如果時候至始至終都沒有那一個人的出現(xiàn), 自己有什么理由不勇敢,堅強。 時光還是匆匆...
    哆啦的A夢閱讀 138評論 0 0
  • 一、課堂的“教案劇” 中小學(xué)課堂的“教案劇”:備課時精心設(shè)問,課堂學(xué)生連續(xù)不斷地匆忙緊張地應(yīng)對教師提問 唱答式 猜...
    趙雪奎閱讀 576評論 0 0
  • By:白憶 zero.花語 所以,你是小憶,亦是憶少。 單翼的你,擁有著一只翅膀。 往右天堂,化...
    憶少閱讀 237評論 0 0
  • 隨手一畫。
    和果閱讀 151評論 0 3