作者介绍:简历上没有一个精通的运维工程师,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。
我们上一章介绍了Docker基本情况,目前在规模较大的容器集群基本都是Kubernetes,但是Kubernetes涉及的东西和概念确实是太多了,而且随着版本迭代功能在还增加,笔者有些功能也确实没用过,所以只能按照我自己的理解来讲解。
我们在svc的时候,svc有一种类型叫NodePort,它是会在每个node上都有对应的iptables规则去请求拦截,如果我们有20个,甚至200个节点的时候,我们应该去访问哪一个节点?或者当我们使用LoadBalance的时候,它必须要有后端RS,我们把这个200个节点都作为后端RS么,如果是这样管理就会比较复杂,好在Kubernetes给我们提供了一个字段叫做:externalTrafficPolicy,它不仅可以规定掉刚才问题,还可以规避掉经过NAT转换以后的源ip丢失的问题。
externalTrafficPolicy 是 Kubernetes 中 Service 资源的一个属性,它主要用于控制 Service 如何将流量路由到 Pod。这个属性对于类型为 LoadBalancer 和 NodePort 的服务特别重要,因为它影响客户端 IP 的保留以及流量的负载均衡方式。
externalTrafficPolicy 有两个可能的值:
externalTrafficPolicy
设置为 Cluster
时,Kubernetes 的代理会从所有健康节点接收流量,并将其转发到后端 Pod。externalTrafficPolicy
设置为 Local
,那么只有运行了属于该服务的 Pod 的节点才会接收来自外部的流量。apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort # 添加此行以更改服务类型为 NodePort,未添加则是ClusterIP
selector:
app: myapp
ports:
- protocol: TCP
port: 80 # 服务的集群内部端口
targetPort: 80 # Pod 上的应用程序端口
nodePort: 30008 # 可选:指定 NodePort 的端口号,如果不指定则自动分配
这里我们还是复用我们前面的配置,虽然我们并没有在svc的yaml文件里面定义externalTrafficPolicy,但是查看这个svc的详细信息,是可以看到这个字段的,并且自动给我们添加了默认值Cluster。
[root@master01 svc]# kubectl get svc my-service -o yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2025-01-15T15:30:12Z"
name: my-service
namespace: default
resourceVersion: "801401"
selfLink: /api/v1/namespaces/default/services/my-service
uid: 0b347fa0-a571-41d6-9fd5-ce960114f4e8
spec:
clusterIP: 10.111.230.179
clusterIPs:
- 10.111.230.179
externalTrafficPolicy: Cluster #自动添加的字段
internalTrafficPolicy: Cluster #也是自动添加的,但是今天不讲这个字段
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- nodePort: 30008
port: 80
protocol: TCP
targetPort: 80
selector:
app: myapp
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
我们无论通过集群外访问还是集群内外访问,后端nginx获取的客户端ip地址都是CNI插件给我们分配的节点ip地址,如果我们的应用,需要客户端真实ip,使用这个配置则无法满足要求。
10.244.0.0 - - [15/Jan/2025:15:37:58 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
10.244.0.0 - - [15/Jan/2025:15:38:07 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
10.244.1.1 - - [15/Jan/2025:15:38:22 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
10.244.1.1 - - [15/Jan/2025:15:38:23 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
当我们把externalTrafficPolicy修改成Local,集群外访问已经可以获得客户端真实ip地址,集群内访问还是无法获取真实ip,不过这个需求一般很少,有兴趣可以下去研究下。
192.168.31.201 - - [15/Jan/2025:15:41:53 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
10.244.0.0 - - [15/Jan/2025:15:42:04 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
10.244.0.0 - - [15/Jan/2025:15:42:49 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"
#Pod所在节点iptables规则,正常转发
-A KUBE-XLB-FXIYY6OHUSNBITIX -m comment --comment "default/my-service"
-j KUBE-SEP-RPL3ZC3VS2WNO5G6
#Pod不在节点的iptables规则,会拒绝请求
-A KUBE-XLB-FXIYY6OHUSNBITIX -m comment --comment "default/my-service
has no local endpoints" -j KUBE-MARK-DROP
简单点说,现在的NodePort只有Pod所在节点能使用NodeIP+NodePort访问,其他没有Pod则不能访问,这样就可以减少LB的后端。比如200个节点,某Pod跑了5个副本(在不同的node),那么这个LB的后端就只有这个5个机器,就不会出现后端200个的情况,当然LB还必须要具备自动更新RS后端能力,因为Pod漂移会导致这个后端变更。