深入解讀docker網絡與kubernetes網絡


大綱:

1.概述

   1.1Linux的namespace+cgroup

   1.2容器的網絡

   1.3pod的網絡

    插播1:Docker和容器的關系

2.Docker容器網絡詳解

   2.1 CNM&libnetwork

   2.2 單機網絡---brige類型的網絡

   2.3 多機網絡---overlay類型的網絡

3.pod的網絡詳解

   2.1 kubernetes網絡概述

   2.2 詳解pod內的網絡

   2.3 詳解pod間的網絡

  

正文:

網絡概述


 

1,Linux的namespace+cgroup
 namespace和cgroup是Linux 內核的兩大特性,namespace的誕生據說就是為了支持容器技術,那么這倆特性到底干了啥呢?

 - namespace:linux支持多種類型的namespace,包括Network,IPC,PID, Mount, UTC, User。創建不同類型的namespace就相當於從不同資源維度在主機上作隔離。

 - cgroup:為了不讓某個進程一家獨大,而其他進程餓死,所以它的作用就是控制各進程分配的CPU,Memory,IO等。

 - namespace+cgroup也適用進程組,即多進程運行在一個單獨的ns中,此時該ns下的進程就可以交互了。

參考:https://coolshell.cn/articles/17010.html

2,容器
容器實際上是結合了namespace 和 cgroup 的一般內核進程,注意,容器就是個進程

所以,當我們使用Docker起一個容器的時候,Docker會為每一個容器創建屬於他自己的namespaces,即各個維度資源都專屬這個容器了,此時的容器就是一個孤島,也可以說是一個獨立VM就誕生了。當然他不是VM,網上關於二者的區別和優劣有一對資料.

更進一步,也可以將多個容器共享一個namespace,比如如果容器共享的是network 類型的namespace,那么這些容器就可以通過 localhost:[端口號]  來通信了。因為此時的兩個容器從網絡的角度看,和宿主機上的兩個內核進程沒啥區別。

在下面的詳解部分會有試驗來驗證這個理論

3,kubernetes的pod
       根據前面的描述我們知道,多進程/多容器可以共享namespace,而k8s的pod里就是有多個容器,他的網絡實現原理就是先創建一個共享namespace,然后將其他業務容器加入到該namespace中。
       k8s會自動以"合適"的方式為他們創建這個共享namespace,這正是"pause"容器的誕生。

       pause容器:創建的每一個pod都會隨之為其創建一個所謂的"父容器"。其主要由兩個功能:

  • (主要)負責為pod創建容器共享命名空間,pod中的其他業務容器都將被加入到pause容器的namespace中
  •   (可選) 負責回收其他容器產生的僵屍進程,此時pause容器可以看做是PID為1的init進程,它是所有其他容器(進程)的父進程。但在k8s1.8及以后,該功能缺省是關閉的(可通過配置開啟)

         水鬼子我猜這個功能是利用了共享PID類型的Namespace吧


插播1:Docker和容器的關系
容器:我們前面說了,就是一個具有獨立資源空間的Linux進程
Docker:是一個容器引擎,用來創建運行管理容器,即由它負責去和linux 內核打交道,給我們創建出來一個容器來。
容器可以被任何人創建出來,但是現在流行由Docker創建出來的,所以我們總說Docker容器,甚至提到docker就意味着說的是容器TOT

 

Docker容器網絡詳解


 

 從范圍上分:
   單機網絡:none,host, bridge
   跨主機網絡:overlay,macvlan,flannel等

從生成方式分:
   原生網絡:none,host, bridge
   自定義網絡:
      使用docker原生實現的驅動自定義的網絡:bridge(自定義),overlay,macvlan,
      使用第三方驅動實現的自定義網絡:flannel等

在學習網絡的時候肯定遇到過關於CNM這個概念,所以首先,我們一起學習下CNM&libnetwork

