1. 程式人生 > 實用技巧 >Docker網路解決方案-Flannel部署記錄

Docker網路解決方案-Flannel部署記錄

Docker跨主機容器間網路通訊實現的工具有Pipework、Flannel、Weave、Open vSwitch(虛擬交換機)、Calico實現跨主機容器間的通訊。其中Pipework、Weave、Flannel,三者的區別是:


Weave的思路

在每個宿主機上佈置一個特殊的route的容器,不同宿主機的route容器連線起來。route攔截所有普通容器的ip請求,並通過udp包傳送到其他宿主機上的普通容器。
這樣在跨機的多個容器端看到的就是同一個扁平網路。weave解決了網路問題,不過部署依然是單機的。


Flannel的思路

Flannel是CoreOS團隊針對Kubernetes設計的一個網路規劃服務,簡單來說,它的功能是讓叢集中的不同節點主機建立的Docker容器都具有全叢集唯一的虛擬IP地址。但在預設的Docker配置中,
每個節點上的Docker服務會分別負責所在節點容器的IP分配。這樣導致的一個問題是,不同節點上容器可能獲得相同的內外IP地址。並使這些容器之間能夠之間通過IP地址相互找到,也就是相
互ping通。

Flannel的設計目的就是為叢集中的所有節點重新規劃IP地址的使用規則,從而使得不同節點上的容器能夠獲得"同屬一個內網"且"不重複的"IP地址,並讓屬於不同節點上的容器能夠直接通過內網IP通訊。

Flannel實質上是一種"覆蓋網路(overlaynetwork)",即表示執行在一個網上的網(應用層網路),並不依靠ip地址來傳遞訊息,而是採用一種對映機制,把ip地址和identifiers做對映來資源定位。也就
是將TCP資料包裝在另一種網路包裡面進行路由轉發和通訊,目前已經支援UDP、VxLAN、AWSVPC和GCE路由等資料轉發方式。

原理是每個主機配置一個ip段和子網個數。例如,可以配置一個覆蓋網路使用10.100.0.0/16段,每個主機/24個子網。因此主機a可以接受10.100.5.0/24,主機B可以接受10.100.18.0/24的包。flannel使用etcd來維護分配的子網到實際的ip地址之間的對映。對於資料路徑,flannel使用udp來封裝ip資料報,轉發到遠端主機。選擇UDP作為轉發協議是因為他能穿透防火牆。例如,AWSClassic無法轉發IPoIPorGRE網路包,是因為它的安全組僅僅支援TCP/UDP/ICMP。

flannel使用etcd儲存配置資料和子網分配資訊。flannel啟動之後,後臺程序首先檢索配置和正在使用的子網列表,然後選擇一個可用的子網,然後嘗試去註冊它。
etcd也儲存這個每個主機對應的ip。flannel使用etcd的watch機制監視/coreos.com/network/subnets下面所有元素的變化資訊,並且根據他來維護一個路由表。為了提高效能,flannel優化了UniversalTAP/TUN裝置,對TUN和UDP之間的ip分片做了代理。


預設的節點間資料通訊方式是UDP轉發.在Flannel的GitHub頁面有如下的一張原理圖:

Bluemix.png

對上圖的簡單解釋:

1)資料從源容器中發出後,經由所在主機的docker0虛擬網絡卡轉發到flannel0虛擬網絡卡,這是個P2P的虛擬網絡卡,flanneld服務監聽在網絡卡的另外一端。
2)Flannel通過Etcd服務維護了一張節點間的路由表,在稍後的配置部分我們會介紹其中的內容。
3)源主機的flanneld服務將原本的資料內容UDP封裝後根據自己的路由表投遞給目的節點的flanneld服務,資料到達以後被解包,然後直接進入目的節點的flannel0虛擬網絡卡,
然後被轉發到目的主機的docker0虛擬網絡卡,最後就像本機容器通訊一下的有docker0路由到達目標容器。

這樣整個資料包的傳遞就完成了,這裡需要解釋三個問題:
1)UDP封裝是怎麼回事?
在UDP的資料內容部分其實是另一個ICMP(也就是ping命令)的資料包。原始資料是在起始節點的Flannel服務上進行UDP封裝的,投遞到目的節點後就被另一端的Flannel服務
還原成了原始的資料包,兩邊的Docker服務都感覺不到這個過程的存在。

