《做一个不背锅运维:K8S Service底层策略初探和分析》

2023-03-24 12:38:40 浏览数 (2)

创建用于测试的Deployment和Service

代码语言:txt复制
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test-goweb
  name: test-goweb
spec:
  replicas: 6
  selector:
    matchLabels:
      app: test-goweb
  template:
    metadata:
      labels:
        app: test-goweb
    spec:
      containers:
      - image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        imagePullPolicy: IfNotPresent
        name: goweb-demo
        ports:
        - containerPort: 8090
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: test-goweb
  name: test-goweb
spec:
  ports:
  - name: 80-8090
    nodePort: 30010
    port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: test-goweb
  type: NodePort

Service底层有哪些iptables链

当在 Kubernetes 中创建 Service 时,将会创建以下几个 iptables 链。这些链都是用于实现 Service 的核心功能,下面列出所涉及到的链:

  1. PREROUTING 链:此链是由 kube-proxy 组件创建的,用于将 Service IP 地址映射到对应的 Pod IP 地址上。当请求进入节点时,该链将被触发,它根据请求的 Service IP 地址来查找对应的 Pod IP 地址,并将请求转发到该 Pod。
  2. KUBE-SERVICES 链:此链包含了一系列规则,用于将 Service IP 地址映射到对应的 Pod IP 地址上。当请求进入节点时,该链将被触发,并根据请求的 Service IP 地址来查找对应的 Pod IP 地址。如果找到了对应的 Pod IP 地址,请求将被转发到该 Pod。
  3. KUBE-SVC-XXX 链:此链包含了一系列规则,其中 XXX 代表 Service 的名称。每个 Service 都有一个对应的 KUBE-SVC-XXX 链。当请求进入节点时,该链将被触发,并根据 Service IP 地址查找对应的 KUBE-SVC-XXX 链。该链中的规则将请求转发到对应的 Pod。
  4. KUBE-SEP-XXX 链:此链包含了一系列规则,其中 XXX 代表 Service 的名称。每个 Service 都有一个对应的 KUBE-SEP-XXX 链。当请求进入节点时,该链将被触发,并根据 Service IP 地址查找对应的 KUBE-SEP-XXX 链。该链中的规则将请求转发到对应的 Pod。
  5. KUBE-FIREWALL 链:此链用于处理来自 Kubernetes 的内部流量。该链包含了一些规则,用于控制访问 Kubernetes 的 API、DNS 和其他一些服务。
  6. KUBE-NODEPORT 链:当 Service 类型为 NodePort 时,此链将被创建。该链包含了一些规则,用于将节点的端口映射到 Service 的端口上。
  7. KUBE-MARK-DROP 链:当请求被拒绝时,会触发此链。该链包含了一些规则,用于标记被拒绝的数据包。

这些 iptables 链是 Kubernetes 中实现 Service 的关键组件。它们使得客户端可以使用 Service 名称来访问运行在 Pod 中的应用程序,而不必了解其具体 IP 地址。

查看和这个service有关的iptables规则

代码语言:txt复制
# iptables-save | grep test-goweb

