k8s-flannel

发布时间 2023-03-22 21:15:57作者: yuanbangchen
一、Flannel介绍
Flannel是由CoreOS开源的针对k8s的网络服务,其目的是为解决k8s集群中各主机上Pod之间的通信问题,其借助etcd维护网络IP地址分配,并为每个Node节点分配一个不同的IP地址段。

Flannel在每个节点运行一个名为flanneld的二进制代理程序,它负责从预留的网络中按照指定或者默认的掩码长度为当前节点申请分配一个子网,并将网络配置、
已分配的子网和辅助数据(比如主机的公网IP等)存储在Kubernetes API或独立的etcd中。Flannel通过不同的后端来实现跨节点Pod间的通信,目前支持的后端如下:

1.vxlan:Linux 内核在在2012年底的v3.7.0之后加入了VXLAN协议支持,使用Linux内核中的封装隧道报文,以Overlay模型支持跨节点的Pod通信,同时该后端支持直接路由模式(Directrouting,类似于host-gw模式),在该模式下,
位于同一个二层网络中的节点上的Pod间通信可通过路由模式直接发送,而跨二层网络的节点之上的Pod间通信仍要使用VXLAN隧道协议转发;
因而VXLAN隶属于Overlay网络模型,或者混合网络模型,,在基础网络上叠加的一种虚拟网络技术模式,该网络中的主机通过虚拟链路连接起来类似VPN隧道,原理为在物理网络上实现的逻辑网络。
vxlan模型中,flanneld监听udp 8472端口接受和发送封装的数据包.

Directrouting 为在同一个二层网络中的node节点启用直接路由机制,类似于host-gw模式,启用后路由表中的Iface中没有Flannel.1接口,而是使用宿主机的接口转发。

2.host-gw:类似于VXLAN后端的直接路由模式,但不支持跨二层网络(须处于同一个局域网)的节点,因此这种模式要求各节点处于同一个二层网络中,不太适用于规模较大的环境,但转发性能较好

3.udp:使用常规UDP报文封装完成隧道转发,性能比vxlan和host-gw相比较差,仅在不支持vxlan和host-gw时使用;UDP后端模式中,flanneld监听UDP 8285端口发送报文(1.15版本已停用)


Pod通信流程分析文档
https://blog.csdn.net/weixin_43266367/article/details/127836595

K8S 中 Pod 网络通信        
(1)Pod 内容器与容器之间的通信
在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享同一个网络命令空间,相当于它们在同一台机器上一样,可以用 localhost 地址访问彼此的端口。
(2)同一个 Node 内 Pod 之间的通信
每个 Pod 都有一个真实的全局 IP 地址,同一个 Node 内的不同 Pod 之间可以直接采用对方 Pod 的 IP 地址进行通信,Pod1 与 Pod2 都是通过 Veth 连接到同一个 CNI0 网桥,网段相同,所以它们之间可以直接通信。
(3)不同 Node 上 Pod 之间的通信
Pod 地址与 CNI0 在同一网段,CNI0 网段与宿主机网卡是两个不同的网段,且不同 Node 之间的通信只能通过宿主机的物理网卡进行。
要想实现不同 Node 上 Pod 之间的通信,就必须想办法通过主机的物理网卡 IP 地址进行寻址和通信。因此要满足两个条件:Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,
通过这个关联让不同 Node 上 Pod 之间直接通过内网 IP 地址通信。

calico和flannel
    calico支持更多的网络层的安全策略,flannel不支持
    公有云大多数都是使用的flannel,早期使用UDP,后来有了vxlan之后就使用vxlan+Directrouting
    自建IDC里面使用什么都可以,flannel配置比较交单,calico功能更加完善
    性能差别不是很大,据统计,calico性能略高于flannel
    私有云推荐使用calico
    公有云可以使用flannel    

Flannel 组件的解释:
Cni0:网桥设备,每创建一个pod都会创建一对 veth pair,其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡),Pod中从网卡eth0发出的流量都会发送到Cni0网桥设备的端口(网卡)上,Cni0设备获得的ip地址是该节点分配到的网段的第一个地址。
Flannel.1: overlay网络的设备,用来进行vxlan报文的处理(封包和解包),不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端。




flannel还会在运行的每个node节点上生成一个环境变量文件,默认是/run/flannel/subnet.env,其包含本节点使用的子网、mtu等信息。例如下面的示例:
root@master-01:~# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.20.0.0/16    #flannel全局网段
FLANNEL_SUBNET=10.20.2.1/24    #本节点子网
FLANNEL_MTU=1450    #容器接口mtu值
FLANNEL_IPMASQ=true    #地址映射



