虚拟化容器,大数据,DBA,中间件,监控。

K8s网络组件之Flannel:VXLAN模式

06 02月
作者:admin|分类:容器虚拟化

K8s网络模型: CNI(容器网络接口)


CNI(Container Network Interface,容器网络接口):是一个容器网络规范,Kubernetes网络采用的就是这个CNI规 范,负责初始化infra容器的网络设备。

  • CNI二进制程序默认路径:/opt/cni/bin/

  • 项目地址:https://github.com/containernetworking/cni

以Flannel网络组件为例,当部署Flanneld后,会在每台宿主机上生成它对应的CNI配置文件(它其实是一个ConfigMap),从而告诉Kubernetes要使用 Flannel 作为容器网络方案。

CNI配置文件默认路径:/etc/cni/net.d

当 kubelet 组件需要创建 Pod 的时候,先调用dockershim它先创建一个 Infra 容器。然后调用 CNI 插件为 Infra 容器配置网络。

这两个路径可在kubelet启动参数中定义:

--network-plugin=cni

--cni-conf-dir=/etc/cni/net.d

--cni-bin-dir=/opt/cni/bin

下面放置着CNI网络插件的二进制程序,通过这些程序完成与cni的对接

[root@k8s-master ~]# ls /opt/cni/bin/
bandwidth  dhcp      flannel      host-local  loopback  portmap  sbr     tuning
bridge     firewall  host-device  ipvlan      macvlan   ptp      static  vlan

CNI配置文件默认路径:/etc/cni/net.d 

[root@k8s-master ~]# ls /etc/cni/net.d/
10-flannel.conflist


[root@k8s-master ~]# cat /etc/cni/net.d/10-flannel.conflist 
{
  "name": "cbr0",
  "cniVersion": "0.3.1",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

这里面就包含了配置内容

所以cni参数都是在kubelet上面配置的,以为它负责创建容器并且为其配置容器网络

CNI的配置是有下面三个参数,第一个就是启用cni网络插件,也就是k8s要使用cni就必须启用

简单说cni就是网络组件的接口,好让第三方的网络都能接入到k8s网络里面来

--network-plugin=cni
--cni-conf-dir=/etc/cni/net.d
--cni-bin-dir=/opt/cni/bin

 

K8s网络组件之Flannel


Flannel是CoreOS维护的一个网络组件,Flannel为每个Pod提供全局唯一的IP,Flannel使用ETCD来存储Pod子网与Node IP之间的关系。flanneld守护进程在每台主机上运行,并负责维护ETCD信息和路由数据包。

这句话体现的几点:

  • 守护进程

  • 使用存储etcd来pod子网和nodeip之前关系,使用ETCD存储子网

  • 提供全局的IP

项目地址: https://github.com/coreos/flannel

YAML地址:https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

 

K8s网络组件之Flannel:部署


在这个文件当中需要了解这个,配置网络相关的信息,配置子网和工作模式,这两个你可能需要修改,Backend:指定工作模式

net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
}

使用的是deamonset部署的

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-amd64
  namespace: kube-system

在部署之前需要做的事情

10.244.0.0/16 这是一个大的子网,会确保每个node都分配到独立的网段

• Network:指定Pod IP分配的网段,与controller-manager配置的保持一样

--allocate-node-cidrs=true

--cluster-cidr=10.244.0.0/16

• kubeadm部署:/etc/kubernetes/manifests/kube-controller-manager.yaml

• 二进制部署:/opt/kubernetes/cfg/kube-controller-manager.conf

 我这里部署集群默认是配置好了,就不需要修改了

