Kubernetes 网络插件
Kubernetes 自身并不提供网络解决方案,允许托管使用第三方的网络解决方案。
flannel
calico
canel
kube-router
......
各种 CNI 插件的解决方案:
虚拟网桥(bridge)
多路复用(MacVLAN)
直接使用物理网卡,基于物理网卡中的 MacVLAN 机制进行跨节点之间通信
硬件交换(SR-IOV)
单根 IO 虚拟化,虚拟出多个网卡
虚拟网桥能实现更多的控制能力,但是网络传输中的性能开销较大。
3.1 Flannel
Flannel 是一个可以用于 Kubernetes 的 overlay 网络提供者,是一种简单易用的方式来配置专为 Kubernetes 设计的第 3 层网络结构。
Flannel 在每台主机上运行一个名为 flanneld 的小型的单个二进制代理,并负责从一个更大的预配置地址空间中为每个主机分配子网租约。Flannel 使用 Kubernetes API 或 etcd 直接存储网络配置、分配的子网和任何辅助数据(例如主机的公共 IP)。数据包使用多种后端机制之一进行转发,包括 VXLAN 和各种云集成。
网络插件能够实现辅助设置 Pod and Pod 之间是否能够互相访问的网络策略,而 Flannel 专注于网络。对于网络策略,可以使用 Calico 等其他项目。
kubernetes 加载 CNI 插件:/etc/cni/net.d/10-flannel.conflist
# 10-flannel.conflist { "name": "cbr0", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, "type": "portmap", "capabilities": { "portMappings": true } ] }
Flannel 默认使用 VxLAN 的方式来作为后端网络传输机制。当然支持多种后端。
VxLAN
原生 VxLAN
Directrouting
节点在同一个三层网络之中使用 Host Gateway,不在同一个三层网络之中使用原生 VxLAN
Host Gateway
要求各节点必须工作在同一个三层网络之中
UDP
Flannel 可以部署为系统守护进程, 被 kubelet 所调用,有 kubelet 存在的节点都必须部署 flannel。kubelet 存在是为了创建 Pod,Pod 需要网络,网络是由 kubelet 调用 flannel 或其他网络插件来为 Pod 的网络做设计的 。
Flannel 可以部署为普通 Pod,也可以部署为系统守护进程(共享节点网络名称空间的 Pod)
kubeadm 部署的集群,默认 flannel 托管运行在 kubernetes 集群之上。
"查看 flannel" $ kubectl get daemonset -n kube-system | grep flannel $ kubectl get pod -n kube-system | grep flannel "查看 flannel 配置" $ kubectl get configmap -n kube-system | grep flannel $ kubectl get configmap kube-flannel-cfg -n kube-system -o json ...... Network: 10.244.0.0/16 # pod network segment SubnetLen: # 将Network切分子网供各节点使用时,使用多长的掩码进行切分,默认为24位 SubnetMin: # 10.244.10.0/24 SubnetMax: # 10.244.100.0/24 Backend: # backend type ......
3.1.1 Directrouting
在两个 Node 节点上分别部署 Pod,分别在两个终端登陆两个 Pod 中相互 Ping。在两个 Node 节点之上做 tcpdump 抓包分析:
$ tcpdump -i cni0 -nn icmp # 有数据: pod ip --- pod ip $ tcpdump -i flannel.1 -nn # 有数据: pod ip --- pod ip $ tcpdump -i ens32 -nn host 172.20.0.67 # 有数据: node ip --- node ip
结果分析:报文 --- cni0进来 --- flannel.1(封装 VxLAN 报文)出去 --- 借助 ens32 发出去。
配置 flannel 使用 Directrouting(VxLAN)做为后端网络传输机制:
# 更改配置文件 $ kubectl edit comfigmap kube-flannel-cfg -n kube-system ...... net-conf.json | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan", "Directrouting": true } } ...... # 查看规则 $ ip route show ...... 10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink # 看到的是:flannel(没生效) ...... # 卸载flannel,更改flannel的yaml部署文件,重新部署flannel!!! # 查看规则 $ ip route show ...... 10.244.1.0/24 via 172.20.0.70 dev ens32 # 看到的是:ens32 ...... # 抓包分析:直接使用物理网卡通信,相当于桥接模式 $ tcpdump -i ens32 -nn icmp
3.1.2 host-gw
host-gw 要求各 Node 节点必须在同一个网段。
# 更改flannel配置文件,部署 ...... net-conf.json | { "Network": "10.244.0.0/16", "Backend": { "Type": "host-gw" } } ......
3.2 Calico
官网:https://projectcalico.docs.tigera.io/about/about-calico
Github:https://github.com/projectcalico/calico
Calico 是一个开源网络和网络安全解决方案,适用于容器、虚拟机和基于本地主机的工作负载。Calico 支持广泛的平台,包括 Kubernetes、OpenShift、Mirantis Kubernetes Engine (MKE)、OpenStack 和裸机服务。
Calico 即支持地址分配,又支持网络策略。可以在实现地址转发的方式当中可以基于 BGP 协议实现二层转发。
3.2.1 NetworkPolicy
3.2.1.1 Ingress
拒绝所有:
# ingressDenyAll-devNamespace.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress namespace: dev spec: podSelector: {} # 选择namespace中所有pod # ingress: # - {} # 定义Ingress规则,{}代表所有,允许所有入栈流量 policyTypes: - Ingress # 没有定义Ingress规则表示不允许任何人访问
$ kubectl create ns dev $ kubectl apply -f ingressDenyAll-devNamespace.yaml $ kubectl get NetworkPolicy -n dev NAME POD-SELECTOR AGE deny-all-ingress <none> 47s
创建测试 Pod(dev namespace):
# pod-devNamespace.yaml apiVersion: v1 kind: Pod metadata: name: pod-dev-ns namespace: dev spec: containers: - name: myapp image: zhangyyhub/myapp:v1.0
# create pod $ kubectl apply -f pod-devNamespace.yaml pod/pod-dev-ns created $ kubectl get pods -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-dev-ns 1/1 Running 0 59s 10.244.235.137 worker1 <none> <none> # can not access $ curl 10.244.235.137 # create pod $ kubectl create ns prod namespace/prod created $ cat pod-prodNamespace.yaml apiVersion: v1 kind: Pod metadata: name: pod-prod-ns namespace: prod spec: containers: - name: myapp image: zhangyyhub/myapp:v1.0 $ kubectl apply -f pod-prodNamespace.yaml pod/pod-dev-ns created $ kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-prod-ns 1/1 Running 0 11s 10.244.235.254 k8s-master <none> <none> "access is successful" $ curl 10.244.235.254 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
放行 Ingress 流量:放行 dev namespace 中入栈流量,允许访问 label app=myapp pod。
"add label" $ kubectl label pods pod-dev-ns app=myapp -n dev pod/pod-dev-ns labeled $ kubectl get pods pod-dev-ns --show-labels -n dev NAME READY STATUS RESTARTS AGE LABELS pod-dev-ns 1/1 Running 0 39m app=myapp
# ingressAllowMyapp-devNamespace.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-myapp-ingress namespace: dev spec: podSelector: matchLabels: app: myapp policyTypes: - Ingress ingress: - from: - ipBlock: cidr: 0.0.0.0/0 # 放行 except: - 172.16.107.104/32 # 排除 ports: - protocol: TCP port: 80 # 允许访问80端口
$ kubectl apply -f ingressAllowMyapp-devNamespace.yaml networkpolicy.networking.k8s.io/allow-myapp-ingress created $ kubectl get NetworkPolicy -n dev NAME POD-SELECTOR AGE allow-myapp-ingress app=myapp 50s deny-all-ingress <none> 94m $ curl 10.244.235.137 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
3.2.1.2 Egress
拒绝所有:
# egressDenyAll-prodNamespace.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-egress namespace: prod spec: podSelector: {} # 选择namespace中所有pod # egress: # - {} # 定义egress规则,{}代表所有,允许所有流量出栈 policyTypes: - Egress # 没有定义Egress规则表示不允许任何流量出栈
$ kubectl apply -f egressDenyAll-prodNamespace.yaml networkpolicy.networking.k8s.io/deny-all-egress created $ kubectl get NetworkPolicy -n prod NAME POD-SELECTOR AGE deny-all-egress <none> 49s $ kubectl get pods -n prod NAME READY STATUS RESTARTS AGE pod-prod-ns 1/1 Running 0 109m "拒绝所有出栈流量" $ kubectl exec -it pod-prod-ns -n prod -- /bin/sh / # ping www.baidu.com ping: bad address 'www.baidu.com'