Flannel官方的部署文件默认使用vxlan后端,相关配置定义在kube-flannel名称空间下configmap/kube-flannel-cfg资源对象中,
/var/lib/kubelet/pods/ID/volumes/kubernetes.io~configmap/flannel-cfg/net-conf.json:内容如下
  net-conf.json: |
    {
      "Network": "10.20.0.0/16",    
      "Backend": {        
        "Type": "vxlan",
        "Directrouting": true
      }
    }
如上所示,其配置是json格式,常用的键有如下几个:
Network:    Flannel全局使用的子网,即pod cidr的值
SubnetLen:子网分割的长度,在全局子网掩码小于24时(例如16),默认为24
SubnetMin:分配给节点使用的起始子网,默认为切割完成后的第一个子网
SubnetMax:分给给节点使用的最大子网,默认为切割完成后的最后一个子网
Backend:        Flannel使用的后端,以及后端的配置
Directrouting: 直接路由模式



当前node主机cni信息:
[root@localhost7F ~]# cat  /var/lib/cni/flannel/222021ac78e25174272ce8d7f3d5f74cf0e31d9a122f82a0fb42a5cc7fd367e4 
{"cniVersion":"0.3.1","hairpinMode":true,"ipMasq":false,"ipam":{"routes":[{"dst":"10.20.0.0/16"}],"subnet":"10.20.2.0/24",
"type":"host-local"},"isDefaultGateway":true,"isGateway":true,"mtu":1450,"name":"cbr0","type":"bridge"}

二、测试

#vxlan转发测试

#创建pod测试夸主机网络通信是否正常(域名无法ping通,是DNS没有设置)
kubectl run net-test1 --image=alpine --replicas=4 sleep 360000 

[root@localhost7C ~]# kubectl exec   -it net-test1-5fcc69db59-dlwmh sh
/ # traceroute 10.20.5.7
traceroute to 10.20.5.7 (10.20.5.7), 30 hops max, 46 byte packets
 1  10.20.2.1 (10.20.2.1)  0.006 ms  0.006 ms  0.003 ms
 2  10.20.5.0 (10.20.5.0)  1.367 ms  0.747 ms  0.213 ms            #使用Flannel.1转发
 3  10.20.5.7 (10.20.5.7)  12.041 ms  0.572 ms  0.272 ms


[root@localhost7C ~]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.80.2    0.0.0.0         UG    100    0        0 eth0
10.20.1.0       10.20.1.0       255.255.255.0   UG    0      0        0 flannel.1
10.20.2.0       10.20.2.0       255.255.255.0   UG    0      0        0 flannel.1
10.20.3.0       10.20.3.0       255.255.255.0   UG    0      0        0 flannel.1
10.20.4.0       10.20.4.0       255.255.255.0   UG    0      0        0 flannel.1
10.20.5.0       10.20.5.0       255.255.255.0   UG    0      0        0 flannel.1  #使用Flannel.1转发
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 eth1
192.168.80.0    0.0.0.0         255.255.255.0   U     100    0        0 eth0
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

[root@localhost7C ~]# kubectl  get pod   -A   -o wide
NAMESPACE              NAME                                         READY   STATUS             RESTARTS   AGE    IP               NODE             NOMINATED NODE   READINESS GATES
default                net-test1-5fcc69db59-dlwmh                   1/1     Running            1          3d     10.20.2.6        192.168.80.150   <none>           <none>
default                net-test1-5fcc69db59-sk2xw                   1/1     Running            1          3d     10.20.5.7        192.168.80.170   <none>           <none>
default                net-test1-5fcc69db59-tszvf                   1/1     Running            1          3d     10.20.5.9        192.168.80.170   <none>           <none>
default                net-test1-5fcc69db59-v7zqg                   1/1     Running            1          3d     10.20.3.8        192.168.80.160   <none>           <none>
kube-system            kube-dns-6b65447b86-wh2fp                    3/3     Running            3          47h    10.20.3.7        192.168.80.160   <none>           <none>
kube-system            kube-flannel-ds-amd64-bl89w                  1/1     Running            0          15s    192.168.80.130   192.168.80.130   <none>           <none>
kube-system            kube-flannel-ds-amd64-ddfjm                  1/1     Running            0          15s    192.168.80.160   192.168.80.160   <none>           <none>
kube-system            kube-flannel-ds-amd64-jjsx4                  1/1     Running            0          15s    192.168.80.140   192.168.80.140   <none>           <none>
kube-system            kube-flannel-ds-amd64-rn9c8                  1/1     Running            0          15s    192.168.80.170   192.168.80.170   <none>           <none>
kube-system            kube-flannel-ds-amd64-v5758                  1/1     Running            0          15s    192.168.80.150   192.168.80.150   <none>           <none>
kube-system            kube-flannel-ds-amd64-vdf4v                  1/1     Running            0          15s    192.168.80.120   192.168.80.120   <none>           <none>


删除flannel网络方法:
# 主节点
kubectl delete   -f /opt/kube/kube-system/flannel.yaml

# 所有节点上(master没有cni0)
systemctl stop kubelet
ifconfig  cni0 down
ifconfig  flannel.1 down

ip link set cni0 down
ip link set flannel.1 down
 
ip link delete cni0
ip link delete flannel.1
 
rm -rf /var/lib/cni/*
rm -rf /etc/cni/net.d/*
systemctl start kubelet



#ansible设置VXLAN+Directrouting
[root@localhost7B ansible]# cat  roles/flannel/defaults/main.yml 
# 部分flannel配置,参考 docs/setup/network-plugin/flannel.md
# 设置flannel 后端
FLANNEL_BACKEND: "vxlan"
DIRECT_ROUTING: "true"          #启用"Directrouting"
#flanneld_image: "quay.io/coreos/flannel:v0.10.0-amd64"
flanneld_image: "easzlab/flannel:v0.11.0-amd64"
# 离线镜像tar包
flannel_offline: "flannel_v0.11.0-amd64.tar"



#使用VXLAN+Directrouting测试
[root@localhost7F ~]# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.80.2    0.0.0.0         UG    100    0        0 eth0
10.20.0.0       192.168.80.120  255.255.255.0   UG    0      0        0 eth0
10.20.1.0       192.168.80.130  255.255.255.0   UG    0      0        0 eth0
10.20.2.0       0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.20.3.0       192.168.80.160  255.255.255.0   UG    0      0        0 eth0
10.20.4.0       192.168.80.140  255.255.255.0   UG    0      0        0 eth0    
10.20.5.0       192.168.80.170  255.255.255.0   UG    0      0        0 eth0   #使用宿主机的接口转发
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 eth1
192.168.80.0    0.0.0.0         255.255.255.0   U     100    0        0 eth0
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0


[root@localhost7C ~]# kubectl exec   -it net-test1-5fcc69db59-dlwmh sh
/ # traceroute 10.20.5.7
traceroute to 10.20.5.7 (10.20.5.7), 30 hops max, 46 byte packets
 1  10.20.2.1 (10.20.2.1)  0.007 ms  0.008 ms  0.003 ms
 2  192.168.80.170 (192.168.80.170)  0.276 ms  0.363 ms  0.156 ms   #使用宿主机的接口转发
 3  10.20.5.7 (10.20.5.7)  0.283 ms  0.758 ms  1.136 ms




host-gw测试,与VXLAN+Directrouting一样,先删除flannel网络:

[root@localhost7B ansible]# cat  roles/flannel/defaults/main.yml 
# 部分flannel配置,参考 docs/setup/network-plugin/flannel.md
# 设置flannel 后端
#FLANNEL_BACKEND: "host-gw"
#flanneld_image: "quay.io/coreos/flannel:v0.10.0-amd64"
flanneld_image: "easzlab/flannel:v0.11.0-amd64"
# 离线镜像tar包
flannel_offline: "flannel_v0.11.0-amd64.tar"


[root@localhost7C ~]# kubectl exec   -it net-test1-5fcc69db59-dlwmh sh
/ # traceroute 10.20.5.7
traceroute to 10.20.5.7 (10.20.5.7), 30 hops max, 46 byte packets
 1  10.20.2.1 (10.20.2.1)  0.007 ms  0.008 ms  0.003 ms
 2  192.168.80.170 (192.168.80.170)  0.276 ms  0.363 ms  0.156 ms   #使用宿主机的接口转发
 3  10.20.5.7 (10.20.5.7)  0.283 ms  0.758 ms  1.136 ms

三、flannel  yaml文件

---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp.flannel.unprivileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
    seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
    apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
    apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
  privileged: false
  volumes:
    - configMap
    - secret
    - emptyDir
    - hostPath
  allowedHostPaths:
    - pathPrefix: "/etc/cni/net.d"
    - pathPrefix: "/etc/kube-flannel"
    - pathPrefix: "/run/flannel"
  readOnlyRootFilesystem: false
  # Users and groups
  runAsUser:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  # Privilege Escalation
  allowPrivilegeEscalation: false
  defaultAllowPrivilegeEscalation: false
  # Capabilities
  allowedCapabilities: ['NET_ADMIN']
  defaultAddCapabilities: []
  requiredDropCapabilities: []
  # Host namespaces
  hostPID: false
  hostIPC: false
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  # SELinux
  seLinux:
    # SELinux is unsed in CaaSP
    rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: flannel
rules:
  - apiGroups: ['policy']
    resources: ['podsecuritypolicies']
    verbs: ['use']
    resourceNames: ['psp.flannel.unprivileged']
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes/status
    verbs:
      - patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.20.0.0/16",
      "Backend": {
        "DirectRouting": true,
        "Type": "vxlan"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-amd64
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - amd64
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: easzlab/flannel:v0.11.0-amd64 
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: easzlab/flannel:v0.11.0-amd64 
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
             add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg