k8sService代理模式之IPVS模式无头服务发布service五种类型Fannel原理及Flannel vxlan类型

Posted dezasseis

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8sService代理模式之IPVS模式无头服务发布service五种类型Fannel原理及Flannel vxlan类型相关的知识,希望对你有一定的参考价值。

一、k8s网络通信

  • k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等。 CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist

插件使用的解决方案如下:

  • 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
  • 多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
  • 硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。

容器间通信:同一个pod内的多个容器间的通信,通过lo回环网络接口即可实现;

pod之间的通信:
同一节点的pod之间通过cni网桥转发数据包。
不同节点的pod之间的通信需要网络插件支持。

pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换。

pod和外网通信: iptables的MASQUERADE。

Service与集群外部客户端的通信:ingress、nodeport、loadbalancer

二、service与service代理

service官方文档

  • Service:Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 ,通常称为微服务。
  • 在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。 kube-proxy 负责为 Service
    实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。

01_ userspace 代理模式

  • 这种模式,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods 中的某个上面(如 Endpoints 所报告的一样)。
    使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。
  • 最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP) 和 Port
    的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。
  • 默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。

02_iptables 代理模式

  • 这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置iptables 规则,这个规则会选择一个后端组合。
  • 默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。
  • 使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。
  • 如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。
  • 可以使用 Pod 就绪探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy
    仅看到测试正常的后端。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。

03 _IPVS模式

  • 在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则,
    并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS将流量定向到后端Pod之一。
  • IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS模式还支持更高的网络流量吞吐量。
  • IPVS 提供了更多选项来平衡后端 Pod 的流量。
  • 要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。
  • 当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则kube-proxy 将退回到以 iptables 代理模式运行。
  • Service 是由 kube-proxy 组件,加上 iptables 来共同实现的.
  • kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables
    规则,如果宿主机有大量的Pod,不断刷新iptables规则,会消耗大量的CPU资源。
  • IPVS模式的service,可以使K8s集群支持更多量级的Pod。

开启kube-proxy的ipvs模式:

  • 所有节点安装:
    yum install -y ipvsadm
  • master端修改为ipvs模式
    kubectl edit cm kube-proxy -n kube-system
mode: "ipvs"
  • master端更新kube-proxy
    kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
    在这里插入图片描述
  • 创建ipvs模式的service
    vim demo.yml
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
 - protocol: TCP
    port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

kubectl apply -f demo.yml
在这里插入图片描述

  • 轮训调度
    在这里插入图片描述在这里插入图片描述

  • pvs模式会创建一个虚拟网卡kube-ipvs0,并分配service IP
    在这里插入图片描述

三、无头服务(Headless Services)

  • Headless Service不需要分配一个VIP,而是直接以DNS记录的方式解析出被代理Pod的IP地址。
域名格式:$(servicename).$(namespace).svc.cluster.local

vim demo.yml

---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

kubectl apply -f demo.yml
在这里插入图片描述
在这里插入图片描述

  • kube-DNS

在这里插入图片描述
dig myservice.default.svc.cluster.local. @10.244.0.10
在这里插入图片描述

  • Pod滚动更新后,依然可以解析
    vim demo.yml
 -   replicas: 6

dig myservice.default.svc.cluster.local. @10.244.0.10
在这里插入图片描述

四、发布服务

  • Kubernetes ServiceTypes 允许指定你所需要的 Service 类型,默认是 ClusterIP。

01_ ClusterIP (默认)

  • 通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType。

02_NodePort

  • 通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。
    通过请求 <节点 IP>:<节点端口>,你可以从集群外部访问一个 NodePort 服务。
    vim demo.yml
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
 - protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

在这里插入图片描述在这里插入图片描述

  • 外部访问node IP+端口:负载均衡
    在这里插入图片描述

03_LoadBalancer

  • 使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
  • 本例没有云主机,所以状态为 pending
    vim demo.yml
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  #type: NodePort
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

在这里插入图片描述

04_引入外部IP(externalIPs)

vim demo.yml

---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  #type: NodePort
  #type: LoadBalancer
  externalIPs:
  - 172.25.2.100
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

在这里插入图片描述

05_ExternalName(内部访问外部)

  • vim exsvc.yml
apiVersion: v1
kind: Service
metadata:
  name: exsvc
spec:
  type:  ExternalName
  externalName: www.westos.org

