创建用于测试的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 的核心功能,下面列出所涉及到的链:
- PREROUTING 链:此链是由 kube-proxy 组件创建的,用于将 Service IP 地址映射到对应的 Pod IP 地址上。当请求进入节点时,该链将被触发,它根据请求的 Service IP 地址来查找对应的 Pod IP 地址,并将请求转发到该 Pod。
- KUBE-SERVICES 链:此链包含了一系列规则,用于将 Service IP 地址映射到对应的 Pod IP 地址上。当请求进入节点时,该链将被触发,并根据请求的 Service IP 地址来查找对应的 Pod IP 地址。如果找到了对应的 Pod IP 地址,请求将被转发到该 Pod。
- KUBE-SVC-XXX 链:此链包含了一系列规则,其中 XXX 代表 Service 的名称。每个 Service 都有一个对应的 KUBE-SVC-XXX 链。当请求进入节点时,该链将被触发,并根据 Service IP 地址查找对应的 KUBE-SVC-XXX 链。该链中的规则将请求转发到对应的 Pod。
- KUBE-SEP-XXX 链:此链包含了一系列规则,其中 XXX 代表 Service 的名称。每个 Service 都有一个对应的 KUBE-SEP-XXX 链。当请求进入节点时,该链将被触发,并根据 Service IP 地址查找对应的 KUBE-SEP-XXX 链。该链中的规则将请求转发到对应的 Pod。
- KUBE-FIREWALL 链:此链用于处理来自 Kubernetes 的内部流量。该链包含了一些规则,用于控制访问 Kubernetes 的 API、DNS 和其他一些服务。
- KUBE-NODEPORT 链:当 Service 类型为 NodePort 时,此链将被创建。该链包含了一些规则,用于将节点的端口映射到 Service 的端口上。
- 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条规则
-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集群中的不同部分可能会有所不同。在实际使用时,链的名称可能会因不同的部署而有所变化,但规则的作用通常是相似的。
- 大概看看第2条
-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 的链上进行进一步处理。
- 大概看看第3条
-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 的链进行转换。
- 再看看第4条
-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的配置和维护。