Kubernetes(k8s)-externalTrafficPolicy介绍和应用

作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

图片

我们上一章介绍了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 有两个可能的值:

  1. Cluster(默认)

    • 当 externalTrafficPolicy 设置为 Cluster 时,Kubernetes 的代理会从所有健康节点接收流量,并将其转发到后端 Pod。

    • 这意味着流量可能会被路由到任何节点上的任意一个合适的 Pod,不论该 Pod 是否在接收到请求的那个节点上运行。

    • 客户端的真实 IP 可能会在转发过程中丢失,因为流量通常通过内部 IP 在集群内传输。

  2. Local

    • 如果 externalTrafficPolicy 设置为 Local,那么只有运行了属于该服务的 Pod 的节点才会接收来自外部的流量。

    • 这种设置可以确保客户端的真实源 IP 传递给后端 Pod,因为流量直接到达承载 Pod 的节点。

    • 如果没有 Pod 在某个节点上运行,而流量指向了该节点,流量会被丢弃。这可能导致较低的资源利用率,但提供了更好的网络性能和保持客户端 IP 地址的能力。

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漂移会导致这个后端变更。

运维小路

一个不会开发的运维!一个要学开发的运维!一个学不会开发的运维!欢迎大家骚扰的运维!

关注微信公众号《运维小路》获取更多内容。

