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

 

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

Weave的思路
在每一個宿主機上佈置一個特殊的route的容器,不一樣宿主機的route容器鏈接起來。 route攔截全部普通容器的ip請求,並經過udp包發送到其餘宿主機上的普通容器。這樣在跨機的多個容器端看到的就是同一個扁平網絡。 weave解決了網絡問題,不過部署依然是單機的。 linux

Flannel的思路
Flannel是CoreOS團隊針對Kubernetes設計的一個網絡規劃服務,簡單來講,它的功能是讓集羣中的不一樣節點主機建立的Docker容器都具備全集羣惟一的虛擬IP地址。但在默認的Docker配置中,每一個節點上的Docker服務會分別負責所在節點容器的IP分配。這樣致使的一個問題是,不一樣節點上容器可能得到相同的內外IP地址。並使這些容器之間可以之間經過IP地址相互找到,也就是相互ping通。Flannel設計目的就是爲集羣中全部節點從新規劃IP地址的使用規則,從而使得不一樣節點上的容器可以得到"同屬一個內網"且"不重複的"IP地址,並讓屬於不一樣節點上的容器可以直接經過內網IP通訊。nginx

Flannel實質上是一種"覆蓋網絡(overlay network)",即表示運行在一個網上的網(應用層網絡),並不依靠ip地址來傳遞消息,而是採用一種映射機制,把ip地址和identifiers作映射來資源定位。也就是將TCP數據包裝在另外一種網絡包裏面進行路由轉發和通訊,目前已經支持UDP、VxLAN、AWS VPC和GCE路由等數據轉發方式。docker

Flannel 使用etcd存儲配置數據和子網分配信息。flannel 啓動以後,後臺進程首先檢索配置和正在使用的子網列表,而後選擇一個可用的子網,而後嘗試去註冊它。etcd也存儲這個每一個主機對應的ip。flannel 使用etcd的watch機制監視/coreos.com/network/subnets下面全部元素的變化信息,而且根據它來維護一個路由表。爲了提升性能,flannel優化了Universal TAP/TUN設備,對TUN和UDP之間的ip分片作了代理。vim

Flannel工做原理
每一個主機配置一個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工做原理流程圖以下 (默認的節點間數據通訊方式是UDP轉發;  flannel默認使用8285端口做爲UDP封裝報文的端口,VxLan使用8472端口)centos

對上圖的簡單說明 (Flannel的工做原理能夠解釋以下):
-> 數據從源容器中發出後,經由所在主機的docker0虛擬網卡轉發到flannel0虛擬網卡,這是個P2P的虛擬網卡,flanneld服務監聽在網卡的另一端。
-> Flannel經過Etcd服務維護了一張節點間的路由表,該張表裏保存了各個節點主機的子網網段信息。
-> 源主機的flanneld服務將本來的數據內容UDP封裝後根據本身的路由表投遞給目的節點的flanneld服務,數據到達之後被解包,而後直接進入目的節點的flannel0虛擬網卡,而後被轉發到目的主機的docker0虛擬網卡,最後就像本機容器通訊同樣的由docker0路由到達目標容器。安全

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

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網卡。ide

pipework的思路
pipework是一個單機的工具,組合了brctl等工具,能夠認爲pipework解決的是宿主機上的設置容器的虛擬網卡、網橋、ip等,能夠配合其餘網絡使用。

若是容器數量很少,想簡單的組一個大的3層網絡,能夠考慮weave
若是容器數量不少,並且大家的環境複雜,須要多個子網,能夠考慮open vswitch或者fannel
weave的整體網絡性能表現欠佳, flannel VXLAN 能知足要求,通常推薦用flannel

Flannel環境部署記錄

1)機器環境(centos7系統)

182.48.115.233     部署etcd,flannel,docker      主機名:node-1   主控端(經過etcd) 
182.48.115.235     部署flannel,docker            主機名:node-2   被控端

2)node-1(182.48.115.233)機器操做

設置主機名及綁定hosts
[root@node-1 ~]# hostnamectl --static set-hostname  node-1
[root@node-1 ~]# vim /etc/hosts
182.48.115.233    node-1
182.48.115.233    etcd
182.48.115.235    node-2
 
關閉防火牆,若是開啓防火牆,則最好打開2379和4001端口
[root@node-1 ~]# systemctl disable firewalld.service
[root@node-1 ~]# systemctl stop firewalld.service
 
先安裝docker環境
[root@node-1 ~]# yum install -y docker
 
安裝etcd
k8s運行依賴etcd,須要先部署etcd,下面採用yum方式安裝:
[root@node-1 ~]# yum install etcd -y
   
yum安裝的etcd默認配置文件在/etc/etcd/etcd.conf,編輯配置文件:
[root@node-1 ~]# cp /etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak
[root@node-1 ~]# 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@node-1 ~]# systemctl start etcd
   
[root@node-1 ~]# ps -ef|grep etcd
etcd     28145     1  1 14:38 ?        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     28185 24819  0 14:38 pts/1    00:00:00 grep --color=auto etcd
[root@node-1 ~]# lsof -i:2379
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
etcd    28145 etcd    6u  IPv6 1283822      0t0  TCP *:2379 (LISTEN)
etcd    28145 etcd   18u  IPv6 1284133      0t0  TCP localhost:53203->localhost:2379 (ESTABLISHED)
........
   
[root@node-1 ~]# etcdctl set testdir/testkey0 0
0
[root@node-1 ~]# etcdctl get testdir/testkey0
0
[root@node-1 ~]# etcdctl -C http://etcd:4001 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
[root@node-1 ~]# etcdctl -C http://etcd:2379 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
 
安裝覆蓋網絡Flannel
[root@node-1 ~]# yum install flannel
  
配置Flannel
[root@node-1 ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak
[root@node-1 ~]# 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@node-1 ~]# etcdctl mk /atomic.io/network/config '{ "Network": "182.48.0.0/16" }'
{ "Network": "182.48.0.0/16" }

舒適提示:上面flannel設置的ip網段能夠任意設定,隨便設定一個網段均可以。容器的ip就是根據這個網段進行自動分配的,ip分配後,容器通常是能夠對外聯網的(網橋模式,只要宿主機能上網就能夠)
 
啓動Flannel
[root@node-1 ~]# systemctl enable flanneld.service
[root@node-1 ~]# systemctl start flanneld.service
[root@node-1 ~]# ps -ef|grep flannel
root      9305  9085  0 09:12 pts/2    00:00:00 grep --color=auto flannel
root     28876     1  0 May15 ?        00:00:07 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network

啓動Flannel後,必定要記得重啓docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網卡的ip會變成上面flannel設定的ip段
[root@node-1 ~]# systemctl restart docker

3)node-2(182.48.115.235)機器操做

設置主機名及綁定hosts
[root@node-2 ~]# hostnamectl --static set-hostname  node-2
[root@node-2 ~]# vim /etc/hosts
182.48.115.233    node-1
182.48.115.233    etcd
182.48.115.235    node-2
 
關閉防火牆,若是開啓防火牆,則最好打開2379和4001端口
[root@node-2 ~]# systemctl disable firewalld.service
[root@node-2 ~]# systemctl stop firewalld.service
 
先安裝docker環境
[root@node-2 ~]# yum install -y docker
 
安裝覆蓋網絡Flannel
[root@node-2 ~]# yum install flannel
  
配置Flannel
[root@node-2 ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak
[root@node-2 ~]# 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@node-2 ~]# systemctl enable flanneld.service
[root@node-2 ~]# systemctl start flanneld.service
[root@node-2 ~]# ps -ef|grep flannel
root      3841  9649  0 09:11 pts/0    00:00:00 grep --color=auto flannel
root     28995     1  0 May15 ?        00:00:07 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network

啓動Flannel後,必定要記得重啓docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網卡的ip會變成上面flannel設定的ip段
[root@node-2 ~]# systemctl restart docker

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

首先在node-1(182.48.115.233)上容器容器,以下,登錄容器發現已經按照上面flannel配置的分配了一個ip段(每一個宿主機都會分配一個182.48.0.0/16的網段)
  
[root@node-1 ~]# docker run -ti -d --name=node-1.test docker.io/nginx /bin/bash
5e403bf93857fa28b42c9e2abaa5781be4e2bc118ba0c25cb6355b9793dd107e
[root@node-1 ~]# docker exec -ti node-1.test /bin/bash
root@5e403bf93857:/# 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
2953: eth0@if2954: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default
    link/ether 02:42:b6:30:19:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 182.48.25.4/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:b6ff:fe30:1904/64 scope link
       valid_lft forever preferred_lft forever
  
  
接着在node-2(182.48.115.233)上容器容器
[root@node-2 ~]# docker exec -ti node-2.test /bin/bash
root@052a6a2a4a19:/# 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
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default
    link/ether 02:42:b6:30:43:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 182.48.67.3/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:b6ff:fe30:4303/64 scope link
       valid_lft forever preferred_lft forever
  
root@052a6a2a4a19:/# ping 182.48.25.4
PING 182.48.25.4 (182.48.25.4): 56 data bytes
64 bytes from 182.48.25.4: icmp_seq=0 ttl=60 time=2.463 ms
64 bytes from 182.48.25.4: icmp_seq=1 ttl=60 time=1.211 ms
.......

root@052a6a2a4a19:/# ping www.baidu.com
PING www.a.shifen.com (14.215.177.37): 56 data bytes
64 bytes from 14.215.177.37: icmp_seq=0 ttl=51 time=39.404 ms
64 bytes from 14.215.177.37: icmp_seq=1 ttl=51 time=39.437 ms
.......

發現,在兩個宿主機的容器內,互相ping對方容器的ip,是能夠ping通的!也能夠直接鏈接外網(橋接模式)
  
查看兩臺宿主機的網卡信息,發現docker0虛擬網卡的ip(至關於容器的網關)也已經變成了flannel配置的ip段,而且多了flannel0的虛擬網卡信息
[root@node-1 ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1472
        inet 182.48.25.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::42:31ff:fe0f:cf0f  prefixlen 64  scopeid 0x20<link>
        ether 02:42:31:0f:cf:0f  txqueuelen 0  (Ethernet)
        RX packets 48  bytes 2952 (2.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 31  bytes 2286 (2.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 182.48.115.233  netmask 255.255.255.224  broadcast 182.48.115.255
        inet6 fe80::5054:ff:fe34:782  prefixlen 64  scopeid 0x20<link>
        ether 52:54:00:34:07:82  txqueuelen 1000  (Ethernet)
        RX packets 10759798  bytes 2286314897 (2.1 GiB)
        RX errors 0  dropped 40  overruns 0  frame 0
        TX packets 21978639  bytes 1889026515 (1.7 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 182.48.25.0  netmask 255.255.0.0  destination 182.48.25.0
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 12  bytes 1008 (1008.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12  bytes 1008 (1008.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
 
經過下面命令,能夠查看到本機的容器的ip所在的範圍
[root@node-1 ~]# ps aux|grep docker|grep "bip"
root      2080  0.0  1.4 796864 28168 ?        Ssl  May15   0:18 /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 --insecure-registry registry:5000 --bip=182.48.25.1/24 --ip-masq=true --mtu=1472
 
這裏面的「--bip=182.48.25.1/24」這個參數,它限制了所在節點容器得到的IP範圍。
這個IP範圍是由Flannel自動分配的,由Flannel經過保存在Etcd服務中的記錄確保它們不會重複。

==========================================================================
舒適提示:
如上面操做後,發現各容器內分配的ip之間相互ping不通,基本就是因爲防火牆問題引發的!
但是明明已經在前面部署的時候,經過"systemctl stop firewalld.service"關閉了防火牆,爲何還有防火牆問題??
這是由於linux還有底層的iptables,因此解決辦法是在各節點上執行下面操做

[root@node-1 ~]# iptables -P INPUT ACCEPT
[root@node-1 ~]# iptables -P FORWARD ACCEPT
[root@node-1 ~]# iptables -F
[root@node-1 ~]# iptables -L -n

執行上面操做後,基本各容器間就能相互ping通了。

docker經過Flannel能夠實現各容器間的相互通訊,即宿主機和容器,容器和容器之間都能相互通訊。

相關文章
相關標籤/搜索