CNM&libnetwork
       libnetwork是Docker團隊將Docker的網絡功能從Docker的核心代碼中分離出來形成的一個單獨的庫,libnetwork通過插件的形式為Docker提供網絡功能。基於代碼層面再升華一下,可以將docker的網絡抽象出一個模型來,就叫CNM(Container Networking Model),該模型包含三大塊:

  • Sandbox:容器的網絡棧,包含interface,路由表,DNS設置等,可以看做就是linux network類型的namespace本身,該有的網絡方面的東西都要有,另外還包含一些用於連接各種網絡的endpoint
  • Endpoint : 用來將sandbox接入到network中。典型的實現是Veth pair技術(Veth pair是Linux固有的,是一個成對的接口,用來做連接用)
  • Network : 具體的網絡實現,比如是brige,VLAN等,同樣它包含了很多endpoint(那一頭)

      一句話:sandbox代表容器,network代表容器外的網絡驅動形成的網絡,endpoint連接了二者

       另外,CMN還提供了2個可插拔的接口,讓用戶可以自己實現驅動然后接入該接口,支持驅動有兩類:網絡驅動和IPAM驅動,看看這倆類驅動干什么的?

  • Network Drivers: 即真正的網絡實現,可以為Docker Engine或其他類型的集群網絡同時提供多種驅動,但是每一個具體的網絡只能實例化一個網絡驅動。細分為本地網絡驅動和遠端網絡驅動:   

          - 本地網絡驅動:對應前面說到的原生網絡
          - 遠端網絡驅動:對應前面說的自定義網絡

    IPAM Drivers — 構建docker網絡的時候,每個docker容器如果不手動指定的話是會被分配ip地址的,這個分配的任務就是由該驅動完成的,同樣的,Docker Engine還是給我們提供了缺省的實現。

 

整個的原理模型圖如下,參見官網:

參考:https://success.docker.com/article/networking
(一定要好好看看這篇文章,我英文不行看了整整2天,很有收獲)

好了,收,開始真正進入docker網絡的學習,我們挑2個代表性的網絡一起研究下

 

單機網絡---brige類型的網絡

原理如下圖(摘自https://success.docker.com/article/networking):

接下來聽我慢慢道來,我們先按照步驟走一遍,然后再細摳里面的原理

實操:在主機上起兩個docker容器,使用缺省網絡即bridge網絡,容器要使用有操作系統的鏡像,要不不方便驗證

  1)進入任一個容器內
     sh-4.2# ip addr
     13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
             inet 172.17.0.3/16 scope global eth0

  附:容器中可能缺少諸多命令,可以在啟動后安裝如下工具:
  yum install net-tools
  yum install iputils
  yum install iproute *

  2)在宿主機上查看接口信息:

   [root@centos network-scripts]# ip addr
      4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
           inet 172.17.0.1/16 scope global docker0
     14: vetha470484@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
     16: veth25dfcae@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 


 3) 在host上查看docker缺省會創建的三個網絡

 [root@centos ~]# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    451a2ff68c71        bridge              bridge              local
    7bd661f0c17f        host                host                local
    6c9bb2d42d95        none                null                local

 

4)再看下支撐網絡背后的驅動,即這個叫“bridge”的bridge類型網絡使用的驅動:一個名叫docker0的bridge(網橋)。網橋上掛兩個interface:veth25dfcae, vetha470484

  [root@centos network-scripts]# brctl show
  bridge name     bridge id             STP enabled       interfaces
  docker0         8000.0242dee689ea     no                veth25dfcae
                                                          vetha470484

附:可能缺少命令,可以在啟動后安裝如下工具:

# yum install bridge-utils

#ln -s /var/run/docker/netns/ /var/run/netns     ---用來在host上查看所有的namespace,缺省情況下ip netns show顯示的是/var/run/netns中的內容,但是Docker啟動后會清除

 

解析】

看容器(Sandbox), 接口的number是13的那個,他名字是eth0, 然后他@if14,這個就是endpoint,那么這個if14是誰?

看主機,有個網橋叫做docker0,有兩個interface 他們的master是docker0,並且這兩個interface的number分別是14,16,並且分別@if13和@if15,是的,if13正是容器中的接口,同理if14也是另一個容器中的接口,也就是說在host上的veth接口(NO.14)和容器中的eth接口(NO.13)正是一對veth pair,至此Endpoint作為容器和nework的連接的任務達成了。而docker0正是名叫bridge的Network的驅動。

最后,看一下路由吧
容器1:

sh-4.2# ip route
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3


