1. 程式人生 > >Docker網絡解決方案-Flannel部署記錄

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

覆蓋 ssl oca wall stop 簡單的 eth0 location http

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實質上是一種"覆蓋網絡(overlay network)",即表示運行在一個網上的網(應用層網絡),並不依靠ip地址來傳遞消息,而是采用一種映射機制,把ip地址和identifiers做映射來資源定位。也就
是將TCP數據包裝在另一種網絡包裏面進行路由轉發和通信,目前已經支持UDP、VxLAN、AWS VPC和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作為轉發協議是因為他能穿透防火墻。例如,AWS Classic無法轉發IPoIP or GRE 網絡包,是因為它的安全組僅僅支持TCP/UDP/ICMP。
 
flannel 使用etcd存儲配置數據和子網分配信息。flannel 啟動之後,後臺進程首先檢索配置和正在使用的子網列表,然後選擇一個可用的子網,然後嘗試去註冊它。
etcd也存儲這個每個主機對應的ip。flannel 使用etcd的watch機制監視/coreos.com/network/subnets下面所有元素的變化信息,並且根據他來維護一個路由表。為了提高性能,flannel優化了Universal TAP/TUN設備,對TUN和UDP之間的ip分片做了代理。


默認的節點間數據通信方式是UDP轉發.在Flannel的GitHub頁面有如下的一張原理圖:

技術分享圖片