2)為什麼每個節點上的Docker會使用不同的IP地址段?
這個事情看起來很詭異,但真相十分簡單。其實只是單純的因為Flannel通過Etcd分配了每個節點可用的IP地址段後,偷偷的修改了Docker的啟動引數。
在運行了Flannel服務的節點上可以檢視到Docker服務程序執行引數(psaux|grepdocker|grep"bip"),例如“--bip=182.48.25.1/24”這個引數,它限制了所在節
點容器獲得的IP範圍。這個IP範圍是由Flannel自動分配的,由Flannel通過儲存在Etcd服務中的記錄確保它們不會重複。

3)為什麼在傳送節點上的資料會從docker0路由到flannel0虛擬網絡卡,在目的節點會從flannel0路由到docker0虛擬網絡卡?
例如現在有一個數據包要從IP為172.17.18.2的容器發到IP為172.17.46.2的容器。根據資料傳送節點的路由表,它只與172.17.0.0/16匹配這條記錄匹配,因此資料從docker0
出來以後就被投遞到了flannel0。同理在目標節點,由於投遞的地址是一個容器,因此目的地址一定會落在docker0對於的172.17.46.0/24這個記錄上,自然的被投遞到了docker0網絡卡。


Pipework的思路

pipework是一個單機的工具,組合了brctl等工具,可以認為pipework解決的是宿主機上的設定容器的虛擬網絡卡、網橋、ip等,可以配合其他網路使用。詳情可參考:Docker網路詳解及pipework原始碼解讀與實踐

如果容器數量不多,想簡單的組一個大的3層網路,可以考慮weave
如果容器數量很多,而且你們的環境複雜,需要多個子網,可以考慮openvswitch或者fannel
weave的總體網路效能表現欠佳,flannelVXLAN能滿足要求,一般推薦用flannel


------------------------------------------------------------------------------------------------------------------------


Flannel環境部署記錄

1)機器環境(CentOS7系統)

10.10.172.201部署etcd,flannel,docker主機名:node1主控端(通過etcd)
10.10.172.202部署flannel,docker主機名:node2被控端


2)node1(10.10.172.201)機器操作

設定主機名及繫結hosts
[[email protected]~]#hostnamectl--staticset-hostnamenode1
[[email protected]~]#vim/etc/hosts
10.10.172.201node1
10.10.172.201etcd
10.10.172.202node2

關閉防火牆,如果開啟防火牆,則最好開啟2379和4001埠
[[email protected]~]#systemctldisablefirewalld.service
[[email protected]~]#systemctlstopfirewalld.service

先安裝docker環境
[[email protected]~]#yuminstalldocker-y

安裝etcd
k8s執行依賴etcd,需要先部署etcd,下面採用yum方式安裝:
[[email protected]~]#yuminstalletcd-y

yum安裝的etcd預設配置檔案在/etc/etcd/etcd.conf,編輯配置檔案:
[[email protected]~]#cp/etc/etcd/etcd.conf/etc/etcd/etcd.conf.bak
[[email protected]~]#cat/etc/etcd/etcd.conf
#[member]
ETCD_NAME=master#節點名稱
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"#資料存放位置
#ETCD_WAL_DIR=""
#ETCD_SNAPSHOT_COUNT="10000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"#監聽客戶端地址
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
#ETCD_CORS=""
#
#[cluster]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
#ifyouusedifferentETCD_NAME(e.g.test),setETCD_INITIAL_CLUSTERvalueforthisname,i.e."test=http://..."
#ETCD_INITIAL_CLUSTER="default=http://localhost:2380"
#ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd:2379,http://etcd:4001"#通知客戶端地址
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""

啟動etcd並驗證狀態
[[email protected]~]#systemctlstartetcd
[[email protected]~]#systemctlenableetcd

