目录

service使用local模式仍无法获取到访问端源ip问题总结

问题简介

根据kubernetes官方文档所述:

Kubernetes 提供了一个特性来保留客户端的源 IP 地址。设置 service.spec.externalTrafficPolicy 的值为 Local,请求就只会被代理到本地 endpoints 而不会被转发到其它节点。这样就保留了最初的源 IP 地址。如果没有本地 endpoints,发送到这个节点的数据包将会被丢弃。这样在应用到数据包的任何包处理规则下,你都能依赖这个正确的 source-ip 使数据包通过并到达 endpoint。

参考文档:https://kubernetes.io/zh/docs/tutorials/services/source-ip/#type-nodeport-%E7%B1%BB%E5%9E%8B-services-%E7%9A%84-source-ip

我们将service的参数service.spec.externalTrafficPolicy 的值设置为 Local,以保证我们部署的nginx可以正确看到源地址。但是在使用中发现,nginx日志中记录的地址,均非源地址,而是pod所在节点网桥的地址。

环境概览

ip地址信息如下:

podip:172.18.0.97

pod所在节点ip:10.0.1.37

有如下两个资源:

  1. Deployment:nginx

    使用官方默认镜像,无任何特殊配置,yaml如下,以略去非必要项

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: nginx
      template:
        metadata:
          labels:
            k8s-app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
    
  2. Service:nginx-svc

    配置如下,已略去非必要内容,并已经开启externalTrafficPolicy: Local

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
    spec:
      clusterIP: 172.18.255.31
      externalTrafficPolicy: Local
      ports:
      - name: http
        nodePort: 30567
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        k8s-app: nginx
        qcloud-app: nginx
      type: NodePort
    

问题复现

通过自己的办公机,对pod所在节点进行ip地址+nodeport端口方式进行访问测试,结果如下,nginx端看到的访问地址,并不是我办公机公网出口的地址,这个地址经我查询,是pod所在节点网桥上的地址: /images/service%E4%BD%BF%E7%94%A8local%E6%A8%A1%E5%BC%8F%E4%BB%8D%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%E8%AE%BF%E9%97%AE%E7%AB%AF%E6%BA%90ip%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/image-20210908201915167.png

问题排查

local模式下,请求就只会被代理到本地 endpoints 而不会被转发到其它节点。故此现象,问题应该是发生在pod所在节点上,应该是节点上有什么iptables规则,导致此问题发生。

在我们的集群上,有使用到ip-masq-agent组件,去控制在何种ip情况下去做SNAT转换,故怀疑是否因此问题导致。

经查询iptables的nat规则发现,节点上的nat规则如下:

/images/service%E4%BD%BF%E7%94%A8local%E6%A8%A1%E5%BC%8F%E4%BB%8D%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%E8%AE%BF%E9%97%AE%E7%AB%AF%E6%BA%90ip%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/image-20210908205651126.png

但是我们的集群,容器的网络是172.18.0.0/16,这里明显是配置有误的,故查看ip-masq-agent的配置文件,发现这里的配置果然有问题:

/images/service%E4%BD%BF%E7%94%A8local%E6%A8%A1%E5%BC%8F%E4%BB%8D%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%E8%AE%BF%E9%97%AE%E7%AB%AF%E6%BA%90ip%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/image-20210908205831577.png

修改这里的配置为我们期望的172.18.0.0/16后,等待约一分钟的时间,让configmap进行热更新,更新后,再次查看iptables的规则,已经恢复成我们期望的

/images/service%E4%BD%BF%E7%94%A8local%E6%A8%A1%E5%BC%8F%E4%BB%8D%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%E8%AE%BF%E9%97%AE%E7%AB%AF%E6%BA%90ip%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/image-20210908210047603.png

修复后验证

修复ip-masq-agent规则后,再次尝试请求nodeip+nodeport进行测试,结果已经正常,nginx获取到的地址正是我办公机网络的出口地址

/images/service%E4%BD%BF%E7%94%A8local%E6%A8%A1%E5%BC%8F%E4%BB%8D%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%E8%AE%BF%E9%97%AE%E7%AB%AF%E6%BA%90ip%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/image-20210908210235956.png

总结

ip-masq-agent组件会根据配置,决定于哪些ip需要进行nat转换,哪些不需要,本例为错误的配置了相关规则,导致service的local模式无法生效

参考文档

IP Masquerade Agent 用户指南

使用 Source IP