searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

K8s Service场景和原理

2023-09-01 01:21:49
53
0

背景&问题

当K8s的无状态应用Deployment有多个Pod的时候,我们访问这个应用,面临以下两个问题:

  • 需要负载均衡能力,转发到后端Pod
  • 负载均衡器需动态更新后端Pod(因为Pod重启后,IP会变化的问题)

解决方案

kubernetes提供了Service资源,作用如下:

  • 主要用于定义服务类型,服务如何找到后端Pod,服务端口和Pod端口映射关系

Service支持的访问需求:

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,client只能在集群内,通过该IP负载到后端的Pod
  • 集群外访问:
    • 通过Node节点暴露:
      • 服务类型:NodePort
      • 含义:会在Node节点上创建一个端口,通过NodeIP:NodePort负载到后端Pod
    • 通过集群外LoadBalance(Node节点外层再顶一个LoadBalance)
      • 服务类型:LoadBalance
      • 含义:请求先到ELB -> NodeIP:NodePort -> PodIP:PodPort(有很多种实现方式,这是其中一种)

常见问题

Service如何找到Pod?

使用selector通过标签,找到同标签的Pod(注意,service和deployment没什么关系)

apiVersion: v1

kind: Pod

metadata:

name: nginx

labels:

app.kubernetes.io/name: proxy

spec:

containers:

- name: nginx

image: nginx:stable

ports:

- containerPort: 80

name: http-web-svc

---

apiVersion: v1

kind: Service

metadata:

name: nginx-service

spec:

selector:

app.kubernetes.io/name: proxy

ports:

- name: name-of-service-port

protocol: TCP

port: 80

targetPort: http-web-svc

例子:

  • 通过标签找Pod
    • service找标签:app.kubernetes.io/name: proxy
    • Pod定义标签:app.kubernetes.io/name: proxy
  • 指定端口转发
    • service定义入口端口:port: 80,并转向pod的端口名,targetPort: http-web-svc
    • port定义端口名和端口号: - containerPort: 80 name: http-web-svc

Service类型有哪些?

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,client只能在集群内,通过该IP负载到后端的Pod
  • 集群外访问:
    • 通过Node节点暴露:
      • 服务类型:NodePort
      • 含义:会在Node节点上创建一个端口,通过NodeIP:NodePort负载到后端Pod
    • 通过集群外LoadBalance(Node节点外层再顶一个LoadBalance)
      • 服务类型:LoadBalance
      • 含义:请求先到ELB -> NodeIP:NodePort -> PodIP:PodPort(有很多种实现方式,这是其中一种)

Endpoint是什么?

可以简单理解为已经ready的pod,具备被访问条件的pod

当pod的readiness检测失败,pod不会加入到某个服务的Endpoints里面

如上图:10.1.3.8还没ready,就没有被加入my-service的Endpoints里

Service和Pod都会被分配域名吗?

Service 和 Pod 都会被分配对应的 DNS A 记录(从域名解析 IP 的记录)。

  • service
    • 对于 ClusterIP 模式的 Service 来说,它的 A 记录的格式是:..svc.cluster.local。
    • 当你访问这条 A 记录的时候,它解析到的就是该 Service 的cluster的 VIP 地址。
  • pod
    • 对于 ClusterIP 模式的 Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:..pod.cluster.local。
    • 这条记录指向 Pod 的 IP 地址

ClusterIP类型Service如何定义?

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,通过该IP会负载到后端的Pod
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

ClusterIP类型Service实现原理?

k8s的每个Node节点上都运行着一个kube-proxy服务进程。

  • 控制面:
    • 当创建Service的时候,会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则(有3种工作模式)
  • 数据面:
    • client访问服务IP(ClusterIp),会被Iptables拦截,转给ipvs做负载均衡转发