[[email protected]~]#ps-ef|grepetcd
etcd151481013:10?00:00:00/usr/bin/etcd--name=master#節點名稱--data-dir=/var/lib/etcd/default.etcd#資料存放位置--listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001#?聽客戶端地址
root1550615419013:11pts/000:00:00grep--color=autoetcd
[[email protected]~]#lsof-i:2379
COMMANDPIDUSERFDTYPEDEVICESIZE/OFFNODENAME
etcd15148etcd6uIPv6489110t0TCP*:2379(LISTEN)
etcd15148etcd11uIPv4480550t0TCPlocalhost:44959->localhost:2379(ESTABLISHED)
etcd15148etcd15uIPv6480610t0TCPlocalhost:2379->localhost:44959(ESTABLISHED)

[[email protected]~]#etcdctlsettestdir/testkey00
0
[[email protected]~]#etcdctlgettestdir/testkey0
0
[[email protected]~]#etcdctl-Chttp://etcd:4001cluster-health
member8e9e05c52164694dishealthy:gothealthyresultfromhttp://etcd:2379
clusterishealthy
[[email protected]~]#etcdctl-Chttp://etcd:2379cluster-health
member8e9e05c52164694dishealthy:gothealthyresultfromhttp://etcd:2379
clusterishealthy

安裝覆蓋網路Flannel
[[email protected]~]#yuminstallflannel-y

配置Flannel
[[email protected]~]#cp/etc/sysconfig/flanneld/etc/sysconfig/flanneld.bak
[[email protected]~]#vim/etc/sysconfig/flanneld
#Flanneldconfigurationoptions

#etcdurllocation.Pointthistotheserverwhereetcdruns
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"

#etcdconfigkey.Thisistheconfigurationkeythatflannelqueries
#Foraddressrangeassignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"

#Anyadditionaloptionsthatyouwanttopass
#FLANNEL_OPTIONS=""

配置etcd中關於flannel的key(這個只在安裝了etcd的機器上操作)
Flannel使用Etcd進行配置,來保證多個Flannel例項之間的配置一致性,所以需要在etcd上進行如下配置('/atomic.io/network/config'這個key與上文/etc/sysconfig/flannel中的配置項FLANNEL_ETCD_PREFIX是相對應的,錯誤的話啟動就會出錯):
[[email protected]~]#etcdctlmk/atomic.io/network/config'{"Network":"10.10.0.0/16"}'
{"Network":"10.10.0.0/16"}

溫馨提示:上面flannel設定的ip網段可以任意設定,隨便設定一個網段都可以。容器的ip就是根據這個網段進行自動分配的,ip分配後,容器一般是可以對外聯網的(網橋模式,只要宿主機能上網就可以)

啟動Flannel
[[email protected]~]#systemctlenableflanneld.service
[[email protected]~]#systemctlstartflanneld.service
[[email protected]~]#ps-ef|grepflannel
root157301013:16?00:00:00/usr/bin/flanneld-etcd-endpoints=http://etcd:2379-etcd-prefix=/atomic.io/network
root1587315419013:16pts/000:00:00grep--color=autoflannel

啟動Flannel後,一定要記得重啟docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網絡卡的ip會變成上面flannel設定的ip段
[[email protected]~]#systemctlrestartdocker
[[email protected]~]#systemctlenabledocker


3)node2(10.10.172.202)機器操作

設定主機名及繫結hosts
[[email protected]~]#hostnamectl--staticset-hostnamenode2
[[email protected]~]#vim/etc/hosts
10.10.172.201node1
10.10.172.201etcd
10.10.172.202node2

關閉防火牆,如果開啟防火牆,則最好開啟2379和4001埠
[[email protected]~]#systemctldisablefirewalld.service
[[email protected]~]#systemctlstopfirewalld.service

先安裝docker環境
[[email protected]~]#yuminstalldocker-y

安裝覆蓋網路Flannel
[[email protected]~]#yuminstallflannel-y

配置Flannel
[[email protected]~]#cp/etc/sysconfig/flanneld/etc/sysconfig/flanneld.bak
[[email protected]~]#vim/etc/sysconfig/flanneld
#Flanneldconfigurationoptions

#etcdurllocation.Pointthistotheserverwhereetcdruns
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"

#etcdconfigkey.Thisistheconfigurationkeythatflannelqueries
#Foraddressrangeassignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"

#Anyadditionaloptionsthatyouwanttopass
#FLANNEL_OPTIONS=""