表示:目的是172.17的流量交給eth0出去,然后交給網關172.17.0.1,也就是docker0

宿主機:

[root@centos ~]# ip route
default via 192.168.12.2 dev ens33 proto dhcp metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
192.168.12.0/24 dev ens33 proto kernel scope link src 192.168.12.132 metric 100


表示:目的是172.17的流量從docker0出去,
           缺省的交給ens33接口給網關192.168.12.2(因為我的宿主機是個虛擬機,所以還是個小網ip),也就是說如果訪問的是同網段(如加入同一網絡的其他容器)則交給網橋docker0內部轉發,否則走向世界

另外:詳細的可以 看一下bridge網絡,可以網絡中有兩個容器,ip,mac都有

[root@centos ~]# docker network inspect bridge
    {
        "Name": "bridge",
        "Driver": "bridge", 
        "IPAM": {     //負責給容器分配ip地址 
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },

        "Containers": {
            "9161f717c07ac32f96b1ede19d21a56a63f17fb69a63627f66704f5cec01ca27": {
                "Name": "server.1.oeep0sn0121wrvrw3aunmf9ww",
                "EndpointID": "5083992493b0a69fedb2adc02fe9c0aa61e59b068e16dd9371ec27e28d7d088c",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",""
            },
            "fb67b65aa43619779d0d4f9d2005815aea90586f0aba295436431f688239562b": {
                "Name": "fervent_ritchie",
                "EndpointID": "e402fa0f99f60199c8ba50263173ef3bc14ca75dbb597d2cbcd813dd4f8706f7",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
            }
        },
View Code

 

插播:bridge的原理
在容器技術中,bridge扮演了一個非常重要的角色,懂得bridge的原理可以很好的定位網絡問題,這里就不展開討論,在我的[爬坑]系列有講述,你只需要記住:不要把bridge想復雜,bridge是一個橋作為master,可以往橋上掛很多類型及個數的interface接口,當橋上有一個接口接收到數據后,只要不是給橋所在的宿主機本身,則橋會內部轉發,數據會從其余接口同步冒出來


】:
1,容器連接外網--OK

sh-4.2# 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=127 time=5.38 ms


注:這里面要說明一下,從容器發外網的egress流量之所以能順利得到應答,是因為它在出去的時候經過了iptables的NAT表,就是這里:

# iptables -t nat -L
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        anywhere            
MASQUERADE  all  --  172.18.0.0/16        anywhere 


這里如果對iptables的原理不是很清楚的,推薦這位大牛的博客:
http://www.zsythink.net/archives/1199/


2,容器連接另一個容器--OK

sh-4.2# ping 172.17.0.2 -c 2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=95.9 ms


3,容器如果想要被外網可以訪問的到,需要在起容器的時候指定--publish/-p,即在host上找一個port與容器映射,這個host將代表容器對外打交道,這里就不展開了,網上資料很多,上面貼出的鏈接中也有講解。

 

單機網絡---overlay類型的網絡

 上一個章節我們沒有細說容器和linux的namespace之間的關系,因為在overlay類型的網絡中,大量使用了linux的namespace技術,所以我們再展開講。

 overlay這個詞不是docker家的,一直以來就有overlay類型的網絡,意/譯為"覆蓋"型網絡,其中VxLan技術就可以認為是一種overlay類型網絡的實現,而在docker的overlay網絡,使用的正是Vxlan技術。所以我們再跑偏一下,講講VxLAN

https://www.cnblogs.com/shuiguizi/p/10923841.html

水鬼子:簡言之,可以暫時這么理解,宿主機上有一個叫做VTEP的組件。它的ip就是宿主機的ip,負責和其他宿主機連通形成隧道。這樣宿主機上的VM就可以利用該隧道和其他host上的VM溝通了,然后還並不感知該隧道的存在。也許這么說並不嚴謹,但是有助於對overlay網絡的理解。

另外,為了學習vxlan網絡以及容器對vxlan網絡的應用,我做了大量的實驗,遇到了很多很多的坑,需要的可以參考:.[爬坑系列]之VXLan網絡實現

oK,再“收”,回到docker 網絡

前情提要:
我們也可以直接使用docker 提供的overlay驅動創建overlay網絡,然后創建容器加入到該網絡,但如果是Docker Engine 1.12之前,還需要一個k-v類型的存儲介質。Docker Engine 1.12之后的由於集成了一個叫做“網絡控制平面(control plane)”的功能,則不需要額外的存儲介質了。在這里為了更好的理解,我們選擇前者,大致的步驟如下:

操作】
1,安裝啟動etcd,安裝方法
2,在一個host上創建overlay類型的網絡,並創建容器使用該網絡
3,在另一個容器上也可以看到該網絡,然后也加入這個網絡

root@master ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
731d1b63b387        ov_net2             overlay             global

分別在兩個節點上創建兩個docker 容器
master:
docker run -ti -d --network=ov_net2 --name=centos21 centos:wxy /bin/sh

minion:
docker run -d --name nginx --network=ov_net2 nginx22

 注:更詳細的步驟網上很多,另外想要看我自己搭建的過程中遇到的坑等,請參見【爬坑系列】之docker的overlay網絡配置

        這里我只想展示overlay網絡的深層實現,包括和namespace,vxlan的關系等

 

【解析】

1)看一下namespace以及配置
ln -s /var/run/docker/netns/ /var/run/netns

