flannel是CoreOS提供用于解決Dokcer集群跨主機(jī)通訊的覆蓋網(wǎng)絡(luò)工具。它的主要思路是:預(yù)先留出一個(gè)網(wǎng)段,每個(gè)主機(jī)使用其中一部分,然后每個(gè)容器被分配不同的ip;讓所有的容器認(rèn)為大家在同一個(gè)直連的網(wǎng)絡(luò),底層通過UDP/VxLAN
等進(jìn)行報(bào)文的封裝和轉(zhuǎn)發(fā)。
flannel項(xiàng)目地址:https://github.com/coreos/flannel
flannel架構(gòu)介紹
flannel默認(rèn)使用8285端口作為UDP
封裝報(bào)文的端口,VxLan使用8472端口。
那么一條網(wǎng)絡(luò)報(bào)文是怎么從一個(gè)容器發(fā)送到另外一個(gè)容器的呢?
容器直接使用目標(biāo)容器的ip訪問,默認(rèn)通過容器內(nèi)部的eth0發(fā)送出去。
報(bào)文通過veth pair
被發(fā)送到vethXXX
。
vethXXX
是直接連接到虛擬交換機(jī)docker0
的,報(bào)文通過虛擬bridge docker0
發(fā)送出去。
查找路由表,外部容器ip的報(bào)文都會(huì)轉(zhuǎn)發(fā)到flannel0
虛擬網(wǎng)卡,這是一個(gè)P2P
的虛擬網(wǎng)卡,然后報(bào)文就被轉(zhuǎn)發(fā)到監(jiān)聽在另一端的flanneld
。
flanneld
通過etcd
維護(hù)了各個(gè)節(jié)點(diǎn)之間的路由表,把原來(lái)的報(bào)文UDP
封裝一層,通過配置的iface
發(fā)送出去。
報(bào)文通過主機(jī)之間的網(wǎng)絡(luò)找到目標(biāo)主機(jī)。
報(bào)文繼續(xù)往上,到傳輸層,交給監(jiān)聽在8285端口的flanneld
程序處理。
數(shù)據(jù)被解包,然后發(fā)送給flannel0
虛擬網(wǎng)卡。
查找路由表,發(fā)現(xiàn)對(duì)應(yīng)容器的報(bào)文要交給docker0
。
docker0
找到連到自己的容器,把報(bào)文發(fā)送過去。
flannel安裝配置
環(huán)境準(zhǔn)備
一共三臺(tái)機(jī)器:一個(gè)etcd集群,三臺(tái)機(jī)器安裝flannel和Docker。
節(jié)點(diǎn)名稱
IP地址
軟件環(huán)境
etcd1
192.168.2.210
etcd、flannel、docker
etcd2
192.168.2.211
etcd、flannel、docker
etcd3
192.168.2.212
etcd、flannel、docker
安裝etcd
關(guān)于etcd的安裝使用已經(jīng)在「etcd使用入門」和「通過靜態(tài)發(fā)現(xiàn)方式部署etcd集群」中做了比較詳細(xì)的講解,如果你還不會(huì)安裝etcd可先閱讀下這兩篇文章。這里就不再重復(fù)講解了。
安裝flannel
三個(gè)節(jié)點(diǎn)都需安裝配置flannel,這里以etcd1節(jié)點(diǎn)為例。
flannel和etcd一樣,直接從官方下載二進(jìn)制執(zhí)行文件就可以用了。當(dāng)然,你也可以自己編譯。
1
2
3
$ curl -L https://github.com/coreos/flannel/releases/download/v0.7.0/flannel-v0.7.0-linux-amd64.tar.gz -o flannel.tar.gz
$ mkdir -p /opt/flannel
$ tar xzf flannel.tar.gz -C /opt/flannel
解壓后主要有flanneld
、mk-docker-opts.sh
這兩個(gè)文件,其中flanneld
為主要的執(zhí)行文件,sh腳本用于生成Docker啟動(dòng)參數(shù)。
配置flannel
由于flannel
需要依賴etcd
來(lái)保證集群IP分配不沖突的問題,所以首先要在etcd
中設(shè)置 flannel
節(jié)點(diǎn)所使用的IP段。
1
2
3
4
$ etcdctl --endpoints "http://etcd1.hi-linux.com:2379"
set /coreos.com/network/config '{"NetWork":"10.0.0.0/16", "SubnetMin": "10.0.1.0", "SubnetMax": "10.0.20.0"}'
{"NetWork":"10.0.0.0/16", "SubnetMin": "10.0.1.0", "SubnetMax": "10.0.20.0"}
flannel預(yù)設(shè)的backend type
是udp,如果想要使用vxlan
作為backend
,可以加上backend
參數(shù):
1
2
$ etcdctl --endpoints "http://etcd1.hi-linux.com:2379"
set /coreos.com/network/config '{"NetWork":"10.0.0.0/16", "Backend": {"Type": "vxlan"}}'
flannel backend為vxlan比起預(yù)設(shè)的udp性能相對(duì)好一些。
啟動(dòng)flannel
命令行方式運(yùn)行
1
$ /opt/flannel/flanneld --etcd-endpoints="http://etcd1.hi-linux.com:2379" --ip-masq=true >> /var/log/flanneld.log 2>&1 &
后臺(tái)服務(wù)方式運(yùn)行
給flannel創(chuàng)建一個(gè)systemd服務(wù),方便以后管理。創(chuàng)建flannel配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat <<EOF | sudo tee /etc/systemd/system/flanneld.service
[Unit]
Description=Flanneld
Documentation=https://github.com/coreos/flannel
After=network.target
Before=docker.service
[Service]
User=root
ExecStart=/opt/flannel/flanneld
--etcd-endpoints="http://etcd1.hi-linux.com:2379,http://etcd2.hi-linux.com:2379,http://etcd3.hi-linux.com:2379"
--iface=192.168.2.210
--ip-masq
Restart=on-failure
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
注意:--iface
參數(shù)為要綁定的網(wǎng)卡的IP地址,請(qǐng)根據(jù)實(shí)際情況修改。
啟動(dòng)flannel服務(wù)
1
$ systemctl start flanneld
flannel啟動(dòng)過程解析
flannel服務(wù)需要先于Docker啟動(dòng)。flannel服務(wù)啟動(dòng)時(shí)主要做了以下幾步的工作:
從etcd中獲取network的配置信息。
劃分subnet,并在etcd中進(jìn)行注冊(cè)。
將子網(wǎng)信息記錄到/run/flannel/subnet.env
中。
驗(yàn)證flannel網(wǎng)絡(luò)
在etcd1節(jié)點(diǎn)上看etcd中的內(nèi)容
1
2
3
$ etcdctl --endpoints "http://etcd1.hi-linux.com:2379" ls /coreos.com/network/subnets
/coreos.com/network/subnets/10.0.2.0-24
查看flannel0的網(wǎng)絡(luò)情況:
1
2
3
4
5
6
7
8
$ ifconfig flannel0
flannel0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.0.2.0 P-t-P:10.0.2.0 Mask:255.255.0.0
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1472 Metric:1
RX packets:85 errors:0 dropped:0 overruns:0 frame:0
TX packets:75 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:7140 (7.1 KB) TX bytes:6300 (6.3 KB)
可以看到flannel0網(wǎng)卡的地址和etcd中存儲(chǔ)的地址一樣,這樣flannel網(wǎng)絡(luò)配置完成。
配置Docker
在各個(gè)節(jié)點(diǎn)安裝好以后最后要更改Docker
的啟動(dòng)參數(shù),使其能夠使用flannel
進(jìn)行IP分配,以及網(wǎng)絡(luò)通訊。
flannel
運(yùn)行后會(huì)生成一個(gè)環(huán)境變量文件,包含了當(dāng)前主機(jī)要使用flannel
通訊的相關(guān)參數(shù)。
查看flannel分配的網(wǎng)絡(luò)參數(shù)
1
2
3
4
5
6
$ cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.0.0.0/16
FLANNEL_SUBNET=10.0.2.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=true
創(chuàng)建Docker運(yùn)行參數(shù)
使用flannel提供的腳本將subnet.env轉(zhuǎn)寫成Docker啟動(dòng)參數(shù),創(chuàng)建好的啟動(dòng)參數(shù)位于/run/docker_opts.env
文件中。
1
2
3
4
$ /opt/flannel/mk-docker-opts.sh -d /run/docker_opts.env -c
$ cat /run/docker_opts.env
DOCKER_OPTS=" --bip=10.0.2.1/24 --ip-masq=false --mtu=1472"
修改Docker啟動(dòng)參數(shù)
修改docker的啟動(dòng)參數(shù),并使其啟動(dòng)后使用由flannel生成的配置參數(shù),修改如下:
1
2
3
4
5
6
編輯 systemd service 配置文件
$ vim /lib/systemd/system/docker.service
在啟動(dòng)時(shí)增加flannel提供的啟動(dòng)參數(shù)
ExecStart=/usr/bin/dockerd $DOCKER_OPTS
指定這些啟動(dòng)參數(shù)所在的文件位置(這個(gè)配置是新增的,同樣放在Service標(biāo)簽下)
EnvironmentFile=/run/docker_opts.env
然后重新加載systemd配置,并重啟Docker
即可
1
2
$ systemctl daemon-reload
$ systemctl restart docker
此時(shí)可以看到docker0
的網(wǎng)卡ip地址已經(jīng)處于flannel
網(wǎng)卡網(wǎng)段之內(nèi)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ifconfig flannel0
flannel0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.0.2.0 P-t-P:10.0.2.0 Mask:255.255.0.0
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1472 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
$ ifconfig docker0
docker0 Link encap:Ethernet HWaddr 02:42:cf:87:3c:f7
inet addr:10.0.2.1 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
到此節(jié)點(diǎn)etcd1的flannel安裝配置完成了,其它兩節(jié)點(diǎn)按以上方法配置完成就行了。
測(cè)試flannel
三臺(tái)機(jī)器都配置好了之后,我們?cè)谌_(tái)機(jī)器上分別開啟一個(gè)docker容器,測(cè)試它們的網(wǎng)絡(luò)是否可相互聯(lián)通的。
etcd1
1
2
3
4
5
$ docker run -it busybox sh
查看容器IP
$ cat /etc/hosts
10.0.2.2 9de86bfde6cc
etcd2
1
2
3
4
5
$ docker run -it busybox sh
查看容器IP
$ cat /etc/hosts
10.0.5.2 9ddd4a4e455b
etcd3
1
2
3
4
5
$ docker run -it busybox sh
查看容器IP
$ cat /etc/hosts
10.0.6.2 cbb0d891f353
從不同宿主機(jī)容器到三臺(tái)宿主機(jī)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/ # ping -c3 192.168.2.210
PING 192.168.2.210 (192.168.2.210): 56 data bytes
64 bytes from 192.168.2.210: seq=0 ttl=64 time=0.089 ms
64 bytes from 192.168.2.210: seq=1 ttl=64 time=0.065 ms
/ # ping -c5 192.168.2.211
PING 192.168.2.211 (192.168.2.211): 56 data bytes
64 bytes from 192.168.2.211: seq=0 ttl=63 time=1.712 ms
64 bytes from 192.168.2.211: seq=1 ttl=63 time=0.356 ms
64 bytes from 192.168.2.211: seq=2 ttl=63 time=2.201 ms
/ # ping -c3 192.168.2.212
PING 192.168.2.212 (192.168.2.212): 56 data bytes
64 bytes from 192.168.2.212: seq=0 ttl=63 time=0.467 ms
64 bytes from 192.168.2.212: seq=1 ttl=63 time=0.477 ms
64 bytes from 192.168.2.212: seq=2 ttl=63 time=0.532 ms
從容器到到跨宿主機(jī)容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/ # ping -c3 10.0.5.2
PING 10.0.5.2 (10.0.5.2): 56 data bytes
64 bytes from 10.0.5.2: seq=0 ttl=60 time=0.692 ms
64 bytes from 10.0.5.2: seq=1 ttl=60 time=0.565 ms
64 bytes from 10.0.5.2: seq=2 ttl=60 time=1.135 ms
/ # ping -c3 10.0.6.2
PING 10.0.6.2 (10.0.6.2): 56 data bytes
64 bytes from 10.0.6.2: seq=0 ttl=60 time=0.678 ms
64 bytes from 10.0.6.2: seq=1 ttl=60 time=0.907 ms
64 bytes from 10.0.6.2: seq=2 ttl=60 time=1.272 ms
/ # ping -c3 10.0.2.2
PING 10.0.2.2 (10.0.2.2): 56 data bytes
64 bytes from 10.0.2.2: seq=0 ttl=60 time=0.644 ms
64 bytes from 10.0.2.2: seq=1 ttl=60 time=0.915 ms
64 bytes from 10.0.2.2: seq=2 ttl=60 time=1.032 ms
測(cè)試容器到到跨宿主機(jī)容器遇到一個(gè)坑,開始怎么都不通,后找到原因是宿主機(jī)iptables
給阻擋掉了。附:Ubuntu一鍵清除iptables規(guī)則腳本
1
2
3
4
5
6
7
8
9
10
$ cat clear_iptables_rule.sh
!/bin/bash
iptables -F
iptables -X
iptables -Z
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
參考文檔
http://www.google.comhttp://t.cn/RcnGQ02http://t.cn/RXVHGpIhttp://t.cn/RXfavPGhttp://t.cn/RXfEThAhttp://t.cn/RXfEmS8http://t.cn/R5Xgfnx