-A KUBE-EXT-XRKWZPWLY5ZGEEBK -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations" -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp --dport 30010 -j KUBE-EXT-XRKWZPWLY5ZGEEBK
-A KUBE-SEP-2KC5TQ77EILRJT77 -s 10.244.240.51/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-2KC5TQ77EILRJT77 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.51:8090
-A KUBE-SEP-5AVQRPMC6RQQAAKG -s 10.244.240.9/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-5AVQRPMC6RQQAAKG -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.9:8090
-A KUBE-SEP-7QBH2WDQDSESRX53 -s 10.244.240.19/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-7QBH2WDQDSESRX53 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.19:8090
-A KUBE-SEP-KGPYN3PAVPO2A2G3 -s 10.244.240.20/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-KGPYN3PAVPO2A2G3 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.20:8090
-A KUBE-SEP-VXCKMNYZWUWZOOOJ -s 10.244.240.38/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-VXCKMNYZWUWZOOOJ -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.38:8090
-A KUBE-SEP-XH5PMCJ3CYSK4B7L -s 10.244.240.56/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-XH5PMCJ3CYSK4B7L -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.56:8090
-A KUBE-SERVICES -d 10.104.238.165/32 -p tcp -m comment --comment "default/test-goweb:80-8090 cluster IP" -m tcp --dport 80 -j KUBE-SVC-XRKWZPWLY5ZGEEBK
-A KUBE-SVC-XRKWZPWLY5ZGEEBK ! -s 10.244.0.0/16 -d 10.104.238.165/32 -p tcp -m comment --comment "default/test-goweb:80-8090 cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.19:8090" -m statistic --mode random --probability 0.16666666651 -j KUBE-SEP-7QBH2WDQDSESRX53
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.20:8090" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-KGPYN3PAVPO2A2G3
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.38:8090" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-VXCKMNYZWUWZOOOJ
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.51:8090" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-2KC5TQ77EILRJT77
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.56:8090" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XH5PMCJ3CYSK4B7L
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.9:8090" -j KUBE-SEP-5AVQRPMC6RQQAAKG

上面看到的这一堆规则,就是由 kube-proxy 组件自动创建和维护 iptables 规则,继续往下看,抽几条规则做个简单的分析。

简单分析

  1. 先看整体看看这1条规则
代码语言:txt复制
-A KUBE-EXT-XRKWZPWLY5ZGEEBK -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations" -j KUBE-MARK-MASQ

这是上面第一条iptables规则,它用于Kubernetes集群中的网络转发和流量伪装。具体来说,这个规则将来自Kubernetes服务“default/test-goweb”的流量伪装为外部目标,以便它们可以通过集群外部访问。

规则中的参数解释如下:

  • -A:将规则添加到链的末尾
  • KUBE-EXT-XRKWZPWLY5ZGEEBK:链的名称
  • -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations":添加一条注释,说明此规则是用于伪装“default/test-goweb”的流量,并指定了流量端口范围和目标类型
  • -j KUBE-MARK-MASQ:将流量标记为需要进行伪装的流量,以便其能够离开集群并在目标处正确路由

请注意,KUBE-EXT-XRKWZPWLY5ZGEEBK、KUBE-MARK-MASQ是自定义的链名称,它在Kubernetes集群中的不同部分可能会有所不同。在实际使用时,链的名称可能会因不同的部署而有所变化,但规则的作用通常是相似的。

  1. 大概看看第2条
代码语言:txt复制
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp --dport 30010 -j KUBE-EXT-XRKWZPWLY5ZGEEBK

它的作用是将从 NodePort 类型的 Service 访问到的流量(目标端口为 30010/tcp)转发到名为 KUBE-EXT-XRKWZPWLY5ZGEEBK 的链上进行进一步处理。

  1. 大概看看第3条
代码语言:txt复制
-A KUBE-SEP-2KC5TQ77EILRJT77 -s 10.244.240.51/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ

它的作用是将来自 IP 地址为 10.244.240.51 的源地址流量进行 SNAT 转换,以便将源 IP 地址更改为 Node 的 IP 地址,从而使流量能够返回到客户端。该规则使用名为 KUBE-MARK-MASQ 的链进行转换。

  1. 再看看第4条
代码语言:txt复制
-A KUBE-SEP-2KC5TQ77EILRJT77 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.51:8090

它的作用是将从集群内某个节点上的 Pod 访问 Service 的流量进行 DNAT 转换,以便将流量重定向到特定 Pod 的 IP 地址和端口上。

k8s的iptables规则是由k8s自身自动维护的,它使用 kube-proxy 组件来自动创建和维护 iptables 规则,当创建一个 Service 时,kube-proxy 会自动为该 Service 创建一组 iptables 规则,当 Pod 被添加或删除时,kube-proxy 会相应地更新这些规则。所以,不需要人为手动管理这些规则,简直是香到不行。