ClusterIp的实现原理?

  1. 是什么?
    1. 当创建一个带有ClusterIP类型的Service时,Kubernetes会为该Service分配一个唯一的ClusterIP地址
    2. 这个ClusterIp其实是一个VIP,只做负载用
    3. 这个IP地址是在集群的内部网络中使用的,并且只能由同一集群内的其他Pod访问
  1. 如何规划?
    1. Service地址段的管理由集群的网络插件负责。不同的网络插件可能有不同的管理方式。
    2. Kubernetes在集群创建时会预先定义一个内部IP地址段,这个IP地址段是专门用于集群内部通信的
    3. 参考云厂商的规划,是不能和Pod的CIDR地址段重叠
      • Flannel网络模式Service地址段。Service类型为ClusterIP(Type=ClusterIP)时,每个Service有自己的地址。配置网段时,请注意:
        • Service地址只在Kubernetes集群内使用,不能在集群外使用。
        • Service地址段不能和虚拟交换机地址段重叠。
        • Service地址段不能和Pod网络CIDR地址段重叠
  1. 如何分配某个IP?
    1. Kubernetes会自动为该Service分配一个ClusterIP地址。
    2. 参考Kubernetes 1.24: 避免为 Services 分配 IP 地址时发生冲突

kube-proxy3种工作模式原理?

1. userspace模式(淘汰)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy创建一个clusterIP
      • kube-proxy配置Iptables,将访问clusterIp请求转给kube-proxy
      • kube-proxy配置自身做为proxy,为每个Service创建一个监听端口,配置LB算法将请求转发到Pod上。
    • 数据面:
      • client发向Cluster IP的请求
      • 被iptables规则重定向到kube-proxy监听的端口上,
      • kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。
  • 缺点:
    • kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,性能较差

2. iptables模式(淘汰)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy创建一个clusterIP
        • 自动从Service地址段分配一个ip:10.0.1.175
      • kube-proxy为service后端的每个Pod创建对应的iptables规则
        • -A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
          • 表示:凡是目的地址是 10.0.1.175、目的端口是 80 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-NWV5X2332I4OT4T3 的 iptables 链进行处理
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
          • 表示:这三条链指向的最终目的地,其实就是这个 Service 代理的三个 Pod。所以这一组规则,就是 Service 实现负载均衡的位置。
          • 需要注意的是,iptables 规则的匹配是从上到下逐条进行的,所以为了保证上述三条规则每条被选中的概率都相同,我们应该将它们的 probability 字段的值分别设置为 1/3(0.333…)、1/2 和 1。
        • -A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
        • -A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
        • -A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
    • 数据面:
      • client发向Cluster IP的请求
      • iptables规则直接重定向到一个Pod IP
  • 优点:
    • 该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则,较userspace模式效率更高
  • 缺点
    • 当你的宿主机上有大量 Pod 的时候,成百上千条 iptables 规则不断地被刷新,会大量占用该宿主机的 CPU 资源,甚至会让宿主机“卡”在这个过程中。

