Kubernetes入门学习-十九-网络配置插件flannel-01

最近学习k8s遇到很多问题,建了一个qq群:153144292,交流devops、k8s、docker等

Kubernetes的网络模型和网络策略
    Kubernetes网络模型和CNI插件
​    在Kubernetes中设计了一种网络模型,要求无论容器运行在集群中的哪个节点,所有容器
都能通过一个扁平的网络平面进行通信,即在同一IP网络中。
    需要注意的是:在K8S集群中,IP地址分配是以Pod对象为单位,而非容器,同一Pod内的所
有容器共享同一网络名称空间。

Docker网络模型
​    了解Docker的友友们都应该清楚,Docker容器的原生网络模型主要有4种:Bridge(桥接)、
joined、Host(主机)、none。
    Bridge:桥接式网络,借助虚拟网桥设备为容器建立网络连接。
    joined: 联盟式网络、共享别的容器网络名称空间
    Host(open):设置容器直接共享当前节点主机的网络名称空间。
    none:不使用网络名称空间。
    
===========================
#使用以下命令查看docker原生的三种网络
[root@node01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
11d82740d302        bridge              bridge              local
e91c59d0b9c0        host                host                local
37ce079dc9a9        none                null                local

#none网络,在该网络下的容器仅有lo网卡,属于封闭式网络,通常用于对安全性要求较高并且不需要联网的应用
[root@node01 ~]# docker run -it --network=none busybox
/ # ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

#host网络,共享宿主机的网络名称空间,容器网络配置和host一致,但是存在端口冲突的问题
[root@node01 ~]# docker run -it --network=host busybox
/ # ip addr
1: lo: mtu 65536 qdisc noqueue qlen 1
    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
2: ens2f0: mtu 1500 qdisc mq qlen 1000
    link/ether a0:36:9f:8d:e3:5e brd ff:ff:ff:ff:ff:ff
3: ens2f1: mtu 1500 qdisc mq master bond0 qlen 1000
    link/ether a0:36:9f:8d:e3:5f brd ff:ff:ff:ff:ff:ff
4: eno1: mtu 1500 qdisc mq master bond0 qlen 1000
    link/ether a0:36:9f:8d:e3:5f brd ff:ff:ff:ff:ff:ff
5: eno2: mtu 1500 qdisc mq qlen 1000
    link/ether 00:8c:fa:f9:f4:e5 brd ff:ff:ff:ff:ff:ff
6: bond0: mtu 1500 qdisc noqueue qlen 1000
    link/ether a0:36:9f:8d:e3:5f brd ff:ff:ff:ff:ff:ff
    inet 10.249.6.101/24 brd 10.249.6.255 scope global bond0
       valid_lft forever preferred_lft forever
    inet6 fe80::a236:9fff:fe8d:e35f/64 scope link 
       valid_lft forever preferred_lft forever
7: docker0: mtu 1500 qdisc noqueue 
    link/ether 02:42:a5:5d:da:05 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:a5ff:fe5d:da05/64 scope link 
       valid_lft forever preferred_lft forever
10: flannel.1: mtu 1450 qdisc noqueue 
    link/ether ce:74:25:7c:7b:ec brd ff:ff:ff:ff:ff:ff
    inet 10.244.1.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::cc74:25ff:fe7c:7bec/64 scope link 
       valid_lft forever preferred_lft forever
13: cni0: mtu 1450 qdisc noqueue qlen 1000
    link/ether 0a:58:0a:f4:01:01 brd ff:ff:ff:ff:ff:ff
    inet 10.244.1.1/24 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::4073:9cff:fe59:47b/64 scope link 
       valid_lft forever preferred_lft forever
25: veth99ad7c1e@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether a2:d9:41:28:3b:29 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a0d9:41ff:fe28:3b29/64 scope link 
       valid_lft forever preferred_lft forever
26: veth21cd58be@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether fe:54:97:71:bb:63 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:97ff:fe71:bb63/64 scope link 
       valid_lft forever preferred_lft forever
38: veth766df1a0@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether a2:05:42:46:af:24 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a005:42ff:fe46:af24/64 scope link 
       valid_lft forever preferred_lft forever
47: vethc8a23d2a@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether 06:94:c4:60:39:ea brd ff:ff:ff:ff:ff:ff
    inet6 fe80::494:c4ff:fe60:39ea/64 scope link 
       valid_lft forever preferred_lft forever
49: veth7005c237@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether c2:88:56:4e:fb:ba brd ff:ff:ff:ff:ff:ff
    inet6 fe80::c088:56ff:fe4e:fbba/64 scope link 
       valid_lft forever preferred_lft forever
50: veth08915585@ens2f1: mtu 1450 qdisc noqueue master cni0 
    link/ether d2:d7:48:6d:7c:66 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::d0d7:48ff:fe6d:7c66/64 scope link 
       valid_lft forever preferred_lft forever
/ # 
/ # hostname              这里跟node01节点共享网络名称空间
node01

#bridge网络,Docker安装完成时会创建一个名为docker0的linux bridge,不指定网络时,创建的网络默认为桥接网络,都会桥接到docker0上。

    桥接式网络是目前较为流行和默认的解决方案。但是这种方案的弊端是无法跨主机通信
的,仅能在宿主机本地进行,而解决该问题的方法就是NAT。所有接入到该桥接设备上的容器
都会被NAT隐藏,它们发往Docker主机外部的所有流量都会经过源地址转换后发出,并且默认
是无法直接接受节点之外的其他主机发来的请求。当需要接入Docker主机外部流量,就需要进
行目标地址转换甚至端口转换将其暴露在外部网络当中。

    任何一个pod出去的时候要做源地址转换,需要做nat。

    容器内的属于私有地址,需要在左侧的主机上的eth0上进行源地址转换,而右侧的地址需要被访问,就需要将eth0的地址进行NAT转换。SNAT---->DNAT
 
    这样的通信方式会比较麻烦,从而需要借助第三方的网络插件实现这样的跨主机通信的网络策略。
    
================================
Kubernetes网络模型
    在K8S上的网络通信包含以下几类:
        1、容器间的通信:同一个Pod内的多个容器间的通信,它们之间通过lo网卡进行通信。
        2、Pod之间的通信:通过Pod IP地址进行通信,直达。
        3、Pod和Service之间的通信:Pod IP地址和Service IP进行通信,两者并不属于同一网络,实现方式是通过IPVS或iptables规则转发。
        4、Service和集群外部客户端的通信,实现方式:Ingress、NodePort、Loadbalance
[root@master ~]# kubectl get configmap -n kube-system
NAME                                 DATA   AGE
coredns                              1      32d
extension-apiserver-authentication   6      32d
kube-flannel-cfg                     2      32d
kube-proxy                           2      32d
kubeadm-config                       2      32d
kubelet-config-1.13                  1      32d
[root@master ~]# kubectl get configmap kube-proxy -o yaml -n kube-system
apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    clientConnection:
      acceptContentTypes: ""
      burst: 10
      contentType: application/vnd.kubernetes.protobuf
      kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
      qps: 5
    clusterCIDR: 10.244.0.0/16
    configSyncPeriod: 15m0s
    conntrack:
      max: null
      maxPerCore: 32768
      min: 131072
      tcpCloseWaitTimeout: 1h0m0s
      tcpEstablishedTimeout: 24h0m0s
    enableProfiling: false
    healthzBindAddress: 0.0.0.0:10256
    hostnameOverride: ""
    iptables:
      masqueradeAll: false
      masqueradeBit: 14
      minSyncPeriod: 0s
      syncPeriod: 30s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      syncPeriod: 30s
    kind: KubeProxyConfiguration
    metricsBindAddress: 127.0.0.1:10249
    mode: ""                           这里修改为ipvs
    nodePortAddresses: null
    oomScoreAdj: -999
    portRange: ""
    resourceContainer: /kube-proxy
    udpIdleTimeout: 250ms
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://10.249.6.100:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
  creationTimestamp: "2019-02-28T11:23:46Z"
  labels:
    app: kube-proxy
  name: kube-proxy
  namespace: kube-system
  resourceVersion: "237"
  selfLink: /api/v1/namespaces/kube-system/configmaps/kube-proxy
  uid: 4ffcc6cf-3b4b-11e9-a704-a0369f95b76e 
  
============================
CNI
    K8S网络的实现不是集群内部自己实现,而是依赖于第三方网络插件----CNI(Container Network Interface)
flannel、calico、canel等是目前比较流行的第三方网络插件。

这三种的网络插件需要实现Pod网络方案的方式通常有以下几种:虚拟网桥、多路复用(MacVLAN)、硬件交换(SR-IOV)

    无论是上面的哪种方式在容器当中实现,都需要大量的操作步骤,而K8S支持CNI插件进行编排网络,
以实现Pod和集群网络管理功能的自动化。每次Pod被初始化或删除,kubelet都会调用默认的CNI插件去
创建一个虚拟设备接口附加到相关的底层网络,为Pod去配置IP地址、路由信息并映射到Pod对象的网络
名称空间。

​    在配置Pod网络时,kubelet会在默认的/etc/cni/net.d/目录中去查找CNI JSON配置文件,然后通过
type属性到/opt/cni/bin中查找相关的插件二进制文件,如下面的"portmap"。然后CNI插件调用IPAM插件
(IP地址管理插件)来配置每个接口的IP地址:
[root@master ~]# cat /etc/cni/net.d/10-flannel.conflist
{
  "name": "cbr0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}
kubelet调用第三方插件,进行网络地址的分配。

    CNI主要是定义容器网络模型规范,链接容器管理系统和网络插件,两者主要通过上面的JSON格式文件进行
通信,实现容器的网络功能。CNI的主要核心是:在创建容器时,先创建好网络名称空间(netns),然后调用
CNI插件为这个netns配置网络,最后在启动容器内的进程。

常见的CNI网络插件包含以下几种:
    1、Flannel:为Kubernetes提供叠加网络的网络插件,基于TUN/TAP隧道技术,使用UDP封装IP报文进行创建叠加网络,借助etcd维护网络的分配情况,缺点:无法支持网络策略访问控制。
    2、Calico:基于BGP的三层网络插件,也支持网络策略进而实现网络的访问控制;它在每台主机上都运行一个虚拟路由,利用Linux内核转发网络数据包,并借助iptables实现防火墙功能。实际上Calico最后的实现就是将每台主机都变成了一台路由器,将各个网络进行连接起来,实现跨主机通信的功能。
    3、Canal:由Flannel和Calico联合发布的一个统一网络插件,提供CNI网络插件,并支持网络策略实现。
    4、其他的还包括Weave Net、Contiv、OpenContrail、Romana、NSX-T、kube-router等等。而Flannel和Calico是目前最流行的选择方案。
=================================
Flannel网络插件
    在各节点上的Docker主机在docker0上默认使用同一个子网,不同节点的容器都有可能会获取
到相同的地址,那么在跨节点通信时就会出现地址冲突的问题。并且在多个节点上的docker0使用
不同的子网,也会因为没有准确的路由信息导致无法准确送达报文。

​    而为了解决这一问题,Flannel的解决办法是,预留一个使用网络,如10.244.0.0/16,然后自
动为每个节点的Docker容器引擎分配一个子网,如10.244.1.0/24和10.244.2.0/24,并将分配信息
保存在etcd持久存储。

​    第二个问题的解决,Flannel是采用不同类型的后端网络模型进行处理。其后端的类型有以下几
种:
   1、VxLAN:使用内核中的VxLAN模块进行封装报文。也是flannel推荐的方式,其报文格式如下:
  |--------------------------------------|--------------vm---------------------------|
  |outer mac---outer ip--outer UDP--VXLAN|MAC-----IP----------TCP/UDP------DATA------|
  
  2、host-gw:即Host GateWay,通过在节点上创建目标容器地址的路由直接完成报文转发,要求
各节点必须在同一个2层网络,对报文转发性能要求较高的场景使用。

  3、UDP:使用普通的UDP报文封装完成隧道转发。
  
VxLAN后端和direct routing
​    VxLAN(Virtual extensible Local Area Network)虚拟可扩展局域网,采用MAC in UDP封装方式
,具体的实现方式为:
    1、将虚拟网络的数据帧添加到VxLAN首部,封装在物理网络的UDP报文中
    2、以传统网络的通信方式传送该UDP报文
    3、到达目的主机后,去掉物理网络报文的头部信息以及VxLAN首部,并交付给目的终端
跨节点的Pod之间的通信就是以上的一个过程,整个过程中通信双方对物理网络是没有感知的。
我这里环境已经安装
https://blog.csdn.net/yujin2010good/article/details/88043217

[root@master ~]# kubectl get daemonset -n kube-system
NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                     AGE
kube-flannel-ds-amd64     3         3         3       3            3           beta.kubernetes.io/arch=amd64     33d
kube-flannel-ds-arm       0         0         0       0            0           beta.kubernetes.io/arch=arm       33d
kube-flannel-ds-arm64     0         0         0       0            0           beta.kubernetes.io/arch=arm64     33d
kube-flannel-ds-ppc64le   0         0         0       0            0           beta.kubernetes.io/arch=ppc64le   33d
kube-flannel-ds-s390x     0         0         0       0            0           beta.kubernetes.io/arch=s390x     33d
kube-proxy                3         3         3       3            3                                      33d

运行正常后,flanneld会在宿主机的/etc/cni/net.d目录下生成自已的配置文件,kubelet将会调用它。

网络插件运行成功后,Node状态才Ready。
[root@master ~]# kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   33d   v1.13.3
node01   Ready       33d   v1.13.3
node02   Ready       33d   v1.13.3
flannel运行后,在各Node宿主机多了一个网络接口
#master节点的flannel.1网络接口,其网段为:10.244.0.0
[root@master ~]# ip a
12: flannel.1: mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether 6a:63:a1:96:b6:66 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::6863:a1ff:fe96:b666/64 scope link 
       valid_lft forever preferred_lft forever
#node1节点的flannel.1网络接口,其网段为:10.244.1.0
10: flannel.1: mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether ce:74:25:7c:7b:ec brd ff:ff:ff:ff:ff:ff
    inet 10.244.1.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::cc74:25ff:fe7c:7bec/64 scope link 
       valid_lft forever preferred_lft forever
#node2节点的flannel.1网络接口,其网段为:10.244.2.0
12: flannel.1: mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether 52:b8:24:34:e6:8c brd ff:ff:ff:ff:ff:ff
    inet 10.244.2.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::50b8:24ff:fe34:e68c/64 scope link 
       valid_lft forever preferred_lft forever
从上面的结果可以知道 :
1、flannel默认就是VXLAN模式,即Overlay Network。
2、flanneld创建了一个flannel.1接口,它是专门用来封装隧道协议的,默认分给集群的Pod网段为10.244.0.0/16。
3、flannel给master节点配置的Pod网络为10.244.0.0段,给node01节点配置的Pod网络为10.244.1.0段,给node02节点配置的Pod网络为10.244.2.0段,如果有更多的节点,以此类推
举个实际例子
#启动一个nginx容器,副本为3
[root@master ~]# kubectl run wolf --image=nginx:1.14-alpine --port=80 --replicas=3
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/wolf created
[root@master ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
myapp-0                         1/1     Running   0          14d
myapp-1                         1/1     Running   1          14d
myapp-2                         1/1     Running   0          14d
myapp-3                         1/1     Running   1          14d
nginx-7849c4bbcd-dscjr          1/1     Running   0          31d
nginx-7849c4bbcd-vdd45          1/1     Running   1          31d
nginx-7849c4bbcd-wrvks          1/1     Running   0          31d
nginx-deploy-84cbfc56b6-scrnt   1/1     Running   1          15d
pod-sa-demo                     1/1     Running   0          13d
wolf-7f649b757d-njtr2           1/1     Running   0          3s
wolf-7f649b757d-ntrp9           1/1     Running   0          3s
wolf-7f649b757d-whsb9           1/1     Running   0          3s
#查看Pod
[root@master ~]# kubectl get pods -o wide |grep wolf
wolf-7f649b757d-njtr2           1/1     Running   0          10s   10.244.2.74   node02            
wolf-7f649b757d-ntrp9           1/1     Running   0          10s   10.244.1.42   node01            
wolf-7f649b757d-whsb9           1/1     Running   0          10s   10.244.2.73   node02            

可以看到,3个Pod都分别运行在各个节点之上,在master节点上查看网络接口可以发现在各个节点上多了一个虚拟接口cni0,其ip地址为10.244.0.1。它是由flanneld创建的一个虚拟网桥叫cni0,在Pod本地通信使用。 这里需要注意的是,cni0虚拟网桥,仅作用于本地通信!!!!

13: cni0: mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:58:0a:f4:00:01 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/24 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::2845:7dff:fecc:30d8/64 scope link 
       valid_lft forever preferred_lft forever
flanneld为每个Pod创建一对veth虚拟设备,一端放在容器接口上,一端放在cni0桥上。 使用brctl查看该网桥:
#可以看到有一veth的网络接口桥接在cni0网桥上
yum install bridge-utils
[root@master ~]#  brctl show cni0
bridge name    bridge id        STP enabled    interfaces
cni0        8000.0a580af40001    no        veth0e85a251
                                        veth1da05c4b
                                        
[root@master ~]# ping 10.244.2.73
PING 10.244.2.73 (10.244.2.73) 56(84) bytes of data.
64 bytes from 10.244.2.73: icmp_seq=1 ttl=63 time=0.404 ms

在现有的Flannel VxLAN网络中,两台主机上的Pod间通信,也是正常的,如master节点上的Pod访问node01上的Pod:
kubectl exec -it wolf-7f649b757d-njtr2 -- /bin/bash
[root@master ~]# kubectl exec -it wolf-7f649b757d-njtr2 -- /bin/bash
root@wolf-7f649b757d-njtr2:/# ping 10.244.1.41
PING 10.244.1.146 (10.244.1.146) 56(84) bytes of data.
64 bytes from 10.244.1.42: icmp_seq=1 ttl=62 time=1.44 ms
64 bytes from 10.244.1.42: icmp_seq=2 ttl=62 time=0.713 ms

可以看到容器跨主机是可以正常通信的,那么容器的跨主机通信是如何实现的呢?????
master上查看路由表信息:
[root@master ~]# ip route
。。。。。。。。。。。
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink 
。。。。。。。。。。
    发送到10.244.1.0/24和10.244.2.0/24网段的数据报文发给本机的flannel.1接口,即进入二层隧
道,然后对数据报文进行封装(封装VxLAN首部-->UDP首部-->IP首部-->以太网首部),到达目标Node
节点后,由目标Node上的flannel.1进行解封装。使用tcpdump进行 抓一下包,如下:
#在宿主机和容器内都进行ping另外一台主机上的Pod ip并进行抓包
[root@master ~]# ping 10.244.2.73
PING 10.244.2.73 (10.244.2.73) 56(84) bytes of data.
64 bytes from 10.244.2.73: icmp_seq=1 ttl=63 time=0.309 ms
64 bytes from 10.244.2.73: icmp_seq=2 ttl=63 time=0.190 ms
[root@master ~]# tcpdump -i flannel.1 -nn host 10.244.2.73
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
11:09:09.157126 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 35, length 64
11:09:09.157303 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 35, length 64
11:09:10.157108 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 36, length 64
11:09:10.157323 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 36, length 64
11:09:11.157122 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 37, length 64
11:09:11.157300 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 37, length 64
11:09:12.157103 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 38, length 64
11:09:12.157307 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 38, length 64

可以看到报文都是经过flannel.1网络接口进入2层隧道进而转发.
    VXLAN是Linux内核本身支持的一种网络虚拟化技术,是内核的一个模块,在内核态实现封装解封装,构
建出覆盖网络,其实就是一个由各宿主机上的Flannel.1设备组成的虚拟二层网络。
    由于VXLAN由于额外的封包解包,导致其性能较差,所以Flannel就有了host-gw模式,即把宿主机当作网
关,除了本地路由之外没有额外开销,性能和calico差不多,由于没有叠加来实现报文转发,这样会导致路由
表庞大。因为一个节点对应一个网络,也就对应一条路由条目。
    ​host-gw虽然VXLAN网络性能要强很多。,但是种方式有个缺陷:要求各物理节点必须在同一个二层网络中
。物理节点必须在同一网段中。这样会使得一个网段中的主机量会非常多,万一发一个广播报文就会产生干扰
。在私有云场景下,宿主机不在同一网段是很常见的状态,所以就不能使用host-gw了。
    VXLAN还有另外一种功能,VXLAN也支持类似host-gw的玩法,如果两个节点在同一网段时使用host-gw通信
,如果不在同一网段中,即 当前pod所在节点与目标pod所在节点中间有路由器,就使用VXLAN这种方式,使用
叠加网络。结合了Host-gw和VXLAN,这就是VXLAN的Direct routing模式
Flannel VxLAN的Direct routing模式配置

修改kube-flannel.yml文件,将flannel的configmap对象改为:

[root@master ~]# vim kube-flannel.yml 
......
 net-conf.json: |
    {
      "Network": "10.244.0.0/16",   #默认网段
      "Backend": {
        "Type": "vxlan",
        "Directrouting": true   #增加
      }
    }
......
[root@master ~]# kubectl apply -f kube-flannel.yml 
clusterrole.rbac.authorization.k8s.io/flannel configured
clusterrolebinding.rbac.authorization.k8s.io/flannel configured
serviceaccount/flannel unchanged
configmap/kube-flannel-cfg configured
daemonset.extensions/kube-flannel-ds-amd64 created
daemonset.extensions/kube-flannel-ds-arm64 created
daemonset.extensions/kube-flannel-ds-arm created
daemonset.extensions/kube-flannel-ds-ppc64le created
daemonset.extensions/kube-flannel-ds-s390x created
查看路由信息
[root@master ~]# ip route
......
10.244.1.0/24 via 10.249.2.101 dev bond0 
10.244.2.0/24 via 10.249.2.102 dev bond0 
......
从上面的结果可以看到,发往10.244.1.0/24和10.244.2.0/24的包都是直接经过bond0网络接口直接发出去的,这
就是Directrouting。如果两个节点是跨网段的,则flannel自动降级为VxLAN模式。
再在此之前创建的Pod和宿主机上进行ping测试,可以看到在flannel.1接口上已经抓不到包了,在bond0上可以用抓到ICMP的包,如下:

[root@master ~]# tcpdump -i flannel.1 -nn host 10.244.2.73
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

[root@master ~]# tcpdump -i bond0 -nn host 10.244.2.73
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
11:09:09.157126 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 35, length 64
11:09:09.157303 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 35, length 64
11:09:10.157108 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 36, length 64
11:09:10.157323 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 36, length 64
11:09:11.157122 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 37, length 64
11:09:11.157300 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 37, length 64
11:09:12.157103 IP 10.244.0.0 > 10.244.2.73: ICMP echo request, id 26050, seq 38, length 64
11:09:12.157307 IP 10.244.2.73 > 10.244.0.0: ICMP echo reply, id 26050, seq 38, length 64
==================================
Host-gw后端
   Flannel除了上面2种数据传输的方式以外,还有一种是host-gw的方式,host-gw后端是通过添加必要
的路由信息使用节点的二层网络直接发送Pod的通信报文。它的工作方式类似于Directrouting的功能,但
是其并不具备VxLan的隧道转发能力。
​   编辑kube-flannel的配置清单,将ConfigMap资源kube-flannel-cfg的data字段中网络配置进行修改,
如下:
[root@master ~]# vim kube-flannel.yml 
......
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }
......
[root@master ~]# kubectl apply -f kube-flannel.yml 
配置完成后,各节点会生成类似directrouting一样的 路由,用于实现二层转发Pod网络的通信报文,省
去了隧道转发模式的额外开销。但是存在的问题点是,对于不在同一个二层网络的报文转发,host-gw是
无法实现的。延续上面的例子,进行抓包查看:
查看路由信息
[root@master ~]# ip route
......
10.244.1.0/24 via 10.249.2.101 dev bond0 
10.244.2.0/24 via 10.249.2.102 dev bond0 
......
在抓包

该模式下,报文转发的相关流程如下:
1、Pod(10.244.2.74)向Pod(10.244.1.42)发送报文,查看到报文中的目的地址为:10.244.1.42,并非本地网段,会直接发送到网关(10.249.6.101);
2、网关发现该目标地址为10.244.2.73,要到达10.244.1.0/24网段,需要送达到node2的物理网卡,node2接收以后发现该报文的目标地址属于本机上的另一个虚拟网卡,然后转发到相对应的Pod(10.244.2.73)

​    以上就是Flannel网络模型的三种工作模式,但是flannel自身并不具备为Pod网络实现网络策略和网络通信隔离的功能,为此只能借助于Calico联合统一的项目Calnal项目进行构建网络策略的功能。

###################################
    网络策略(Network Policy )是 Kubernetes 的一种资源。Network Policy 通过 Label选择 Pod并指定其他 Pod 或外界如何与这些 Pod 通信。
    Pod的网络流量包含流入(Ingress)和流出(Egress)两种方向。默认情况下,所有 Pod是非隔离的,即任何来源的网络流量都能够访问 Pod,没有任何限制。当为 Pod 定义了 Network Policy,只有 Policy 允许的流量才能访问 Pod。
​    Kubernetes的网络策略功能也是由第三方的网络插件实现的,因此,只有支持网络策略功能的网络插件才能进行配置网络策略,比如Calico、Canal、kube-router等等。

部署Canal提供网络策略功能
​    Calico可以独立地为Kubernetes提供网络解决方案和网络策略,也可以和flannel相结合,由flannel提供网络解决方案,Calico仅用于提供网络策略,此时将Calico称为Canal。结合flannel工作时,Calico提供的默认配置清单式以flannel默认使用的10.244.0.0/16为Pod网络,因此在集群中kube-controller-manager启动时就需要通过--cluster-cidr选项进行设置使用该网络地址,并且---allocate-node-cidrs的值应设置为true。

[root@master ~]#  kubectl apply -f https://docs.projectcalico.org/v3.2/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
clusterrole.rbac.authorization.k8s.io/calico created
clusterrole.rbac.authorization.k8s.io/flannel unchanged
clusterrolebinding.rbac.authorization.k8s.io/canal-flannel created
clusterrolebinding.rbac.authorization.k8s.io/canal-calico created
[root@master ~]# kubectl apply -f https://docs.projectcalico.org/v3.2/getting-started/kubernetes/installation/hosted/canal/canal.yaml
configmap/canal-config created
daemonset.extensions/canal created
serviceaccount/canal created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
[root@master ~]# kubectl get ds canal -n kube-system
NAME    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
canal   3         3         0       3            0           beta.kubernetes.io/os=linux   16s
[root@master ~]# kubectl get pods -n kube-system -o wide |grep canal
canal-9wbdl                            0/3     ContainerCreating   0          28s   10.249.6.102   node02            
canal-cr7rx                            0/3     ContainerCreating   0          28s   10.249.6.100   master            
canal-q7mc2                            0/3     ContainerCreating   0          28s   10.249.6.101   node01            

[root@master ~]# kubectl get pod -n kube-system -o wide
NAME                                   READY   STATUS              RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
canal-9wbdl                            0/3     ContainerCreating   0          4m12s   10.249.6.102   node02            
canal-cr7rx                            0/3     ContainerCreating   0          4m12s   10.249.6.100   master            
canal-q7mc2                            0/3     ContainerCreating   0          4m12s   10.249.6.101   node01            
coredns-86c58d9df4-fltl9               1/1     Running             2          33d     10.244.0.7     master            
coredns-86c58d9df4-kdm2h               1/1     Running             2          33d     10.244.0.8     master            
etcd-master                            1/1     Running             4          33d     10.249.6.100   master            
heapster-5b4b969847-x2rqd              1/1     Running             0          8d      10.244.2.68    node02            
kube-apiserver-master                  1/1     Running             2          33d     10.249.6.100   master            
kube-controller-manager-master         1/1     Running             2          33d     10.249.6.100   master            
kube-flannel-ds-amd64-bf7s9            1/1     Running             0          9d      10.249.6.101   node01            
kube-flannel-ds-amd64-vm9vw            1/1     Running             4          9d      10.249.6.102   node02            
kube-flannel-ds-amd64-xqcg9            1/1     Running             1          9d      10.249.6.100   master            
kube-proxy-6fp6m                       1/1     Running             1          33d     10.249.6.102   node02            
kube-proxy-wv6gg                       1/1     Running             0          33d     10.249.6.101   node01            
kube-proxy-zndjb                       1/1     Running             2          33d     10.249.6.100   master            
kube-scheduler-master                  1/1     Running             2          33d     10.249.6.100   master            
kubernetes-dashboard-57df4db6b-cr5qw   1/1     Running             0          8d      10.244.2.61    node02            
monitoring-grafana-564f579fd4-22lrq    1/1     Running             0          8d      10.244.2.66    node02            
monitoring-influxdb-8b7d57f5c-5bkrh    1/1     Running             0          8d      10.244.2.67    node02            

[root@master ~]# kubectl describe pod canal-9wbdl -n kube-system

Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  5m42s  default-scheduler  Successfully assigned kube-system/canal-9wbdl to node02
  Normal  Pulling    5m41s  kubelet, node02    pulling image "quay.io/calico/node:v3.2.7"     这里一直在努力pull
  
部署canal需要的镜像,建议先拉取镜像,避免耗死资源:
quay.io/calico/node:v3.2.6
quay.io/calico/cni:v3.2.6
quay.io/coreos/flannel:v0.9.1

我这里等了一晚上,建议先下载
[root@master ~]# kubectl get pods -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
canal-9wbdl                            3/3     Running   0          21h
canal-cr7rx                            3/3     Running   0          21h
canal-q7mc2                            3/3     Running   0          21h
[root@master ~]# kubectl get pod -n kube-system -o wide
NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
canal-9wbdl                            3/3     Running   0          21h   10.249.6.102   node02            
canal-cr7rx                            3/3     Running   0          21h   10.249.6.100   master            
canal-q7mc2                            3/3     Running   0          21h   10.249.6.101   node01            

​    Canal作为DaemonSet部署到每个节点,属于kube-system这个名称空间。需要注意的是,Canal只是直
接使用了Calico和flannel项目,代码本身没有修改,Canal只是一种部署的模式,用于安装和配置项目。
========================

你可能感兴趣的:(devops)