443446是同样的证书,修改成这样可行吗: apiVersion: v1 kind: Service metadata: name: vms-core-server-cloud-access-pa-fw-v1 namespace: dev3-vms annotations: service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: “Category=dev,Product=vms,ServiceType=biz” service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:ap-southeast-1:242777933053:certificate/74ff9ed2-8bcc-492d-b845-15308bace4e8 service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: “ELBSecurityPolicy-TLS13-1-2-Res-2021-06” service.beta.kubernetes.io/aws-load-balancer-ssl-ports: “443” service.beta.kubernetes.io/aws-load-balancer-type: “external” service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: “ip” service.beta.kubernetes.io/aws-load-balancer-scheme: “internet-facing” labels: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 spec: loadBalancerClass: service.k8s.aws/nlb selector: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 ports: - port: 443 protocol: TCP name: cloud-access-443 targetPort: cloud-access - port: 446 protocol: TCP name: cloud-access-446 targetPort: cloud-access-short type: LoadBalancer externalTrafficPolicy: Cluster apiVersion: v1 kind: Service metadata: name: vms-core-server-cloud-access-pa-fw-v2 namespace: dev3-vms annotations: service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: “Category=dev,Product=vms,ServiceType=biz” service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:ap-southeast-1:242777933053:certificate/e667c161-e7b0-4faa-a21e-23df5cb5f2d4 service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: “ELBSecurityPolicy-TLS13-1-2-Res-2021-06” service.beta.kubernetes.io/aws-load-balancer-ssl-ports: “443” service.beta.kubernetes.io/aws-load-balancer-type: “external” service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: “ip” service.beta.kubernetes.io/aws-load-balancer-scheme: “internet-facing” labels: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 spec: loadBalancerClass: service.k8s.aws/nlb selector: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 ports: - port: 443 protocol: TCP name: cloud-access-443 targetPort: cloud-access - port: 446 protocol: TCP name: cloud-access-446 targetPort: cloud-access-short type: LoadBalancer externalTrafficPolicy: Cluster
最新发布
10-18
<think>我们有两个Service:v1v2。现在要在每个Service上添加446端口,并且使用相同的证书(因为443446使用同样的证书)。 修改点: 1. 在metadata.annotations中,修改`service.beta.kubernetes.io/aws-load-balancer-ssl-ports`注解,将原来的"443"改为"443,446",以指示NLB在443446端口上启用SSL。 2. 在spec.ports下新增一个端口项,端口为446,协议TCP,名称自定义(如cloud-access-446),目标端口为cloud-access-short(对应service-monitor.yaml中的8084端口)。 但是,注意:当前配置中,两个Service的ssl-cert注解都只指定了一个证书ARN。由于两个端口使用相同的证书,这是可行的,因为同一个证书可以同时绑定到多个端口。 因此,您提供的修改配置中,缺少了对注解`service.beta.kubernetes.io/aws-load-balancer-ssl-ports`的更新(仍然为"443"),需要修改为"443,446"。 修改后的正确配置应为(以v1为例): ```yaml apiVersion: v1 kind: Service metadata: name: vms-core-server-cloud-access-pa-fw-v1 namespace: dev3-vms annotations: service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: “Category=dev,Product=vms,ServiceType=biz” service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:ap-southeast-1:242777933053:certificate/74ff9ed2-8bcc-492d-b845-15308bace4e8 # 同一个证书 service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: “ELBSecurityPolicy-TLS13-1-2-Res-2021-06” service.beta.kubernetes.io/aws-load-balancer-ssl-ports: “443,446” # 修改这里!!!将443改为443,446 service.beta.kubernetes.io/aws-load-balancer-type: “external” service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: “ip” service.beta.kubernetes.io/aws-load-balancer-scheme: “internet-facing” labels: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 spec: loadBalancerClass: service.k8s.aws/nlb selector: app.kubernetes.io/name: vms-core-server region: ap-southeast-1 ports: - port: 443 protocol: TCP name: cloud-access-443 targetPort: cloud-access - port: 446 protocol: TCP name: cloud-access-446 targetPort: cloud-access-short # 注意:targetPort是字符串,对应Pod端口的名称(在service-monitor.yaml中cloud-access-short对应8084) type: LoadBalancer externalTrafficPolicy: Cluster ``` 同样,对v2的Service也做相同的修改(添加端口446更新ssl-ports注解)。 因此,您提供的配置中,仅缺少更新注解`service.beta.kubernetes.io/aws-load-balancer-ssl-ports`的值。如果没有更新这个注解,那么446端口虽然被监听,但不会启用SSL,而是作为普通TCP端口(即不会解密密文流量),这会导致Pod接收加密流量(因为客户端是HTTPS)而无法处理。 所以,请务必更新该注解为`"443,446"`。 总结:您的修改配置中,除了注解`service.beta.kubernetes.io/aws-load-balancer-ssl-ports`的值未更新(仍为"443"),其他部分正确。更新该注解后,配置可行。 </think>### 回答 是的,您的修改方案**完全可行**,但需要补充一个关键步骤:必须同时在两个Service的`annotations`中更新`service.beta.kubernetes.io/aws-load-balancer-ssl-ports`注解,将其从`"443"`改为`"443,446"`。以下是完整分析验证: #### 修改后的配置分析(以v1为例): ```yaml apiVersion: v1 kind: Service metadata: annotations: # 关键修改点:必须更新此行 ↓ service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,446" # 原值为"443",需改为逗号分隔 service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:... # 证书ARN保持不变(443446共享同一证书) # 其他注解保持不变... spec: ports: - port: 443 targetPort: cloud-access # 映射到8083端口 - port: 446 # 新增端口 name: cloud-access-446 targetPort: cloud-access-short # 映射到8084端口! # 其他配置保持不变... ``` #### 关键验证点: 1. **SSL端口注解更新**(必须修改): - 原配置中`service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"` **必须改为`"443,446"`**,否则AWS NLB不会为446端口启用HTTPS卸载。 - 未修改时,446端口将被视为普通TCP端口(未加密)。 2. **证书兼容性**: - 同一证书ARN可复用,AWS NLB会自动将证书绑定到`443``446`两个监听器。 3. **端口映射正确性**: - `targetPort: cloud-access-short` 正确引用`service-monitor.yaml`中的8084端口定义: ```yaml - name: cloud-access-short # 名称匹配 port: 8084 # 映射到Pod的8084端口 ``` 4. **双Service配置**: - `v1``v2` Service需同时修改,确保流量负载均衡。 #### 最终可行的配置修改: 仅需在**两个Service的`metadata.annotations`中**增加一行修改: ```diff service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,446" ``` 其他部分完全符合您的YAML描述。应用后,AWS NLB将: - 在443端口接收HTTPS流量 → 转发到Pod的8083端口 - 在446端口接收HTTPS流量 → 转发到Pod的8084端口 > **风险提示**:修改后需监控现有443端口流量是否受影响,建议在低峰期操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值