1 CNI 网络组件
1.1 K8S的三种接口
CRI 容器运行时接口 docker containerd podman cri-o
CNI 容器网络接口 flannel calico cilium
CSI 容器存储接口 nfs ceph gfs oss s3 minio
1.2 K8S的三种网络
节点网络 nodeIP 物理网卡的IP实现节点间的通信
Pod网络 podIP Pod与Pod之间可通过Pod的IP相互通信
Service网络 clusterIP 在K8S集群内可通过service资源的clusterIP实现对Pod集群的网络代理转发
K8S 中 Pod 网络通信:
●Pod 内容器与容器之间的通信
在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享同一个网络命令空间,相当于它们在同一台机器上一样,可以用 localhost 地址访问彼此的端口。
●同一个 Node 内 Pod 之间的通信
每个 Pod 都有一个真实的全局 IP 地址,同一个 Node 内的不同 Pod 之间可以直接采用对方 Pod 的 IP 地址进行通信,Pod1 与 Pod2 都是通过 Veth 连接到同一个 docker0 网桥,网段相同,所以它们之间可以直接通信。
●不同 Node 上 Pod 之间的通信
Pod 地址与 docker0 在同一网段,docker0 网段与宿主机网卡是两个不同的网段,且不同 Node 之间的通信只能通过宿主机的物理网卡进行。 要想实现不同 Node 上 Pod 之间的通信,就必须想办法通过主机的物理网卡 IP 地址进行寻址和通信。因此要满足两个条件:Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让不同 Node 上 Pod 之间直接通过内网 IP 地址通信。
1.3 Flannel
Flannel 的功能是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。 Flannel 是 Overlay 网络的一种,也是将 TCP 源数据包封装在另一种网络包里面进行路由转发和通信,目前支持 udp、vxlan、 host-GW 3种数据转发方式。
flannel的三种模式
模式类型 | 说明 |
---|---|
UDP | 出现最早的模式,但是性能最差,基于flanneld应用程序实现数据包的封装/解封装 |
VXLAN | flannel的默认模式,也是推荐使用的模式,性能比UDP模式更好,基于内核实现数据帧的封装/解封装,而且配置简单使用方便 |
HOST-GW | 性能最好的模式,但是配置负载,且不能跨网段 |
flannel的UDP模式工作原理
1)原始数据包从源主机的Pod容器发出到cni0网桥接口,再由cni0转发到flannel0虚拟接口 2)flanneld服务进程会监听flannel0接口接收到的数据,flanneld进程会将原始数据包封装到UDP报文里 3)flanneld进程会根据在etcd中维护的路由表查到目标Pod所在的nodeIP,并在UDP报文外封装nodeIP头部、MAC头部,再通过物理网卡发送到目标node节点 4)UDP报文通过8285端口送达到目标node节点的flanneld进程进行解封装,再根据本地路由规则通过flannel0接口发送到cni0网桥,再由cni0发送到目标Pod容器
ETCD 之 Flannel 提供说明
存储管理Flannel可分配的IP地址段资源 监控 ETCD 中每个 Pod 的实际地址,并在内存中建立维护 Pod 节点路由表
VXLAN
将源数据包封装到UDP中,并使用基础网络的IP/MAC作为外层报文头进行封装,然后在以太网上传输,到达目的地后由隧道端点解封装并将数据发送给目标地址。
flannel的VXLAN模式工作原理
1)原始数据帧从源主机的Pod容器发出到cni0网桥接口,再由cni0转发到flannel.1虚拟接口 2)flannel.1接口接收到数据帧后添加VXLAN头部,并在内核将原始数据帧封装到UDP报文里 3)根据在etcd中维护的路由表查到目标Pod所在的nodeIP,并在UDP报文外封装nodeIP头部、MAC头部,再通过物理网卡发送到目标node节点 4)UDP报文通过8472端口送达到目标node节点的flannel.1接口并在内核进行解封装,再根据本地路由规则发送到cni0网桥,再由cni0发送到目标Pod容器
VLAN 和 VXLAN 的区别
1)作用不同:VLAN主要用作于在交换机上逻辑划分广播域,还可以配合STP生成树协议阻塞路径接口,避免产生环路和广播风暴,VXLAN可以将数据帧封装成UDP报文,再通过网络层传输给其它网络,从而实现虚拟大二层网络的通信 2)VXLAN支持更多的二层网络:VXLAN最多可支持 2^24 个;VLAN最多支持 2^12 个(4096-2) 3)VXLAN可以防止物理交换机MAC表耗尽:VLAN需要在交换机的MAC表中记录MAC物理地址;VXLAN采用隧道机制,MAC物理地址不需记录在交换机
Overlay Network
叠加网络,在二层或者三层基础网络上叠加的一种虚拟网络技术模式,该网络中的主机通过虚拟链路隧道连接起来(类似于VPN)。
1.4 flannel部署
在 node01、node02 节点上操作
上传 cni-plugins-linux-amd64-v0.8.6.tgz 和 flannel.tar 到 /opt 目录中 cd /opt/ mkdir /opt/cni/bin -p docker load -i flannel-cni-plugin.tar #导入镜像 docker load -i flannel.tar #导入镜像 tar zxvf cni-plugins-linux-amd64-v1.3.0.tgz -C /opt/cni/bin #解压cni的压缩包到cni插件的工作目录
在 master01 节点上操作
cd /opt/k8s kubectl apply -f kube-flannel.yml #启动flannel插件 kubectl get pods -n kube-flannel #进入kube-flannel网络命名空间 NAME READY STATUS RESTARTS AGE kube-flannel-ds-hjtc7 1/1 Running 0 7s kubectl get nodes #查看node状态 NAME STATUS ROLES AGE VERSION 192.168.111.11 Ready <none> 81m v1.20.11
重启服务器查看node01、node02是否分配网卡
systemctl restart network ip -d addr show flannel.1 8: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN link/ether 22:37:61:bb:a1:64 brd ff:ff:ff:ff:ff:ff promiscuity 0 vxlan id 1 local 192.168.111.22 dev ens33 srcport 0 0 dstport 8472 nolearning ageing 300 inet 10.244.0.0/32 scope global flannel.1 valid_lft forever preferred_lft forever node01和node02都分配了一个flannel.1的虚拟网卡,网段是10.244.0.0/16分配的目标端口是8472(对应的flannel的vxlan模式)
网络插件的目的是为了解决跨node节点的pod进行通信,那么进行验证
在master01节点创建pod资源
kubectl create deployment test-v1 --image=soscscs/myapp:v1 --replicas=2 #创建pod deployment.apps/test-v1 created kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-v1-56f56b4db5-82hf6 1/1 Running 0 22s 10.244.0.2 node02 <none> <none> test-v1-56f56b4db5-zrcgv 1/1 Running 0 22s 10.244.1.2 node01 <none> <non
在node节点查看容器情况
docker ps -a
进入容器中,查看是否可以完成跨主机的pod通信
docker exec -it 9c16ee2809b1 sh
注意:有几个文件中的网段设置需要一致
kube-flannel.yml中的网段设置
与controller manager以及kube-proxy脚本中设置的网段需要保持一致
kube-flannel.yml net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } }
controller manager脚本 #!/bin/bash ##创建 kube-controller-manager 启动参数配置文件 MASTER_ADDRESS=$1 cat >/opt/kubernetes/cfg/kube-controller-manager <<EOF KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\ --v=2 \\ --log-dir=/opt/kubernetes/logs \\ --leader-elect=true \\ --kubeconfig=/opt/kubernetes/cfg/kube-controller-manager.kubeconfig \\ --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 \\ --cluster-signing-duration=87600h0m0s" EOF
kube-proxy脚本
proxy.sh #!/bin/bash NODE_ADDRESS=$1 #创建 kube-proxy 启动参数配置文件 cat >/opt/kubernetes/cfg/kube-proxy <<EOF KUBE_PROXY_OPTS="--logtostderr=false \\ --v=2 \\ --log-dir=/opt/kubernetes/logs \\ --hostname-override=${NODE_ADDRESS} \\ --cluster-cidr=10.244.0.0/16 \\ --proxy-mode=ipvs \\ --kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
2.2 Calico的工作模式
IPIP模式
可以实现跨子网传输,但是传输过程中需要额外的封包和解包过程,对性能有一定的影响。
calico的IPIP模式工作原理
1)原始数据包从源主机的Pod容器发出,通过 veth pair 设备送达到tunl0接口,再被内核的IPIP驱动封装到node节点网络的IP报文里 2)根据Felix维护的路由规则通过物理网卡发送到目标node节点 3)IP数据包到达目标node节点的tunl0接口后再通过内核的IPIP驱动解封装得到原始数据包,再根据本地路由规则通过 veth pair 设备送达到目标Pod容器
BGP模式
会把每个node节点看作成路由器,通过Felix、BIRD组件来维护和分发路由规则,可实现直接通过BGP路由协议实现路由转发,传输过程中不需要额外封包和解包过程,因此性能较好,但是只能在同一个网段里使用,无法跨子网传输。
calico的BGP模式工作原理(本质就是通过路由规则来实现Pod之间的通信)
每个Pod容器都有一个 veth pair 设备,一端接入容器,另一个接入宿主机网络空间,并设置一条路由规则。 这些路由规则都是 Felix 维护配置的,由 BIRD 组件基于 BGP 动态路由协议分发路由信息给其它节点。 1)原始数据包从源主机的Pod容器发出,通过 veth pair 设备送达到宿主机网络空间 2)根据Felix维护的路由规则通过物理网卡发送到目标node节点 3)目标node节点接收到数据包后,会根据本地路由规则通过 veth pair 设备送达到目标Pod容器
混合模式(CrossSubnet)
2.3 flannel 与 calico 的区别
●flannel方案 需要在每个节点上把发向容器的数据包进行封装后,再用隧道将封装后的数据包发送到运行着目标Pod的node节点上。目标node节点再负责去掉封装,将去除封装的数据包发送到目标Pod上。数据通信性能则大受影响。
●calico方案 Calico不使用隧道或NAT来实现转发,而是把Host当作Internet中的路由器,使用BGP同步路由,并使用iptables来做安全访问策略,完成跨Host转发来。
flannel
UDP VXLAN HOST-GW 默认网段:10.244.0.0/16 通常会采用VXLAN模式,用的是叠加网络、IP隧道方式传输数据,对性能有一定的影响。 Flannel产品成熟,依赖性较少,易于安装,功能简单,配置方便,利于管理。但是不具备复杂的网络策略配置能力。
calico
IPIP BGP 混合模式(CrossSubnet) 默认网段:192.168.0.0/16 使用IPIP模式可以实现跨子网传输,但是传输过程中需要额外的封包和解包过程,对性能有一定的影响。 使用BGP模式会把每个node节点看作成路由器,通过Felix、BIRD组件来维护和分发路由规则,可实现直接通过BGP路由协议实现路由转发,传输过程中不需要额外封包和解包过程,因此性能较好,但是只能在同一个网段里使用,无法跨子网传输。calico不使用cni0网桥,而使通过路由规则把数据包直接发送到目标主机,所以性能较高;而且还具有更丰富的网络策略配置管理能力,功能更全面,但是维护起来较为复杂。
所以对于较小规模且网络要求简单的K8S集群,可以采用flannel作为cni网络插件。对于K8S集群规模较大且要求更多的网络策略配置时,可以考虑采用性能更好功能更全面的calico或cilium。
2.4 Calico实际部署
//在 master01 节点上操作 #上传 calico.yaml 文件到 /opt/k8s 目录中,部署 CNI 网络 cd /opt/k8s vim calico.yaml #修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kube-controller-manager配置文件指定的cluster-cidr网段一样 - name: CALICO_IPV4POOL_CIDR value: "192.168.0.0/16" kubectl apply -f calico.yaml kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-659bd7879c-4h8vk 1/1 Running 0 58s calico-node-nsm6b 1/1 Running 0 58s calico-node-tdt8v 1/1 Running 0 58s #等 Calico Pod 都 Running,节点也会准备就绪 kubectl get nodes ---------- node02 节点部署 ---------- //在 node01 节点上操作 cd /opt/ scp kubelet.sh proxy.sh root@192.168.20.17:/opt/ scp -r /opt/cni root@192.168.20.17:/opt/ //在 node02 节点上操作 #启动kubelet服务 cd /opt/ chmod +x kubelet.sh ./kubelet.sh 192.168.20.17 //在 master01 节点上操作 kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0 10s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFE 85m kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Approved,Issued #通过 CSR 请求 kubectl certificate approve node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0 kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION node-csr-BbqEh6LvhD4R6YdDUeEPthkb6T_CJDcpVsmdvnh81y0 23s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Approved,Issued node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFE 85m kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Approved,Issued #加载 ipvs 模块 for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done #使用proxy.sh脚本启动proxy服务 cd /opt/ chmod +x proxy.sh ./proxy.sh 192.168.20.17 #查看群集中的节点状态 kubectl get nodes
3 CoreDNS
CoreDNS 是 K8S 默认的集群内部 DNS 功能实现,为 K8S 集群内的 Pod 提供 DNS 解析服务
-
根据 service 的资源名称 解析出对应的 clusterIP
-
根据 statefulset 控制器创建的Pod资源名称 解析出对应的 podIP
3.1 在所有 node 节点上操作
上传 coredns.tar 到 /opt 目录中 cd /opt docker load -i coredns.tar
3.2 在master节点上部署coredns
上传 coredns.yaml 文件到 /opt/k8s 目录中,部署 CoreDNS cd /opt/k8s kubectl apply -f coredns.yaml kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-5ffbfd976d-j6shb 1/1 Running 0 32s
验证可以通过service的名称进行通信
[root@master01 k8s#kubectl get pods --show-labels ##查看当前的pod资源 并展示其label标签 NAME READY STATUS RESTARTS AGE LABELS test-v1-56f56b4db5-ksplj 1/1 Running 0 25m app=test-v1,pod-template-hash=56f56b4db5 test-v1-56f56b4db5-z8p2p 1/1 Running 0 25m app=test-v1,pod-template-hash=56f56b4db5 ##查看当前的service资源有哪些 [root@master01 k8s#kubectl get service
[root@master01 k8s#kubectl expose deployment test-v1 --port=80 --target-port=80 ##创建service资源 service/test-v1 exposed