将Service底层的代理模式改为IPVS后

代码语言:txt复制
tantianran@test-b-k8s-master:~$ kubectl get svc test-goweb
NAME         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
test-goweb   NodePort   10.104.238.165   <none>        80:30010/TCP   25h

在其中一台节点上看虚拟服务器信息

代码语言:txt复制
tantianran@test-b-k8s-node01:~$ sudo ipvsadm-save
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r test-b-k8s-master:6443 -m -w 1
-A -t test-b-k8s-node01:domain -s rr
-a -t test-b-k8s-node01:domain -r 10.244.82.19:domain -m -w 1
-a -t test-b-k8s-node01:domain -r 10.244.240.60:domain -m -w 1
-A -t test-b-k8s-node01:9153 -s rr
-a -t test-b-k8s-node01:9153 -r 10.244.82.19:9153 -m -w 1
-a -t test-b-k8s-node01:9153 -r 10.244.240.60:9153 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:8000 -s rr
-a -t test-b-k8s-node01:8000 -r 10.244.240.16:8000 -m -w 1
-A -t test-b-k8s-node01:http -s rr
-a -t test-b-k8s-node01:http -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r 10.244.240.15:4443 -m -w 1
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -u test-b-k8s-node01:domain -s rr
-a -u test-b-k8s-node01:domain -r 10.244.82.19:domain -m -w 1
-a -u test-b-k8s-node01:domain -r 10.244.240.60:domain -m -w 1

要注意了,在上面的虚拟服务器信息中可以看到,有的是-a,有的是-A,这两个选项都可以用于向IPVS中添加一个新的服务(virtual server)。它们的区别不仅仅在于是大小写的区别,更大的区别在于添加服务的方式和语义上略有不同:

  • -a选项将添加一个新的服务,并将其附加到一个现有的调度器上。如果调度器不存在,则会创建一个新的调度器。
  • -A选项将添加一个新的服务,并将其附加到一个现有的调度器上。如果调度器不存在,则不会创建新的调度器。如果调度器已经存在,则服务将被添加到现有的调度器中。

拿这条策略来看看

代码语言:txt复制
-a -t test-b-k8s-node01:http -r 10.244.240.24:8090 -m -w 1

以下是每个选项的含义:

  • -a: 添加虚拟服务
  • -t test-b-k8s-node01:http: 虚拟服务的名称和协议。
  • -r 10.244.240.24:8090: 后端真实服务器的IP地址和端口号,也就是POD的。
  • -m: 使用IPVS的NAT模式。
  • -w 1: 将权重设置为1,即将1个请求发送给该服务器。

总而言之它的作用是:它将添加一个名为test-b-k8s-node01的HTTP虚拟服务,并将客户端的请求源IP地址改为工作节点的IP地址,并将请求发送到后端服务器10.244.240.24:8090,其中只有一个后端服务器,它的服务能力是1。

最后的总结

k8s中的Service底层不管是iptables还是ipvs,它们的策略规则都是k8s自身自动维护的。具体来说,当创建一个Service时,Kubernetes会在底层为该Service创建一个虚拟IP(VIP),并自动配置iptables或者ipvs规则,使得这个VIP可以将流量转发到Service中的多个Pod实例。

当使用iptables时,Kubernetes会在每个节点上创建iptables规则,通过iptables NAT功能实现负载均衡和服务发现。而当使用ipvs时,Kubernetes会在每个节点上创建ipvs规则,并使用ipvs的负载均衡算法实现服务发现和流量转发。

无论是使用iptables还是ipvs,Kubernetes都会自动维护这些规则,保证Service的负载均衡和高可用性。当Service中的Pod实例发生变化时,Kubernetes会自动更新iptables或ipvs规则,以确保流量能够正确地转发到新的Pod实例上。Kubernetes通过自动化的方式,简化了Service的配置和维护。

0 人点赞