一、flannel
1.1、flannel 插件的基本介绍
Flannel由CoreOS推出,解决跨主机通信的一种方式;支持3种实现:UDP、VXLAN、host-gw
udp模式:使用设备flannel.0进行封包解包,不是内核原生支持,上下文切换较大,性能非常差;
vxlan模式:使用flannel.1进行封包解包,内核原生支持,性能较强;
host-gw模式:无需flannel.1这样的中间设备,直接宿主机当作子网的下一跳地址,性能最强,host-gw的性能损失大约在10%左右,而其他所有基于VXLAN“隧道”机制的网络方案,性能损失在20%~30%左右
1.2、flannel的跨主机通信模式:VXLAN
1.2.1 、什么是VXLAN
VXLAN,即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network)
1.2.2 、VXLAN的设计过程
在现有的三层网络之上,“覆盖”一层虚拟的、由内核VXLAN模块负责维护的二层网络,使得连接在这个VXLAN二nfcu网络上的“主机”(虚拟机或容器都可以),可以像在同一个局域网(LAN)里那样自由通信。
为了能够在nfcu网络上打通“隧道”,VXLAN会在宿主机上设置一个特殊的网络设备作为“隧道”的两端,叫VTEP:VXLAN Tunnel End Point(虚拟隧道端点)
1.2.3、VXLAN的工作原理
图例解释:
Container:即运行的容器--包含各自的IP;
Cni0:网桥设备,没创建一个POD都会创建一对veth pair。其中一端是POD中的eth0,另一端是Cni0网桥中的端口(即网卡)
Flanel.1:TUN设备(虚拟网卡),用来进行VXLAN报文的处理(封装和解封)。不同node之间的pod数居流都是从高overlay设备以隧道模式发送到对端的。
Flanneld:flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。同时Flanneld监听K8s集群数据库,为flannel1设备提供封装数据时必要的mac、ip等网络数据信息。
过程解释:
1、当要发送数据包时,首先通过veth pair发送到cni网桥,再路由到本机的flannel.1设备进行处理;
2、VTEP设备之间通过二层数据桢进行通信;源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址,封装成一个导去数据桢,发送给目的VTEP设备(获取 MAC地址需要通过三层IP地址查询,这是ARP表的功能);
3、对于得到的内部数据帧,并不能在宿主机的二层网络传输,Linux内核还需要把它进一步封装成为宿主机的一个普通的数据桢,好让它带着“内部数据桢”通过宿主机的eth0进行传输,Linux会在内部数据桢前面,加上一个VXLAN头,VXLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。
4、当数据伪装完毕则可以通过eth0进行转发,然后到目的主机进行相应的解析即可。
其中在Flannel中,VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因;一个flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。
在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库,这个flannel.1网桥对应的FDB信息,是由flanneld进程维护的。linux内核再在IP包前面加上二层数据桢头,把Node2的MAC地址填进去。这个MAC地址本身,是Node1的ARP表要学习的,需Flannel维护,这时候Linux封装的“外部数据桢”的格式如下
在这里插入图片描述
1.3 host-gw模式和directrouting的设置和测试
1.3.1 host-gw模式
host-gw是一种纯三层网络的方案,性能最高。
工作原理:就是将每个Flannel子网的下一跳,设置成了该子网对应的宿主机的IP地址,也就是说,宿主机(host)充当了这条容器通信路径的“网关”(Gateway),这正是host-gw的含义。所有的子网和主机的信息,都保存在Etcd中,flanneld只需要watch这些数据的变化 ,实时更新路由表就行了。
核心:IP包在封装成桢的时候,使用路由表的“下一跳”设置上的MAC地址,这样可以经过二层网络到达目的宿主机。
##host-gw模式
[root@server1 fannel]# cp ~/kube-flannel.yml . ##将flannel.yml pod清单复制到当前目录下
[root@server1 fannel]# vim kube-flannel.yml ##编辑kube-flannel.yml文件,将网络类型改为直接路由模式(host-gw)
[root@server1 fannel]# kubectl apply -f kube-flannel.yml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
[root@server1 fannel]# kubectl get pod -n kube-system ## 查看flannel网络插件应用成功
查看三台Node的IP,发现都存在gw:10.96.0.1/32
创建测试用例:
###创建pod:
[root@server1 network]# vim pod2.yml
1 Version: apps/v1
2 kind: Deployment
3 metadata:
4 name: deployment-example
5 spec:
6 replicas: 4
7 selector:
8 matchLabels:
9 app: myapp
10 template:
11 metadata:
12 labels:
13 app: myapp
14 spec:
15 containers:
16 - name: myapp
17 image: nginx
##创建服务:
1 nd: Service
2 apiVersion: v1
3 metadata:
4 name: myservice
5 spec:
6 ports:
7 - protocol: TCP
8 port: 80
9 targetPort: 80
10 selector:
11 app: myapp
12 type: NodePort
查看节点上的IP:10.224.1.0/24 10.224.2.0/24
通过外部访问:不卡顿,server2 server3 轮循访问
1.3.2 Flannel——vxlan+Directrouting模式
##删除之前的模式:
[root@server1 fannel]# kubectl delete -f kube-flannel.yml
##重新设置配置
[root@server1 fannel]# vim kube-flannel.yml
##应用新的配置
[root@server1 fannel]# kubectl apply -f kube-flannel.yml
##查看服务是否启动
[root@server1 fannel]# kubectl get pod -n kube-system
使用curl进行访问测试,和host-gw相同,这里不再赘述。
二、calico
默认当前的通信模式为calico,具体切换方式,请查看文章:
kubernetes---fannel和calico之间的切换
官方参考:
https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises
2.1 基本介绍
Fannal只解决通信,没有策略,k8s本事有相应的策略,但是需要相应的服务进行支持。
Calico 就是一种开源网络和网络安全解决方案,适用于容器,虚拟机和基于主机的本机工作负载。Calico 支持广泛的平台,包括 Kubernetes,docker,OpenStack 和裸机服务。Calico 后端支持多种网络模式。
三种模式:
BGP 模式:将节点做为虚拟路由器通过 BGP 路由协议来实现集群内容器之间的网络访问。
IPIP 模式:在原有 IP 报文中封装一个新的 IP 报文,新的 IP 报文中将源地址 IP 和目的地址 IP 都修改为对端宿主机 IP。
cross-subnet:Calico-ipip 模式和 calico-bgp 模式都有对应的局限性,对于一些主机跨子网而又无法使网络设备使用 BGP 的场景可以使用 cross-subnet 模式,实现同子网机器使用 calico-BGP 模式,跨子网机器使用 calico-ipip 模式。
网络架构:
Felix: 监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了限离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
BIRD: 一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准 BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个P在这里,路由的时候到这里来。
2.2 应用和配置
2.2.1 安装和配置
##安装和配置calico
##下载配置文件
curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O
##根据配置文件,下载相应的镜像
[root@server1 fannel]# docker pull docker.io/calico/cni:v3.22.2
[root@server1 fannel]# docker pull docker.io/calico/pod2daemon-flexvol:v3.22.2
[root@server1 fannel]# docker pull docker.io/calico/node:v3.22.2
[root@server1 fannel]# docker pull docker.io/calico/kube-controllers:v3.22.2
##编写配置文件的模式,设置IPIP为OFF
##应用配置文件
[root@server1 calico]# kubectl apply -f calico.yaml
##查看应用状态
[root@server1 calico]# kubectl get pod -n kube-system
[root@server1 calico]# kubectl get daemonset.apps -n kube-system
##查看运行的模式
[root@server1 calico]# kubectl describe ippools
2.2.2 基本的通信状态
##配置pod和svc,查看通信状态
[root@server1 network]# cat pod2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-example
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx
[root@server1 network]# cat server2.yml
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: myapp
type: NodePort
##查看路由环,观察通信模式
[root@server1 network]# ip route
2.2.3 打开隧道模式,分配固定的pod ip网段
[root@server1 calico]# vim calico.yaml
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Always"
- name: CALICO_IPV4POOL_CIDR
value: "192.168.0.0/16"
[root@server1 calico]# kubectl apply -f calico.yaml
2.3 通过Calico实现网络策略
calico的限制策略都是通过标签来进行匹配,设置相应的主机服务。
官方网址:https://projectcalico.docs.tigera.io/security/
2.3.1 限制访问指定服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-nginx
spec:
podSelector: ##通过标签选择含有指定label的pod进行通信
matchLabels:
app: nginx
2.3.2 允许指定pod访问
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress: ##允许通过
- from:
- podSelector: ##选择含有对应的标签的pod
matchLabels:
app: demo
2.3.3 禁止 namespace 中所有 Pod 之间的相互访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: default
spec:
podSelector: {} ##没有选择任何标签,则为拒绝所有POD
2.3.4 禁止其他 namespace 访问服务
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: deny-namespace
spec:
podSelector:
matchLabels:
ingress: ##没有选择其他的namespace,则为禁止其他的namespace
- from:
- podSelector: {}
2.3.5 只允许指定namespace访问服务
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-namespace
spec:
podSelector:
matchLabels:
app: myapp
ingress:
- from:
- namespaceSelector: ##指定有相应标签的namespace
matchLabels:
role: prod
2.3.6 允许外网访问服务
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-external
spec:
podSelector:
matchLabels:
app: web
ingress: ##指定特定端口
- ports:
- port: 80
from: [] ##来自于任何地方均可以