//一個容器創建完了,就多了兩個namespace
[root@master ~]# ip netns    
a740da7c2043 (id: 9)
1-731d1b63b3 (id: 8)

第一個namespace:其實就是docker容器本身,它有兩個接口,都是veth pair類型,對應的兄弟接口分別位於另一個namespace和系統namespace

root@master ~]# ip netns exec a740da7c2043 ip addr
44: eth0@if45: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:0a:00:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.1.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe00:102/64 scope link 
       valid_lft forever preferred_lft forever
46: eth1@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 172.18.0.4/16 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:4/64 scope link 
       valid_lft forever preferred_lft forever

第二個namespace:他的作用是專門用來做vxlan轉發的,核心是一個bro橋,橋上有兩個接口,一個與容器(第一個ns )相連,另一個vxlan1接口充當 vxlan網絡的vtep

[root@master ~]# ip netns exec 1-731d1b63b3 ip addr
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 12:54:57:62:92:74 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.1/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::842a:a1ff:fec8:da3b/64 scope link 
       valid_lft forever preferred_lft forever
43: vxlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN group default 
    link/ether 12:54:57:62:92:74 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::1054:57ff:fe62:9274/64 scope link 
       valid_lft forever preferred_lft forever
45: veth2@if44: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UP group default 
    link/ether ae:a1:58:8c:c2:0a brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::aca1:58ff:fe8c:c20a/64 scope link 
       valid_lft forever preferred_lft forever

 

結論:docker的overlay網絡 = 2namespace + vxlan

 

kubernetes之pod網絡詳解


一,kubernetes網絡概述

我們說的k8s網絡就是集群網絡,因為k8s是用於集群的,單機網絡沒什么意義。一個集群的網絡,主要涉及一下4個方面的通信

1,pod中的容器之間的通信:
   這個在前面的章節我們已經說了,pod中容器都是共享網絡空間的,所以就如一台機器上的應用一般,使用localhost:port就可以通信,也當然需要容器們自己保證大家別端口沖突了。

2,pod-to-pod的通信
   首先k8s給每一個pod都分配ip了,具體他們之間怎么通信取決於具體的網絡實施,這個不是k8s做的,但是k8s做了要求,也叫網絡模型,具體要求如下:
   1)一個節點上的pod可以和所有節點上的所有pod通信,且不需要NAT
   2)節點上的agent(比如系統daemons:kubelet)可以和該節點上的所有pod通信
   3)如果pod是運行與host的網絡中,則要求pod同樣可以和節點上的其他pod通信

3,pod和service的通信,這個詳見service的定義
4,外網和serice的通信,同樣相近service的定義
注:3,4的實現就是service的實現,建議仔仔細細研究官方文檔就可以搞清楚了,有時間我會將這部分也整理下分享出來。那部分總結一句話就是:iptables的運用