3. ipvs模式(推荐)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy监控Pod的变化并创建相应的ipvs规则
      • kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址
        • # ip addr
        • ...
        • 73:kube-ipvs0:<BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
        • link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff
        • inet 10.0.1.175/32 scope global kube-ipvs0
        • valid_lft forever preferred_lft forever
      • kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置n个 IPVS 虚拟主机,并设置这n个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略
        • # ipvsadm -ln
        • IP Virtual Server version 1.2.1 (size=4096)
        • Prot LocalAddress:Port Scheduler Flags
        • -> RemoteAddress:Port Forward Weight ActiveConn InActConn
        • TCP 10.0.1.175:80 rr
        • -> 10.244.3.6:9376 Masq 1 0 0
        • -> 10.244.1.7:9376 Masq 1 0 0
        • -> 10.244.2.3:9376 Masq 1 0 0
    • 数据面:
      • client发向Cluster IP的请求
      • 被iptables规则直接重定向到ipvs(IPVS 模块只负责上述的负载均衡和代理功能。而一个完整的 Service 流程正常工作所需要的包过滤、SNAT 等操作,还是要靠 iptables 来实现。
      • IPVS 模块根据负载均衡算法,转发到某一个后端 Pod 上了
  • 优点:
    • 性能高一点,维护性也好点(在大规模集群里,为 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。
    • IPVS 并不需要在宿主机上为每个 Pod 设置 iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价

0条评论
作者已关闭评论
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
原创

K8s Service场景和原理

2023-09-01 01:21:49
53
0

背景&问题

当K8s的无状态应用Deployment有多个Pod的时候,我们访问这个应用,面临以下两个问题:

  • 需要负载均衡能力,转发到后端Pod
  • 负载均衡器需动态更新后端Pod(因为Pod重启后,IP会变化的问题)

解决方案

kubernetes提供了Service资源,作用如下:

  • 主要用于定义服务类型,服务如何找到后端Pod,服务端口和Pod端口映射关系

Service支持的访问需求:

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,client只能在集群内,通过该IP负载到后端的Pod
  • 集群外访问:
    • 通过Node节点暴露:
      • 服务类型:NodePort
      • 含义:会在Node节点上创建一个端口,通过NodeIP:NodePort负载到后端Pod
    • 通过集群外LoadBalance(Node节点外层再顶一个LoadBalance)
      • 服务类型:LoadBalance
      • 含义:请求先到ELB -> NodeIP:NodePort -> PodIP:PodPort(有很多种实现方式,这是其中一种)

常见问题

Service如何找到Pod?

使用selector通过标签,找到同标签的Pod(注意,service和deployment没什么关系)

apiVersion: v1

kind: Pod

metadata:

name: nginx

labels:

app.kubernetes.io/name: proxy

spec:

containers:

- name: nginx

image: nginx:stable

ports:

- containerPort: 80

name: http-web-svc

---

apiVersion: v1

kind: Service

metadata:

name: nginx-service

spec:

selector:

app.kubernetes.io/name: proxy

ports:

- name: name-of-service-port

protocol: TCP

port: 80

targetPort: http-web-svc

例子:

  • 通过标签找Pod
    • service找标签:app.kubernetes.io/name: proxy
    • Pod定义标签:app.kubernetes.io/name: proxy
  • 指定端口转发
    • service定义入口端口:port: 80,并转向pod的端口名,targetPort: http-web-svc
    • port定义端口名和端口号: - containerPort: 80 name: http-web-svc

Service类型有哪些?

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,client只能在集群内,通过该IP负载到后端的Pod
  • 集群外访问:
    • 通过Node节点暴露:
      • 服务类型:NodePort
      • 含义:会在Node节点上创建一个端口,通过NodeIP:NodePort负载到后端Pod
    • 通过集群外LoadBalance(Node节点外层再顶一个LoadBalance)
      • 服务类型:LoadBalance
      • 含义:请求先到ELB -> NodeIP:NodePort -> PodIP:PodPort(有很多种实现方式,这是其中一种)

Endpoint是什么?

可以简单理解为已经ready的pod,具备被访问条件的pod

当pod的readiness检测失败,pod不会加入到某个服务的Endpoints里面

如上图:10.1.3.8还没ready,就没有被加入my-service的Endpoints里

Service和Pod都会被分配域名吗?

Service 和 Pod 都会被分配对应的 DNS A 记录(从域名解析 IP 的记录)。

  • service
    • 对于 ClusterIP 模式的 Service 来说,它的 A 记录的格式是:..svc.cluster.local。
    • 当你访问这条 A 记录的时候,它解析到的就是该 Service 的cluster的 VIP 地址。
  • pod
    • 对于 ClusterIP 模式的 Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:..pod.cluster.local。
    • 这条记录指向 Pod 的 IP 地址

ClusterIP类型Service如何定义?

  • 集群内访问:
    • 服务类型:ClusterIP(默认值)
    • 含义:会创建一个集群内的服务IP,通过该IP会负载到后端的Pod
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

ClusterIP类型Service实现原理?

k8s的每个Node节点上都运行着一个kube-proxy服务进程。

  • 控制面:
    • 当创建Service的时候,会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则(有3种工作模式)
  • 数据面:
    • client访问服务IP(ClusterIp),会被Iptables拦截,转给ipvs做负载均衡转发

ClusterIp的实现原理?

  1. 是什么?
    1. 当创建一个带有ClusterIP类型的Service时,Kubernetes会为该Service分配一个唯一的ClusterIP地址
    2. 这个ClusterIp其实是一个VIP,只做负载用
    3. 这个IP地址是在集群的内部网络中使用的,并且只能由同一集群内的其他Pod访问
  1. 如何规划?
    1. Service地址段的管理由集群的网络插件负责。不同的网络插件可能有不同的管理方式。
    2. Kubernetes在集群创建时会预先定义一个内部IP地址段,这个IP地址段是专门用于集群内部通信的
    3. 参考云厂商的规划,是不能和Pod的CIDR地址段重叠
      • Flannel网络模式Service地址段。Service类型为ClusterIP(Type=ClusterIP)时,每个Service有自己的地址。配置网段时,请注意:
        • Service地址只在Kubernetes集群内使用,不能在集群外使用。
        • Service地址段不能和虚拟交换机地址段重叠。
        • Service地址段不能和Pod网络CIDR地址段重叠
  1. 如何分配某个IP?
    1. Kubernetes会自动为该Service分配一个ClusterIP地址。
    2. 参考Kubernetes 1.24: 避免为 Services 分配 IP 地址时发生冲突

kube-proxy3种工作模式原理?

1. userspace模式(淘汰)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy创建一个clusterIP
      • kube-proxy配置Iptables,将访问clusterIp请求转给kube-proxy
      • kube-proxy配置自身做为proxy,为每个Service创建一个监听端口,配置LB算法将请求转发到Pod上。
    • 数据面:
      • client发向Cluster IP的请求
      • 被iptables规则重定向到kube-proxy监听的端口上,
      • kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。
  • 缺点:
    • kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,性能较差

2. iptables模式(淘汰)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy创建一个clusterIP
        • 自动从Service地址段分配一个ip:10.0.1.175
      • kube-proxy为service后端的每个Pod创建对应的iptables规则
        • -A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
          • 表示:凡是目的地址是 10.0.1.175、目的端口是 80 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-NWV5X2332I4OT4T3 的 iptables 链进行处理
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
        • -A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
          • 表示:这三条链指向的最终目的地,其实就是这个 Service 代理的三个 Pod。所以这一组规则,就是 Service 实现负载均衡的位置。
          • 需要注意的是,iptables 规则的匹配是从上到下逐条进行的,所以为了保证上述三条规则每条被选中的概率都相同,我们应该将它们的 probability 字段的值分别设置为 1/3(0.333…)、1/2 和 1。
        • -A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
        • -A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
        • -A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
        • -A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
    • 数据面:
      • client发向Cluster IP的请求
      • iptables规则直接重定向到一个Pod IP
  • 优点:
    • 该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则,较userspace模式效率更高
  • 缺点
    • 当你的宿主机上有大量 Pod 的时候,成百上千条 iptables 规则不断地被刷新,会大量占用该宿主机的 CPU 资源,甚至会让宿主机“卡”在这个过程中。

3. ipvs模式(推荐)

  • 图示:
  • 工作方式:
    • 控制面:
      • kube-proxy监控Pod的变化并创建相应的ipvs规则
      • kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址
        • # ip addr
        • ...
        • 73:kube-ipvs0:<BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
        • link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff
        • inet 10.0.1.175/32 scope global kube-ipvs0
        • valid_lft forever preferred_lft forever
      • kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置n个 IPVS 虚拟主机,并设置这n个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略
        • # ipvsadm -ln
        • IP Virtual Server version 1.2.1 (size=4096)
        • Prot LocalAddress:Port Scheduler Flags
        • -> RemoteAddress:Port Forward Weight ActiveConn InActConn
        • TCP 10.0.1.175:80 rr
        • -> 10.244.3.6:9376 Masq 1 0 0
        • -> 10.244.1.7:9376 Masq 1 0 0
        • -> 10.244.2.3:9376 Masq 1 0 0
    • 数据面:
      • client发向Cluster IP的请求
      • 被iptables规则直接重定向到ipvs(IPVS 模块只负责上述的负载均衡和代理功能。而一个完整的 Service 流程正常工作所需要的包过滤、SNAT 等操作,还是要靠 iptables 来实现。
      • IPVS 模块根据负载均衡算法,转发到某一个后端 Pod 上了
  • 优点:
    • 性能高一点,维护性也好点(在大规模集群里,为 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。
    • IPVS 并不需要在宿主机上为每个 Pod 设置 iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价

文章来自个人专栏
云技术专栏
20 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
2
2