在这里插入图片描述

  • 查询DNS结果

在这里插入图片描述
在这里插入图片描述

五、k8s 网络模型

k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等。
CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist

插件使用的解决方案如下:

  • 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
  • 多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
  • 硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。

flannel支持多种后端:

  • Vxlan
    vxlan:报文封装,默认
    Directrouting:直接路由,跨网段使用vxlan,同网段使用host-gw模式。

  • host-gw
    主机网关,性能好,但只能在二层网络中,不支持跨网络,如果有成千上万的Pod,容易产生广播风暴,不推荐

  • UDP
    性能差,不推荐

01_Flannel vxlan模式模型结构

  • VXLAN,即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network)。
  • VTEP:VXLAN Tunnel End Point(虚拟隧道端点),在Flannel中 VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因。
  • Cni0: 网桥设备,每创建一个pod都会创建一对 veth pair(虚拟网络对)。其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡)。
  • Flannel.1: TUN设备(隧道设备)(虚拟网卡),用来进行 vxlan报文的处理(封包和解包)。不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端。
  • Flanneld:flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。同时Flanneld监听K8s集群数据库,为flannel.1设备提供封装数据时必要的mac、ip等网络数据信息。

02_Fannel vxlan模式工作原理

Flannel vxlan模式跨主机通信原理

在这里插入图片描述

  • 当容器发送IP包,通过veth pair 发往cni网桥,再路由到本机的flannel.1设备进行处理。

  • VTEP设备之间通过二层数据帧进行通信,源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址,封装成一个内部数据帧,发送给目的VTEP设备。
    (每个节点缓存所有节点的的flannel的MAC地址,通过ip n 可以查看)
    在这里插入图片描述在这里插入图片描述

  • 内部数据桢,并不能在宿主机的二层网络传输,Linux内核还需要把它进一步封装成为宿主机的一个普通的数据帧,承载着内部数据帧通过宿主机的eth0进行传输。

  • Linux会在内部数据帧前面,加上一个VXLAN头,VXLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。

  • flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库,这个flannel.1网桥对应的FDB信息,是由flanneld进程维护的。
    在这里插入图片描述在这里插入图片描述

  • linux内核在IP包前面再加上二层数据帧头,把目标节点的MAC地址填进去,MAC地址从宿主机的ARP表获取。
    在这里插入图片描述在这里插入图片描述

  • 此时flannel.1设备就可以把这个数据帧从eth0发出去,再经过宿主机网络来到目标节点的eth0设备。目标主机内核网络栈会发现这个数据帧有VXLAN Header,并且VNI为1,Linux内核会对它进行拆包,拿到内部数据帧,根据VNI的值,交给本机flannel.1设备处理,flannel.1拆包,根据路由表发往cni网桥,最后到达目标容器。

测试

  • server3的pod ping server4的pod(不同子网)

在这里插入图片描述

  • 成功抓包
    tcpdump -i eth0 -nn host 172.25.2.3
    在这里插入图片描述

03_Fannel host-gw模式

主机网关,性能好,但只能在二层网络中,不支持跨网络,如果有成千上万的Pod,容易产生广播风暴,不推荐

  • kubectl -n kube-system edit cm kube-flannel-cfg 修改模式
"Type": "host-gw"

在这里插入图片描述

  • kubectl get pod -n kube-system | grep flannel | awk '{system("kubectl delete pod "$1" -n kube-system")}' 更新
    在这里插入图片描述
    在这里插入图片描述

04_Fannel vxlan Directrouting模式

直接路由,跨网段使用vxlan,同网段使用host-gw模式。

  • kubectl -n kube-system edit cm kube-flannel-cfg 修改模式
    在这里插入图片描述
  • kubectl get pod -n kube-system | grep flannel | awk '{system("kubectl delete pod "$1" -n kube-system")}' 更新
    在这里插入图片描述
    在这里插入图片描述

以上是关于k8sService代理模式之IPVS模式无头服务发布service五种类型Fannel原理及Flannel vxlan类型的主要内容,如果未能解决你的问题,请参考以下文章

k8s学习-Service(概念模板创建外部代理删除等)

kube-proxy IPVS 模式的工作原理

Kubernetes(k8s)之Service(服务)

如何查看 kube-proxy 当前处于啥代理模式

云原生之kubernetes实战kubernetes集群的Service资源对象

k8s 实践经验service 详解