對上圖的簡單解釋:

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服務進程運行參數(ps aux|grep docker|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
如果容器數量很多,而且你們的環境復雜,需要多個子網,可以考慮open vswitch或者fannel
weave的總體網絡性能表現欠佳, flannel VXLAN 能滿足要求,一般推薦用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
[root@node1 ~]# hostnamectl --static set-hostname  node1
[root@node1 ~]# vim /etc/hosts
10.10.172.201    node1
10.10.172.201    etcd
10.10.172.202    node2
  
關閉防火墻,如果開啟防火墻,則最好打開2379和4001端口
[root@node1 ~]# systemctl disable firewalld.service
[root@node1 ~]# systemctl stop firewalld.service
  
先安裝docker環境
[root@node1 ~]# yum install docker -y
  
安裝etcd
k8s運行依賴etcd,需要先部署etcd,下面采用yum方式安裝:
[root@node1 ~]# yum install etcd -y
    
yum安裝的etcd默認配置文件在/etc/etcd/etcd.conf,編輯配置文件:
[root@node1 ~]# cp /etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak
[root@node1 ~]# 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"
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, 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並驗證狀態
[root@node1 ~]# systemctl start etcd
[root@node1 ~]# systemctl enable etcd
    
[root@node1 ~]# ps -ef|grep etcd
etcd     15148     1  0 13: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#?聽客戶端地址
root     15506 15419  0 13:11 pts/0    00:00:00 grep --color=auto etcd
[root@node1 ~]# lsof -i:2379
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
etcd    15148 etcd    6u  IPv6  48911      0t0  TCP *:2379 (LISTEN)
etcd    15148 etcd   11u  IPv4  48055      0t0  TCP localhost:44959->localhost:2379 (ESTABLISHED)
etcd    15148 etcd   15u  IPv6  48061      0t0  TCP localhost:2379->localhost:44959 (ESTABLISHED)
    
[root@node1 ~]# etcdctl set testdir/testkey0 0
0
[root@node1 ~]# etcdctl get testdir/testkey0
0
[root@node1 ~]# etcdctl -C http://etcd:4001 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
[root@node1 ~]# etcdctl -C http://etcd:2379 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
  
安裝覆蓋網絡Flannel
[root@node1 ~]# yum install flannel -y
   
配置Flannel
[root@node1 ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak
[root@node1 ~]# vim /etc/sysconfig/flanneld
# Flanneld configuration options
   
# etcd url location.  Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"
   
# etcd config key.  This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"
   
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""
  
配置etcd中關於flannel的key(這個只在安裝了etcd的機器上操作)
Flannel使用Etcd進行配置,來保證多個Flannel實例之間的配置一致性,所以需要在etcd上進行如下配置('/atomic.io/network/config'這個key與上文/etc/sysconfig/flannel中的配置項FLANNEL_ETCD_PREFIX是相對應的,錯誤的話啟動就會出錯):
[root@node1 ~]# etcdctl mk /atomic.io/network/config '{ "Network": "10.10.0.0/16" }'    
{ "Network": "10.10.0.0/16" }
 
溫馨提示:上面flannel設置的ip網段可以任意設定,隨便設定一個網段都可以。容器的ip就是根據這個網段進行自動分配的,ip分配後,容器一般是可以對外聯網的(網橋模式,只要宿主機能上網就可以)
  
啟動Flannel
[root@node1 ~]# systemctl enable flanneld.service
[root@node1 ~]# systemctl start flanneld.service
[root@node1 ~]# ps -ef|grep flannel
root     15730     1  0 13:16 ?        00:00:00 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network
root     15873 15419  0 13:16 pts/0    00:00:00 grep --color=auto flannel
 
啟動Flannel後,一定要記得重啟docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網卡的ip會變成上面flannel設定的ip段
[root@node1 ~]# systemctl restart docker
[root@node1 ~]# systemctl enable docker


3)node2(10.10.172.202)機器操作

設置主機名及綁定hosts
[root@node2 ~]# hostnamectl --static set-hostname  node2
[root@node2 ~]# vim /etc/hosts
10.10.172.201    node1
10.10.172.201    etcd
10.10.172.202    node2
  
關閉防火墻,如果開啟防火墻,則最好打開2379和4001端口
[root@node2 ~]# systemctl disable firewalld.service
[root@node2 ~]# systemctl stop firewalld.service
  
先安裝docker環境
[root@node2 ~]# yum install docker -y
  
安裝覆蓋網絡Flannel
[root@node2 ~]# yum install flannel -y
   
配置Flannel
[root@node2 ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak
[root@node2 ~]# vim /etc/sysconfig/flanneld
# Flanneld configuration options
   
# etcd url location.  Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"
   
# etcd config key.  This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"
   
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""
  
啟動Flannel
[root@node2 ~]# systemctl enable flanneld.service
[root@node2 ~]# systemctl start flanneld.service
[root@node2 ~]# ps -ef|grep flannel
root     31765     1  0 13:20 ?        00:00:00 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network
root     31814 31576  0 13:20 pts/0    00:00:00 grep --color=auto flannel
 
啟動Flannel後,一定要記得重啟docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網卡的ip會變成上面flannel設定的ip段
[root@node2 ~]# systemctl restart docker
[root@node2 ~]# systemctl enable docker


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

首先在node1(10.10.172.201)上容器容器,如下,登陸容器發現已經按照上面flannel配置的分配了一個ip段(每個宿主機都會分配一個182.48.0.0/16的網段)
   
[root@node1 ~]# docker run -ti -d --name=node1.test docker.io/nginx /bin/bash
2dea24b1562f3d4dc89cde3fa00c707276edcfba1c8f3b0ab4c62e075e63de2f
[root@node1 ~]# docker exec -ti node1.test /bin/bash
root@2dea24b1562f:/# apt-get update && apt-get install iproute iputils-ping -y
root@2dea24b1562f:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:5c:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.92.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe0a:5c02/64 scope link 
       valid_lft forever preferred_lft forever
   
   
接著在node2(10.10.172.202)上容器容器
[root@node2 ~]# docker run -ti -d --name=node2.test docker.io/nginx /bin/bash
374417e9ce5bcd11222d8138e684707c00ca8a4b7a16243ac5cfb1a8bd19ee6e
[root@node2 ~]# docker exec -ti node2.test /bin/bash
root@374417e9ce5b:/# cat /etc/debian_version 
9.3
root@374417e9ce5b:/# apt-get update && apt-get install iproute iputils-ping -y
root@374417e9ce5b:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
469: eth0@if470: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:1d:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.29.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe0a:1d02/64 scope link 
       valid_lft forever preferred_lft forever
   
root@374417e9ce5b:/# ping 10.10.92.2
PING 10.10.92.2 (10.10.92.2) 56(84) bytes of data.
64 bytes from 10.10.92.2: icmp_seq=1 ttl=60 time=0.657 ms
64 bytes from 10.10.92.2: icmp_seq=2 ttl=60 time=0.487 ms
.......
 
root@374417e9ce5b:/# ping www.baidu.com
PING www.a.shifen.com (115.239.210.27) 56(84) bytes of data.
64 bytes from 115.239.210.27 (115.239.210.27): icmp_seq=1 ttl=48 time=11.7 ms
64 bytes from 115.239.210.27 (115.239.210.27): icmp_seq=2 ttl=48 time=12.4 ms
.......
 
發現,在兩個宿主機的容器內,互相ping對方容器的ip,是可以ping通的!也可以直接連接外網(橋接模式)
   
查看兩臺宿主機的網卡信息,發現docker0虛擬網卡的ip(相當於容器的網關)也已經變成了flannel配置的ip段,並且多了flannel0的虛擬網卡信息
[root@node1 ~]# ifconfig 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1472
        inet 10.10.92.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::42:ebff:fe16:438d  prefixlen 64  scopeid 0x20<link>
        ether 02:42:eb:16:43:8d  txqueuelen 0  (Ethernet)
        RX packets 5944  bytes 337155 (329.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6854  bytes 12310552 (11.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eno16777984: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.172.201  netmask 255.255.255.0  broadcast 10.10.172.255
        inet6 fe80::250:56ff:fe86:2135  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:86:21:35  txqueuelen 1000  (Ethernet)
        RX packets 98110  bytes 134147911 (127.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 60177  bytes 5038428 (4.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 10.10.92.0  netmask 255.255.0.0  destination 10.10.92.0
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 2  bytes 168 (168.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2  bytes 168 (168.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
.......  
  
通過下面命令,可以查看到本機的容器的ip所在的範圍
[root@node1 ~]# ps aux|grep docker|grep "bip"
root     16589  0.3  1.3 734912 27840 ?        Ssl  13:23   0:04 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.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服務中的記錄確保它們不會重復。

[root@node2 ~]# ifconfig 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1472
        inet 10.10.29.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::42:42ff:fe21:d694  prefixlen 64  scopeid 0x20<link>
        ether 02:42:42:21:d6:94  txqueuelen 0  (Ethernet)
        RX packets 644697  bytes 41398904 (39.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 675608  bytes 1683878582 (1.5 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.172.202  netmask 255.255.255.0  broadcast 10.10.172.255
        inet6 fe80::250:56ff:fe86:6833  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:86:68:33  txqueuelen 1000  (Ethernet)
        RX packets 2552698  bytes 2441204870 (2.2 GiB)
        RX errors 0  dropped 104  overruns 0  frame 0
        TX packets 1407162  bytes 3205869301 (2.9 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 10.10.29.0  netmask 255.255.0.0  destination 10.10.29.0
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 2  bytes 168 (168.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2  bytes 168 (168.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
.......		
[root@node2 ~]# ps aux|grep docker|grep "bip"
root     31925  0.3  1.7 747404 35864 ?        Ssl  13:21   0:05 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.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		


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