[root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-controller-manager.yaml
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
    - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --bind-address=127.0.0.1
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
- --cluster-cidr=10.244.0.0/16


[root@k8s-master ~]# cat /opt/kubernetes/cfg/kube-controller-manager.conf 
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
--leader-elect=true \
--master=127.0.0.1:8080 \
--bind-address=127.0.0.1 \
--allocate-node-cidrs=true \
--cluster-cidr=10.244.0.0/16 \
--service-cluster-ip-range=10.0.0.0/24 \
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem  \
--root-ca-file=/opt/kubernetes/ssl/ca.pem \
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \
--experimental-cluster-signing-duration=87600h0m0s"

如果部署了calico那么先删除,在一个k8s网络当中只能使用一个网络组件

[root@k8s-master ~]# kubectl delete -f calico.yaml 
[root@k8s-master ~]# rm -f /etc/cni/net.d/10-calico.conflist /etc/cni/net.d/calico-kubeconfig 
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml 


[root@k8s-master ~]# kubectl get pod -n kube-system 
NAME                          READY   STATUS    RESTARTS   AGE
kube-flannel-ds-amd64-lb6vm   1/1     Running   0          139d
kube-flannel-ds-amd64-lxxdq   1/1     Running   0          139d
kube-flannel-ds-amd64-vl4fn   1/1     Running   0          139d

 

 

K8s网络组件之Flannel:工作模式


Flannel支持多种工作模式:
  • UDP:最早支持的一种方式,由于性能最差,目前已经弃用。

  • VXLAN:Overlay Network方案,源数据包封装在另一种网络包里面进行路由转发和通信

  • Host-GW:Flannel通过在各个节点上的Agent进程,将容器网络的路由信息写到主机的路由表上,这样一来所有的主机都有整个容器网络的路由数据了。

  • Directrouting:同时支持VXLAN和Host-GW工作模式

  • 公有云VPC:ALIYUN,AWS

 

K8s网络组件之Flannel:VXLAN模式


VXLAN介绍
VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是 Linux 内核本身就支持的一种网络虚似化技术。VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。
VXLAN的覆盖网络设计思想:在现有的三层网络之上,覆盖一层二层网络,使得连接在这个VXLAN
二层网络上的主机之间,可以像在同一局域网里通信。为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。

隧道模式内部自己实现了封装方式,VETP设备用于封包和解包

VTEP设备进行封装和解封装的对象是二层数据帧,这个工作是在Linux内核中完成的。

 
Flannel工作逻辑图如下:

[root@k8s-master ~]# ifconfig
cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.1  netmask 255.255.255.0  broadcast 10.244.0.255
        inet6 fe80::ec98:8bff:fea1:554d  prefixlen 64  scopeid 0x20<link>
        ether ee:98:8b:a1:55:4d  txqueuelen 1000  (Ethernet)
        RX packets 35973  bytes 9023583 (8.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40472  bytes 28071561 (26.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:b9:2e:09:e2  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.179.99  netmask 255.255.255.0  broadcast 192.168.179.255
        inet6 fe80::54c7:3ae8:3659:6b97  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:b4:88:32  txqueuelen 1000  (Ethernet)
        RX packets 5674009  bytes 2565682866 (2.3 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6213197  bytes 4945068979 (4.6 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.0  netmask 255.255.255.255  broadcast 0.0.0.0
        inet6 fe80::2027:5aff:fef0:9316  prefixlen 64  scopeid 0x20<link>
        ether 22:27:5a:f0:93:16  txqueuelen 0  (Ethernet)
        RX packets 3604  bytes 2986402 (2.8 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2830  bytes 585691 (571.9 KiB)
        TX errors 1  dropped 8 overruns 0  carrier 1  collisions 0


vethf5cad454: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet6 fe80::6401:bbff:fe31:76bd  prefixlen 64  scopeid 0x20<link>
        ether 66:01:bb:31:76:bd  txqueuelen 0  (Ethernet)
        RX packets 6  bytes 509 (509.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13  bytes 1000 (1000.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@k8s-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.10,那么就会走这个路由表
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 
这个路由表的下一条是 10.244.1.0 
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.0

 

K8s网络组件之Flannel


Flannel是CoreOS维护的一个网络组件,Flannel为每个Pod提供全局唯一的IP,Flannel使用ETCD来存储Pod子网与Node IP之间的关系。flanneld守护进程在每台主机上运行,并负责维护ETCD信息和路由数据包。
  • 项目地址: https://github.com/coreos/flannel

  • YAML地址:https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

 

 

下面看看vxlan模式下,不同主机的pod通信


Pod1容器当中发出了数据包,这个数据包会到达宿主机上面的cni0这个网桥,前面的流程和docker流程一样,只要发送数据包肯定要到达cni0,cni0在这里充当了网桥的作用,二层交换,容器以cni0的网桥作为网关,不管是不是处于同网段都会到达cni0网桥这里,这是第一步

第二步 数据包已经到达了宿主机上面,宿主机上面的网络协议栈可以看到这个数据包的,所以会根据路由表转发到flannel.1这张虚拟网卡,也即是来到了隧道的入口

[root@k8s-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.10,那么就会走这个路由表
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 
这个路由表的下一条是 10.244.1.0 
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.0

这样数据包来到宿主机查看宿主机上面的路由表发到下一跳即flannel.1设备

flannel.1设备这个设备是完成vetp这个设备封装的,就相当于隧道的入口,之后就要使用xvlan对其进行封装,封装之后再走宿主机上面的网络,这里数据的封包是二层的

封装包必须要有目标的mac地址

flannel.1就是vetp设备,基于二层去封装,那么必须知道目标mac地址是谁,这里源IP目标IP都知道

查看这个网卡的arp信息,这两个就是地址就是另外两台机器上面的 flannel.1 mac地址

[root@k8s-master ~]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP            NODE         NOMINATED NODE   READINESS GATES
kubia-859d757f8c-74g6s   1/1     Running   0          124d   10.244.2.4    k8s-node2    <none>           <none>
kubia-859d757f8c-97znt   1/1     Running   0          124d   10.244.0.14   k8s-master   <none>           <none>
kubia-859d757f8c-9mjf9   1/1     Running   0          124d   10.244.1.5    k8s-node1    <none>           <none>


[root@k8s-master ~]# ifconfig 
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.0.0
[root@k8s-node1 ~]# ifconfig 
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.1.0
[root@k8s-node2 ~]# ifconfig
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.2.0

其实在flanneld进程启动后,就会自动添加其他节点ARP记录,可以通过ip neigh show dev flannel.1命令查看
[root@k8s-master ~]# ip neigh show dev flannel.1
10.244.2.0 lladdr 4a:5a:f0:f5:19:5e PERMANENT
10.244.1.0 lladdr b6:68:f7:5e:af:9c PERMANENT

这个走的是二层的
[root@k8s-master ~]# bridge fdb show dev flannel.1
b6:68:f7:5e:af:9c dst 192.168.179.100 self permanent
4a:5a:f0:f5:19:5e dst 192.168.179.101 self permanent

找到宿主机的IP就可以向这个宿主机发送UDP的数据包

 

 

K8s网络组件之Flannel:VXLAN模式


如果Pod 1访问Pod 2,源地址10.244.1.10,目的地址10.244.2.10 ,数据包传输流程如下:
1.容器路由: 容器根据路由表,将数据包发送下一跳10.244.0.1,从eth0网卡出。可以使用ip route命令查看路由表
2.主机路由: 数据包进入到宿主机虚拟网卡cni0,根据路由表转发到flannel.1虚拟网卡,也就是来到了隧道的入口。
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink # 凡是发往10.244.2.0/24网段的数据包,都需要经过flannel.1设备发出,并且下一跳是10.244.2.0,即Node2 VTEP设备flannel.1。
3.VXLAN封装: 而这些VTEP设备之间组成一个二层网络,但是二层网络必须要知道目的MAC地址,那这个MAC地址从哪获取到呢? 其实在flanneld进程启动后,就会自动添加其他节点ARP记录,可以通过ip neigh show dev flannel.1命令查看。
4.二次封包: 知道了目的MAC地址,Linux内核就可以进行二层封包了。 但是,对于宿主机网络来说这个二层帧并不能在宿主机二层网络里传输 。所以接下来,Linux内核还要把这个数据帧进一步封装成为宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过宿主机的eth0网卡进行传输。 数据格式如下图:

5.封装到UDP包发出去 :在封装成宿主机网络可传输的数据帧时,还缺少目标宿主机MAC地址,也就是说这个UDP包该发给哪台宿主机呢? flanneld进程也维护着一个叫做FDB的转发数据库,可以通过bridge fdb show dev flannel.1命令查看。 可以看到,上面用的对方flannel.1的MAC地址 对应宿主机IP,也就是UDP要发往的目的地。所以使用这个目的IP与MAC地址进行封装。
6.数据包到达目的宿主机: 接下来,就是宿主机与宿主机之间通信了, 数据包从Node1的eth0网卡发出去,Node2接收到数据包,解封装发现是VXLAN数据包,把它交给flannel.1设备。flannel.1设备则会进一步拆包,取出原始IP包(源容器IP和目标容器IP),通过cni0网桥二层转发给容器。
浏览397 评论0
返回
目录
返回
首页
在 Kubernetess 中使用 DNS 和 Headless Service 发现运行中的 Pod DNS实战