啟動Flannel
[[email protected]~]#systemctlenableflanneld.service
[[email protected]~]#systemctlstartflanneld.service
[[email protected]~]#ps-ef|grepflannel
root317651013:20?00:00:00/usr/bin/flanneld-etcd-endpoints=http://etcd:2379-etcd-prefix=/atomic.io/network
root3181431576013:20pts/000:00:00grep--color=autoflannel

啟動Flannel後,一定要記得重啟docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網絡卡的ip會變成上面flannel設定的ip段
[[email protected]~]#systemctlrestartdocker
[[email protected]~]#systemctlenabledocker


4)建立容器,驗證跨主機容器之間的網路聯通性

首先在node1(10.10.172.201)上容器容器,如下,登陸容器發現已經按照上面flannel配置的分配了一個ip段(每個宿主機都會分配一個182.48.0.0/16的網段)

[[email protected]~]#dockerrun-ti-d--name=node1.testdocker.io/nginx/bin/bash
2dea24b1562f3d4dc89cde3fa00c707276edcfba1c8f3b0ab4c62e075e63de2f
[[email protected]~]#dockerexec-tinode1.test/bin/bash
[email protected]:/#apt-getupdate&&apt-getinstalliprouteiputils-ping-y
[email protected]:/#ipaddr
1:lo:<LOOPBACK,UP,LOWER_UP>mtu65536qdiscnoqueuestateUNKNOWNgroupdefault
link/loopback00:00:00:00:00:00brd00:00:00:00:00:00
inet127.0.0.1/8scopehostlo
valid_lftforeverpreferred_lftforever
inet6::1/128scopehost
valid_lftforeverpreferred_lftforever
7:[email protected]:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1472qdiscnoqueuestateUPgroupdefault
link/ether02:42:0a:0a:5c:02brdff:ff:ff:ff:ff:fflink-netnsid0
inet10.10.92.2/24scopeglobaleth0
valid_lftforeverpreferred_lftforever
inet6fe80::42:aff:fe0a:5c02/64scopelink
valid_lftforeverpreferred_lftforever


接著在node2(10.10.172.202)上容器容器
[[email protected]~]#dockerrun-ti-d--name=node2.testdocker.io/nginx/bin/bash
374417e9ce5bcd11222d8138e684707c00ca8a4b7a16243ac5cfb1a8bd19ee6e
[[email protected]~]#dockerexec-tinode2.test/bin/bash
[email protected]:/#cat/etc/debian_version
9.3
[email protected]:/#apt-getupdate&&apt-getinstalliprouteiputils-ping-y
[email protected]:/#ipaddr
1:lo:<LOOPBACK,UP,LOWER_UP>mtu65536qdiscnoqueuestateUNKNOWNgroupdefault
link/loopback00:00:00:00:00:00brd00:00:00:00:00:00
inet127.0.0.1/8scopehostlo
valid_lftforeverpreferred_lftforever
inet6::1/128scopehost
valid_lftforeverpreferred_lftforever
469:[email protected]:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1472qdiscnoqueuestateUPgroupdefault
link/ether02:42:0a:0a:1d:02brdff:ff:ff:ff:ff:fflink-netnsid0
inet10.10.29.2/24scopeglobaleth0
valid_lftforeverpreferred_lftforever
inet6fe80::42:aff:fe0a:1d02/64scopelink
valid_lftforeverpreferred_lftforever

[email protected]:/#ping10.10.92.2
PING10.10.92.2(10.10.92.2)56(84)bytesofdata.
64bytesfrom10.10.92.2:icmp_seq=1ttl=60time=0.657ms
64bytesfrom10.10.92.2:icmp_seq=2ttl=60time=0.487ms
.......

[email protected]:/#pingwww.baidu.com
PINGwww.a.shifen.com(115.239.210.27)56(84)bytesofdata.
64bytesfrom115.239.210.27(115.239.210.27):icmp_seq=1ttl=48time=11.7ms
64bytesfrom115.239.210.27(115.239.210.27):icmp_seq=2ttl=48time=12.4ms
.......

發現,在兩個宿主機的容器內,互相ping對方容器的ip,是可以ping通的!也可以直接連線外網(橋接模式)

