使用multus實現管理網和業務網分離——calico和flannel共存

shininglight發表於2021-06-09

多個網路層面的需求

一開始為k8s叢集搭建了calico網路,所有的容器都用calico對應的網路卡進行通訊。為了實現網路監控的清爽,想把管理元件,例如日誌、統計、監控等元件挪到另外一個網路。於是產生一個想法把管理網和業務網分離,這裡採用相對成熟的multus來粘合calico和flannel網路。讓所有的業務容器走calico網路,讓管理容器走flannel網路。其實hostlocal模式的容器也是走的管理網。

首先搭建一個預設網路

這裡把calico作為預設網路,因此需要先搭建好calico網路,參見之前的博文如何搭建calico網路。

建立flannel叢集

對Kubernetes v1.17+ 叢集使用如下命令

  kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

該命令會在每個節點建立一個flannel容器

[root@k8s-master multus]# kubectl get pods  -o wide -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
kube-system   calico-kube-controllers-65d7476764-qrp8r   1/1     Running   0          152m    10.200.113.137   k8s-node     <none>           <none>
kube-system   calico-node-b62rz                          1/1     Running   0          152m    192.168.31.128   k8s-master   <none>           <none>
kube-system   calico-node-mchl8                          1/1     Running   0          152m    192.168.31.129   k8s-node     <none>           <none>
kube-system   coredns-7ff77c879f-j89ch                   1/1     Running   1          75d     10.200.113.131   k8s-node     <none>           <none>
kube-system   coredns-7ff77c879f-x47fq                   1/1     Running   1          75d     10.200.235.194   k8s-master   <none>           <none>
kube-system   etcd-k8s-master                            1/1     Running   3          257d    192.168.31.128   k8s-master   <none>           <none>
kube-system   kube-apiserver-k8s-master                  1/1     Running   4          72d     192.168.31.128   k8s-master   <none>           <none>
kube-system   kube-controller-manager-k8s-master         1/1     Running   0          72d     192.168.31.128   k8s-master   <none>           <none>
kube-system   kube-flannel-ds-mqkmc                      1/1     Running   0          2m12s   192.168.31.128   k8s-master   <none>           <none>
kube-system   kube-flannel-ds-x62mj                      1/1     Running   0          2m12s   192.168.31.129   k8s-node     <none>           <none>

這裡有兩點需要注意:

  1. flannel會自動讀取k8s-api-server的cluster-cidr資訊,也就是/etc/kubernetes/manifests/kube-controller-manager.yaml 檔案中的--cluster-cidr引數,要注意這個地址的有效性,不能和其他網路的有重疊。例如不能和calico網路重疊也不能和--service-cluster-ip-range重疊。
  2. 如果想要flannel繫結指定網路卡,可以修改kube-flannel.yml檔案,新增--iface-regex或者--iface相關引數,如下所示:
args:
- --ip-masq
- --kube-subnet-mgr
- --iface-regex=172.18.(.*)  //注意等號兩邊不能有空格,後面的正規表示式不用加引號 
- --iface=eth0 //如果網路卡名固定的話,最好用這句配置,並且iface可以覆蓋iface-regex

建立完成後,檢視flannel分配給容器的IP地址段:

[root@k8s-master multus]# kubectl exec -ti -n kube-system   kube-flannel-ds-mqkmc cat /run/flannel/subnet.env 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

另外,檢視flannel繫結的網路卡:

[root@k8s-master ~]# ip -d link show flannel.1
18: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/ether ba:ad:f0:ca:4e:6d brd ff:ff:ff:ff:ff:ff promiscuity 0 
    vxlan id 1 local 192.168.31.128 dev ens33 srcport 0 0 dstport 8472 nolearning ageing 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 

可以看到vtep裝置flannel.1繫結的網路卡是ens33,flannel.1會把資料包封裝成vxlan資料包從ens33傳送出去。

使用multus把calico和flannel粘合起來

multus可以管理多個網路外掛,可以通過設定相關引數使得容器使用多個網路卡而且每個網路卡使用不同的網路外掛,也可以指定使用一種網路。如果什麼都不指定就使用預設網路。

建立multus叢集

kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/images/multus-daemonset.yml

該命令會建立multus叢集,每個節點建立一個multus容器。在任意一個節點上檢視cni配置檔案,如下所示:

