多個網絡層面的需求
一開始為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>
這里有兩點需要注意:
- flannel會自動讀取k8s-api-server的cluster-cidr信息,也就是/etc/kubernetes/manifests/kube-controller-manager.yaml 文件中的--cluster-cidr參數,要注意這個地址的有效性,不能和其他網絡的有重疊。例如不能和calico網絡重疊也不能和--service-cluster-ip-range重疊。
同時,要注意該值要和kube-flannel-cfg configmap中的Network字段一致否則flannel網絡不通,當該字段和--cluster-cidr參數沖突時flannel會使用--cluster-cidr參數來分配flannel容器地址。 - 如果想要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,注意這個annotation中定義的是default-network,就是制定默認網絡插件是flannel,因此就只有單網卡並且該網卡使用flannel插件。不同於下面雙網卡中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網絡之間有通信,而使之起到網絡分流的作用。