檢視兩臺宿主機的網絡卡資訊,發現docker0虛擬網絡卡的ip(相當於容器的閘道器)也已經變成了flannel配置的ip段,並且多了flannel0的虛擬網絡卡資訊
[[email protected]~]#ifconfig
docker0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1472
inet10.10.92.1netmask255.255.255.0broadcast0.0.0.0
inet6fe80::42:ebff:fe16:438dprefixlen64scopeid0x20<link>
ether02:42:eb:16:43:8dtxqueuelen0(Ethernet)
RXpackets5944bytes337155(329.2KiB)
RXerrors0dropped0overruns0frame0
TXpackets6854bytes12310552(11.7MiB)
TXerrors0dropped0overruns0carrier0collisions0

eno16777984:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500
inet10.10.172.201netmask255.255.255.0broadcast10.10.172.255
inet6fe80::250:56ff:fe86:2135prefixlen64scopeid0x20<link>
ether00:50:56:86:21:35txqueuelen1000(Ethernet)
RXpackets98110bytes134147911(127.9MiB)
RXerrors0dropped0overruns0frame0
TXpackets60177bytes5038428(4.8MiB)
TXerrors0dropped0overruns0carrier0collisions0

flannel0:flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>mtu1472
inet10.10.92.0netmask255.255.0.0destination10.10.92.0
unspec00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00txqueuelen500(UNSPEC)
RXpackets2bytes168(168.0B)
RXerrors0dropped0overruns0frame0
TXpackets2bytes168(168.0B)
TXerrors0dropped0overruns0carrier0collisions0
.......

通過下面命令,可以檢視到本機的容器的ip所在的範圍
[[email protected]~]#psaux|grepdocker|grep"bip"
root165890.31.373491227840?Ssl13:230:04/usr/bin/dockerd-current--add-runtimedocker-runc=/usr/libexec/docker/docker-runc-current--default-runtime=docker-runc--exec-optnative.cgroupdriver=systemd--userland-proxy-path=/usr/libexec/docker/docker-proxy-current--selinux-enabled--log-driver=journald--signature-verification=false--bip=10.10.92.1/24--ip-masq=true--mtu=1472

這裡面的“--bip=10.10.92.1/24”這個引數,它限制了所在節點容器獲得的IP範圍。
這個IP範圍是由Flannel自動分配的,由Flannel通過儲存在Etcd服務中的記錄確保它們不會重複。

[[email protected]~]#ifconfig
docker0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1472
inet10.10.29.1netmask255.255.255.0broadcast0.0.0.0
inet6fe80::42:42ff:fe21:d694prefixlen64scopeid0x20<link>
ether02:42:42:21:d6:94txqueuelen0(Ethernet)
RXpackets644697bytes41398904(39.4MiB)
RXerrors0dropped0overruns0frame0
TXpackets675608bytes1683878582(1.5GiB)
TXerrors0dropped0overruns0carrier0collisions0

eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500
inet10.10.172.202netmask255.255.255.0broadcast10.10.172.255
inet6fe80::250:56ff:fe86:6833prefixlen64scopeid0x20<link>
ether00:50:56:86:68:33txqueuelen1000(Ethernet)
RXpackets2552698bytes2441204870(2.2GiB)
RXerrors0dropped104overruns0frame0
TXpackets1407162bytes3205869301(2.9GiB)
TXerrors0dropped0overruns0carrier0collisions0

flannel0:flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>mtu1472
inet10.10.29.0netmask255.255.0.0destination10.10.29.0
unspec00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00txqueuelen500(UNSPEC)
RXpackets2bytes168(168.0B)
RXerrors0dropped0overruns0frame0
TXpackets2bytes168(168.0B)
TXerrors0dropped0overruns0carrier0collisions0
.......		
[[email protected]~]#psaux|grepdocker|grep"bip"
root319250.31.774740435864?Ssl13:210:05/usr/bin/dockerd-current--add-runtimedocker-runc=/usr/libexec/docker/docker-runc-current--default-runtime=docker-runc--exec-optnative.cgroupdriver=systemd--userland-proxy-path=/usr/libexec/docker/docker-proxy-current--selinux-enabled--log-driver=journald--signature-verification=false--bip=10.10.29.1/24--ip-masq=true--mtu=1472		


轉載於:https://blog.51cto.com/dengaosky/2069377