另外,在進行k8s網絡驗證之前,需要進行k8s本地環境安裝,為了更好的研究我走了一條非常復雜的安裝之路:本地編譯源碼生成二進制,在打包鏡像,最后通過三種途徑安裝了master節點和node節點:yum自動安裝,二進制安裝,鏡像安裝,想起來都是淚,想參考的見【爬坑系列】之kubernetes環境搭建:二進制安裝與鏡像安裝


二,詳解pod內的通信
1,一個例子模擬pod的通信
模擬k8的行為,首先創建pause容器,然后創建centos容器和nginx容器都加入到pause容器的網絡中,然后在centos容器中訪問localhost:80,於是訪問到了nginx容器。具體如下:
docker run -d --name pause docker.io/ist0ne/pause-amd64

docker run -d --name nginx --net=container:pause --ipc=container:pause --pid=container:pause nginx

docker run -d -ti --name centos --net=container:pause --ipc=container:pause --pid=container:pause centos /bin/sh
sh-4.2# curl localhost:80  ---訪問nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

2,實際的k8s的:

創建一個有倆容器的pod,一個是centos操作系統,一個是nginx,在centos中訪問localhost:80可以訪問到nginx服務

//創建pod的yaml文件,該pod中有兩個容器
# vi centos-nginx.yaml apiVersion: v1 kind: Pod metadata: name: myapp-2c labels: app: centos spec: containers: - name: centos-container image: centos:wxy command: ["/bin/sh"] args: ["-c", "while true; do echo hello; sleep 10; done"] - name: nginx-container image: nginx
//登錄pod默認登錄到centos-container這個容器,剛好
# kubectl exec -ti myapp-2c /bin/sh Defaulting container name to centos-container. Use 'kubectl describe pod/myapp-2c -n default' to see all of the containers in this pod. sh-4.2# curl localhost:80 <!DOCTYPE html> ... <h1>Welcome to nginx!</h1>

 

//看看容器的情況:一個pause容器領着領養倆業務容器
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES edf722104aa6 nginx "nginx -g 'daemon ..." 27 minutes ago Up 27 minutes k8s_nginx-container.570a1191_myapp-2c_default_0461d9cd-8370-11e9-a770-5254006bdf04_702066eb 6e5e2c96bd90 centos:wxy "/bin/sh -c 'while..." 27 minutes ago Up 27 minutes k8s_centos-container.e8c7257b_myapp-2c_default_0461d9cd-8370-11e9-a770-5254006bdf04_d950aeda 044e4c09f0e9 docker.io/ist0ne/pause-amd64 "/pause" 27 minutes ago Up 27 minutes k8s_POD.68b7dd1e_myapp-2c_default_0461d9cd-8370-11e9-a770-5254006bdf04_00db96a2

 

二:詳解pod之間的通信
這個是k8s集群網絡的核心,前面說了,取決於具體的網絡實施。

  水鬼子:如果你剛接觸k8s,不知道你是否會對這里感到迷惑,第三方實現是什么鬼?pod之間的通信不是k8s自己做的么?難道要額外安裝啥軟件?
      是的需要額外安裝,在這里我們就以etcd + flunnel為例來講解。

概述

        集群中的各個node,首先一定是連通的,然后基於底層網絡之上的flannel其實就是一個overlay網絡。說到overlay,如果你看了前面Docker網絡的章節,一定大概知道是怎么回事了。flannel網絡有多種實現方式,目前支持的有:udp(默認),host-gw,VxLAN(是不是很熟悉?)。實際上pod之間的網絡要比docker的還簡單。

原理詳解:

1,為什么需要etcd
        etcd是一個key-value形式的存儲系統,可以往里寫各種類型的數據。我們需要做的就是首先約定好一個key,以這個key向etcd中寫入網絡配置參數;然后在安裝flannel的時候配置FLANNEL_ETCD_PREFIX參數為此key。
        k8s集群中的每個節點上都有安裝flanneld作為網絡代理,它通過讀取etcd知道當前的網絡配置信息,為pod分配ip后,再將當前的網絡狀況比如本節點分得的subnet和對應的public ip等信息再寫入etcd中。這種網絡管理模式就是所謂的network planes,用我的話說,大家也沒什么上下級關系,都是處在同一平級,所以叫"網絡平面"。