[root@k8s-master ~]# ls /etc/cni/net.d/
00-multus.conf  10-calico.conflist  10-flannel.conflist  calico-kubeconfig  multus.d
[root@k8s-master ~]# 
[root@k8s-master ~]# cat /etc/cni/net.d/00-multus.conf 
{ "cniVersion": "0.3.1", "name": "multus-cni-network", "type": "multus", "capabilities": {"portMappings": true, "bandwidth": true}, "kubeconfig": "/etc/cni/net.d/multus.d/multus.kubeconfig", "delegates": [ { "name": "k8s-pod-network", "cniVersion": "0.3.1", "plugins": [ { "type": "calico", "log_level": "info", "log_file_path": "/var/log/calico/cni/cni.log", "datastore_type": "kubernetes", "nodename": "k8s-master", "mtu": 0, "ipam": { "type": "calico-ipam" }, "policy": { "type": "k8s" }, "kubernetes": { "kubeconfig": "/etc/cni/net.d/calico-kubeconfig" } }, { "type": "portmap", "snat": true, "capabilities": {"portMappings": true} }, { "type": "bandwidth", "capabilities": {"bandwidth": true} } ] } ] }
[root@k8s-master ~]# 

可以看出cni配置檔案中有calico、flannel和multus.其中誰的序號小就用誰,這裡使用multus,而multus配置檔案中寫明使用的預設網路外掛是calico.

建立使用calico網路的容器

因為multus使用的預設網路是calico,因此像往常一樣不用修改任何檔案建立出來的容器就是使用的calico網路外掛。當然不能在yaml檔案中指定使用hostlocal網路"hostNetwork: true".

建立使用flannel網路的容器

首先建立一個資源:

cat <<EOF | kubectl create -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: flannel-conf
spec: 
  config: '{
    "cniVersion": "0.3.0",
    "type": "flannel",
    "delegate": {
      "isDefaultGateway": true
    }
  }'
EOF

使用命令kubectl get networkattachmentdefinition.k8s.cni.cncf.io -A檢視該資源。
然後在容器中新增annotation:

[root@k8s-master multus]# cat flannel-pod-128.yml 
---
apiVersion: v1
kind: Pod
metadata:
  name: flannelpod128
  namespace: net 
  annotations:
    v1.multus-cni.io/default-network: default/flannel-conf
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - k8s-master
  containers:
  - name: samplepod
    command: ["/bin/bash", "-c", "sleep 2000000000000"]
    image: dougbtv/centos-network
    ports:
    - containerPort: 80
[root@k8s-master multus]# 

使用以上yaml檔案就可以建立出一個使用flannel網路的容器。

建立一個雙網路卡容器,分別使用calico和flannel

預設網路是calico,如果再指定使用一個網路那麼就會在容器裡面建立兩個網路卡。例如,使用如下的yaml檔案,建立pod

[root@k8s-master multus]# cat example.yml 
apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: default/flannel-conf
spec:
  containers:
  - name: samplepod
    command: ["/bin/bash", "-c", "sleep 2000000000000"]
    image: dougbtv/centos-network
[root@k8s-master multus]# 

當容器執行起來之後可以看到,容器裡面有兩張網路卡,其中eth0是calico管理的,net1是flannel管理的:

[root@k8s-master multus]# kubectl get pods  -o wide -A|grep sample
default       samplepod                                  1/1     Running   0          14s     10.200.235.196   k8s-master   <none>           <none>
[root@k8s-master multus]# kubectl exec -ti -n default       samplepod  ip a
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP 
    link/ether 1a:c9:1e:a8:67:b6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.200.235.196/32 brd 10.200.235.196 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::18c9:1eff:fea8:67b6/64 scope link 
       valid_lft forever preferred_lft forever
6: net1@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP 
    link/ether 66:b7:a4:91:ec:50 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.244.0.4/24 brd 10.244.0.255 scope global net1
       valid_lft forever preferred_lft forever
    inet6 fe80::64b7:a4ff:fe91:ec50/64 scope link 
       valid_lft forever preferred_lft forever
[root@k8s-master multus]# 

網路連通性

這裡使用了calico和flannel兩種網路外掛,資料通路不一樣,但是跨節點都是相互通的,如下所示:

[root@k8s-master multus]# kubectl get pods  -o wide -A|grep pod
net           calicopod128                               1/1     Running   0          6s      10.200.235.195   k8s-master   <none>           <none>
net           calicopod129                               1/1     Running   0          9s      10.200.113.138   k8s-node     <none>           <none>
net           flannelpod128                              1/1     Running   0          4m33s   10.244.0.2       k8s-master   <none>           <none>
net           flannelpod129                              1/1     Running   0          4m14s   10.244.1.2       k8s-node     <none>           <none>
[root@k8s-master multus]# 

這四個Pod兩兩之間是可以ping通的,但是在有些環境中資料包跨節點後到達flannel繫結的網路卡或者calico繫結的網路卡就不再轉發給容器的網路卡了,也是出現過的。按照本地路由是應該轉發給容器的網路卡的,但就是不轉發。你是否也遇到過這種情況,歡迎大家在留言區交流。為了謹慎起見,不建議calico和flannel網路之間有通訊,而使之起到網路分流的作用。

相關文章