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

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

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

Weave的思路

1

2

在每個宿主機上佈置一個特殊的route的容器,不同宿主機的route容器連線起來。 route攔截所有普通容器的ip請求,並通過udp包傳送到其他宿主機上的普通容器。

這樣在跨機的多個容器端看到的就是同一個扁平網路。 weave解決了網路問題,不過部署依然是單機的。

flannel的思路

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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系統)

1

2

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)機器操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

設定主機名及繫結hosts

[[email protected] ~]# hostnamectl --static set-hostname  node-1

[[email protected] ~]# vim /etc/hosts

182.48.115.233    node-1

182.48.115.233    etcd

182.48.115.235    node-2

關閉防火牆,如果開啟防火牆,則最好開啟2379和4001埠

[[email protected] ~]# systemctl disable firewalld.service

[[email protected] ~]# systemctl stop firewalld.service

先安裝docker環境

[[email protected] ~]# yum install -y docker

安裝etcd

k8s執行依賴etcd,需要先部署etcd,下面採用yum方式安裝:

[[email protected] ~]# yum install etcd -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"

# 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並驗證狀態

[[email protected] ~]# systemctl start etcd

[[email protected] ~]# 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

[[email protected] ~]# 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)

........

[[email protected] ~]# etcdctl set testdir/testkey0 0

0

[[email protected] ~]# etcdctl get testdir/testkey0

0

[[email protected] ~]# etcdctl -C http://etcd:4001 cluster-health

member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379

cluster is healthy

[[email protected] ~]# etcdctl -C http://etcd:2379 cluster-health

member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379

cluster is healthy

安裝覆蓋網路Flannel

[[email protected] ~]# yum install flannel

配置Flannel

[[email protected] ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak

[[email protected] ~]# 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是相對應的,錯誤的話啟動就會出錯):

[[email protected] ~]# etcdctl mk /atomic.io/network/config '{ "Network": "182.48.0.0/16" }'

{ "Network": "182.48.0.0/16" }

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

啟動Flannel

[[email protected] ~]# systemctl enable flanneld.service

[[email protected] ~]# systemctl start flanneld.service

[[email protected] ~]# 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段

[[email protected] ~]# systemctl restart docker

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

設定主機名及繫結hosts

[[email protected] ~]# hostnamectl --static set-hostname  node-2

[[email protected] ~]# vim /etc/hosts

182.48.115.233    node-1

182.48.115.233    etcd

182.48.115.235    node-2

關閉防火牆,如果開啟防火牆,則最好開啟2379和4001埠

[[email protected] ~]# systemctl disable firewalld.service

[[email protected] ~]# systemctl stop firewalld.service

先安裝docker環境

[[email protected] ~]# yum install -y docker

安裝覆蓋網路Flannel

[[email protected] ~]# yum install flannel

配置Flannel

[[email protected] ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak

[[email protected] ~]# 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

[[email protected] ~]# systemctl enable flanneld.service

[[email protected] ~]# systemctl start flanneld.service

[[email protected] ~]# 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段

[[email protected] ~]# systemctl restart docker

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

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

[[email protected] ~]# docker run -ti -d --name=node-1.test docker.io/nginx /bin/bash

5e403bf93857fa28b42c9e2abaa5781be4e2bc118ba0c25cb6355b9793dd107e

[[email protected] ~]# docker exec -ti node-1.test /bin/bash

[email protected]:/# 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: [email protected]: <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)上容器容器

[[email protected] ~]# docker exec -ti node-2.test /bin/bash

[email protected]:/# 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: [email protected]: <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

[email protected]:/# 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

.......

[email protected]:/# 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的虛擬網絡卡資訊

[[email protected] ~]# 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所在的範圍

[[email protected] ~]# 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服務中的記錄確保它們不會重複。