2,網絡拓撲和轉發原理

      

       所謂flannel的安裝,最主要是在每個節點上安裝flanneld,這個"代理"一樣的角色會做什么呢?

        1)首先去etcd那里讀取配置。根據配置為自己分配一個subnet,並將其與public ip(在安裝flannel時指定的ip,如果沒有指定則缺省是host上的eth0的地址)的對應關系再存入etcd中,這樣其他節點上的flannel也就共享這些信息了。

        2)創建虛擬網卡flannel0並分配一個該子網段ip,還會添加一條路由:所有到其他pod的數據都從flanel0出去;

        3))將網段信息寫入/run/flannel/subnet.env中,這是一個用於刷新Docker環境變量相關的的文件:/run/flannel/docker。所以這時候重啟一下Docker,docker0就有了一個該子網段的ip。

       [坑]這里要注意,我不知道別的版本,反正我目前安裝的版本,如果flannel重啟並重新給自己分配了subnet,那么此時一定記得重啟Docker,否則docker0的ip和flannel0的ip不一致,進而導致數據無法正確轉發。

       最后,數據如何轉發的呢?數據從容器出來,經過veth pair到達網橋docker0,根據路由再轉發給flannel0,進而數據由flannel的backend(udp或者host-gw或者vxlan)轉發給目的pod所在的backend上,最后由目的host上的backend上送至目的pod的容器中。具體如下:

 //etcd中存放着flannel網絡配置信息:地址空間,缺省backend類型
 #etcdctl get /k8s/network/config
 {"Network": "10.0.0.0/16"}

 //flannel啟動后,它會偷偷改變Docker的環境變量
 #vi /usr/lib/systemd/system/flanneld.service
 ...
 ExecStartPost=/usr/libexec/flannel/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
 ...


 //於是docker在啟動的時候就有了約束,其中bip決定了網橋docker0的IP
 # systemctl status docker.service
 ...
 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current ... --bip=10.0.42.1/24 --ip-masq=true --mtu=1472
 ...

//集群中兩個節點,分別給自己分配了子網,也都存在了etcd中,包括到達子網絡的public ip
# etcdctl ls /k8s/network/subnets /k8s/network/subnets/10.0.58.0-24 /k8s/network/subnets/10.0.42.0-24 # etcdctl get /k8s/network/subnets/10.0.42.0-24 {"PublicIP":"188.x.x.113"}

//veth pair把數據容器里導出來到達網橋docker0,再經過路由表到達flannel0,最后交給backend
# ip addr
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default
link/ether 02:42:ad:d6:96:b7 brd ff:ff:ff:ff:ff:ff
inet 10.0.42.1/24 scope global docker0
valid_lft forever preferred_lft forever

...
36: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 10.0.42.0/16 scope global flannel0
valid_lft forever preferred_lft forever
40: veth9b5a76f@if48: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue master docker0 state UP group default
link/ether da:e4:3e:d3:cb:f9 brd ff:ff:ff:ff:ff:ff link-netnsid 3

# ip route
default via 172.21.0.1 dev eth0
10.0.0.0/16 dev flannel0 proto kernel scope link src 10.0.42.0
10.0.42.0/24 dev docker0 proto kernel scope link src 10.0.42.1

 

3,詳解flannel的三種backend

參考博客:

http://www.360doc.com/content/16/0629/16/17572791_571683078.shtml

我覺得他講的很明了了

實操

1,創建l兩個pod,為了讓他們能夠分別調度到兩個節點上,我還為node打了標簽,並為pod配置了nodeSelector,例如

# cat centos.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: myapp-centos
  labels:
    app: centos
spec:
  containers:
  - name: nginx-container
    image: centos:wxy
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10; done"]
  nodeSelector:
    node: master

 

[root@master ~]# kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
myapp-centos   1/1     Running   0          16h
myapp-nginx    1/1     Running   0          83s

 

2,驗證連通性:在一個pod里訪問另一個pod

1)看一下nginx的ip
# kubectl get pods myapp-nginx -oyaml |grep podIP
  podIP: 10.0.58.3

2)在centos中訪問一下nginx
[root@master ~]# kubectl exec -ti myapp-centos /bin/sh
sh-4.2# curl http://10.0.58.3:80
...
<h1>Welcome to nginx!</h1>

 

 

==============================END===================================================

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM