kubernetes的pod中获取客户端真实ip

kubernetes的pod中获取客户端真实ip

在 Kubernetes 中,Pod 拿到的远程 IP 是 Kubernetes 集群内部的 IP,而不是客户端的真实 IP。这是由于 Kubernetes 的网络模型和网络配置方式导致的。
Kubernetes 使用了一种称为 "Service" 的抽象来提供网络连接和负载均衡功能。当您创建一个 Service,并将其与 Pod 关联时,Kubernetes 会为该 Service 分配一个虚拟 IP(Cluster IP)。当客户端通过 Service IP 访问该服务时,请求会被负载均衡到后端的 Pod 上。在这种情况下,当请求到达 Pod 时,Pod 看到的远程 IP 是来自 Kubernetes 集群内部的 Service IP,而不是客户端的真实 IP。这是因为请求实际上是通过 Kubernetes 集群的网络层转发的,Pod 无法直接感知客户端的真实 IP。
如果您需要获取客户端的真实 IP,可以考虑使用 Kubernetes 的 Ingress 控制器或类似的解决方案。Ingress 控制器可以在 Kubernetes 集群外部创建一个反向代理,并在请求到达集群之前解析客户端的真实 IP。这样,您的 Pod 就可以通过某种方式获取到客户端的真实 IP。
另外,还可以考虑使用 Kubernetes 的网络插件或服务代理来进行更高级的网络配置,以实现更精确的 IP 管理和流量控制。

方法

要在 Kubernetes 中的 Pod 中获取客户端的真实 IP,可以考虑以下几种方法:
使用 Ingress 控制器:如果您在 Kubernetes 集群中使用了 Ingress 控制器(如 Nginx Ingress Controller、Traefik、HAProxy 等),您可以配置 Ingress 规则以将客户端的真实 IP 传递给后端的 Pod。通常,Ingress 控制器会在请求头中添加一个特定的字段,例如 X-Forwarded-For 或 X-Real-IP,其中包含客户端的真实 IP。您可以在 Pod 中读取该请求头字段来获取真实 IP。

使用代理服务器:您可以在 Pod 前面添加一个代理服务器,例如 Nginx 或 Envoy,该代理服务器可以接收来自客户端的请求,并将真实 IP 作为请求头传递给后端的 Pod。您可以在代理服务器的配置中设置相应的选项来实现这一点。

使用 Kubernetes 的 Network Policy:如果您的 Kubernetes 集群启用了 Network Policy 功能,您可以在 Network Policy 中配置 externalTrafficPolicy: Local,这将保留客户端的原始 IP 地址。然后,您可以在 Pod 中查看连接的源 IP 地址,以获取客户端的真实 IP。

需要注意的是,这些方法的实现可能因您使用的 Kubernetes 发行版、网络插件和配置方式而有所不同。建议查阅相关文档或咨询 Kubernetes 社区以获取更详细和准确的信息。

代理服务器+nodeport来获取客户端ip

由于特殊原因,接手的k8s集群没有使用了 Ingress 控制器,对 Network Policy也不熟悉,所以验证使用代理服务器+nodeport来获取客户端ip
在 Kubernetes 中,Service 是一种抽象,用于公开一组 Pod 的网络终结点。当您创建一个 Service 时,可以通过 externalTrafficPolicy 字段来配置服务的外部流量策略。

externalTrafficPolicy 字段有两个可选值:

  • Cluster(默认值):当流量进入 Service 时,它将被负载均衡到后端 Pod,无论流量的源 IP 是什么。这意味着所有流量都会被转发到后端 Pod,即使它们的源 IP 地址相同。这对于需要负载均衡的情况很有用。

  • Local:当流量进入 Service 时,它将根据源 IP 地址进行负载均衡,并将流量转发到与源 IP 地址最近的后端 Pod。这意味着相同源 IP 的流量将被转发到同一个后端 Pod,这对于需要保持会话一致性的应用程序很有用。

步骤1:部署pod、svc

这里我们使用镜像 containous/whoami 作为后端服务镜像。这个镜像的80端口能返回客户端ip,不需要我们额外编写获取ip的工具。

cat realip.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: realip
  name: realip
  namespace: sit-meta
spec:
  type: NodePort
#这里非常重要,注意配置为Local,默认是cluster模式。
  externalTrafficPolicy: Local
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 31508
  selector:
    app: realip
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: realip
  name: realip
  namespace: sit-meta
spec:
  replicas: 1
  selector:
    matchLabels:
      app: realip
  strategy: 
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: realip
    spec:
      containers:
      - image: harbor.vonechain.com/sit-meta/whoami
        name: realip
        ports:
        - containerPort: 80

启动:

 kubectl create -f realip.yaml

查看:

# kubectl get svc,pod,deploy -n sit-meta -owide |grep realip

使用master的ip和运行了pod的node节点ip加上端口,都能访问。其他node节点不能访问,会出现curl: (7) Failed to connect to 172.16.30.52 port 31508: 连接超时。受制于 Local 模式,可能会导致服务不可访问。需要保证对外提供入口的节点上,必须具有服务的负载,所以我们通过nginx方向代理进行代理到指定node。
将容器pod增加固定node运行的配置:

    spec:
      nodeName: sitnode3051    #增加指定node的配置
      containers:
      - image: harbor.vonechain.com/sit-meta/metaverse-everest:79

步骤2:部署代理服务器

在一台nginx服务器172.16.30.129上进行部署,该机器已经配置好公网和域名sit-meta-everest.vonechain.com

nginx配置:sit-meta-everest.vonechain.com.conf

 cat sit-meta-everest.vonechain.com.conf 
upstream  sitmeta-everest {
          server 172.16.30.51:31508 ;
    }
server {
    listen   80; 
    server_name  sit-meta-everest.vonechain.com;
    return 301 https://$host$request_uri;
}
server {
       listen 443 ssl;
       server_name sit-meta-everest.vonechain.com;
       ssl_certificate  /usr/local/nginx/ssl/vonechain.com.pem;
       ssl_certificate_key  /usr/local/nginx/ssl/vonechain.com.key;
       ssl_session_timeout 5m;
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
       ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
       ssl_prefer_server_ciphers on;
       location /  {
#将客户端真实ip放入到 X-Forwarded-For
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

#客户端真实协议(http/https)
                proxy_set_header X-Forwarded-Proto $scheme;

#host修改真实的域名和端口
                proxy_set_header Host $http_host;
                proxy_pass http://sitmeta-everest;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "Upgrade";

                access_log  logs/meta-everest.access.log main;
                error_log   logs/meta-everest.error.log;
}


        }

重新启动nginx:

# /usr/local/nginx/sbin/nginx -s reload

步骤3:检查

在浏览器中输入https://sit-meta-everest.vonechain.com/
在长沙办公室进行检查:

可以看到nginx代理ip和长沙机房的出口ip
换到上海机房的网络再检查:

新的网络可以查到客户端ip已经换成上海机房的出口ip

后续待验证

通过 LB -> Service 访问获取真实 IP

利用 LB 的探活能力,能够提高服务的可访问性。适用于服务较少,或者愿意每个服务一个 LB 的场景。

通过 LB -> Ingress -> Service 访问获取真实 IP

通过 LB 将 80、443 端口的流量转到 Ingress Controller ,再进行服务分发。但 Ingress Controller 使用 Local 模式,就要求 LB 的每个后端节点都有 Ingress Controller 副本。适用于对外暴露服务数量较多的场景。

作者:KubeSphere
链接:https://juejin.cn/post/6937108793427771429
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

posted @ 2024-02-29 15:14  邹姣姣  阅读(726)  评论(0编辑  收藏  举报