
# 不同场景下容器内获取客户端源IP
在容器化环境中，客户端与容器服务器间的通信可能涉及多种代理服务器。当外部请求经过代理服务器多层转发时，客户端源IP地址可能无法被成功传递至容器内的业务中。本文将针对CCE集群提供网络访问的不同方案，详细说明如何在容器内部有效地获取客户端源IP。
#### 场景介绍
图1容器中获取源IP   
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001717422049.png "点击放大")
根据不同的网络设置，容器内获取客户端源IP的方法可能会有所不同。以下是几种常见的网络访问配置及其对应的解决方案：
- **Ingress七层转发：**应用在七层访问时，客户端源IP默认保存在HTTP头部的"X-Forwarded-For"字段，无需进行其他配置即可获取客户端源IP。
- **Service四层转发：** 不同类型的Service获取源IP的方式及原理不同。
  - 负载均衡类型Service：将弹性负载均衡器作为流量入口，支持使用共享型或独享型的弹性负载均衡器。
    - 共享型弹性负载均衡器需要在监听器上开启"获取客户端IP"功能。
    
    - 独享型弹性负载均衡器在监听器上默认启用"获取客户端IP"功能，无需用户手动设置。
     
  
  - 节点访问类型Service：将容器端口映射到节点端口，将节点端口作为对外服务的访问入口。节点访问Service的客户端源IP能力与它的"服务亲和"配置相关。
    - 当节点访问类型Service的"服务亲和"配置为"集群级别"时，流量在集群中会经过一次转发，导致Service后端的容器无法获取客户端源IP。
    
    - 当节点访问类型Service的"服务亲和"配置为"节点级别"时，流量不经过转发直接访问节点上的容器，因此Service后端的容器可以获取客户端源IP。
     
   
![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
若已使用Istio服务网格，获取源IP地址的方法请参见[服务加入Istio后，如何获取客户端真实源IP？](https://support.huaweicloud.com/cce_faq/cce_faq_00299.html)
 #### 支持获取源IP地址的场景
由于网络模型差异，CCE在部分使用场景下暂不支持获取源IP，如[表1]，若在集群使用过程中需要获取源IP，请尽量避免此类场景。表中"-"代表无此场景。
 表1支持获取源IP地址的场景分类 
| 一级分类          | 二级分类                         | 负载均衡类型 | VPC、容器隧道网络模型 | 云原生网络2.0模型（CCE Turbo集群）    | 操作指导                                                                                                          |
|:---|:---|:---|:---|:---|:---|
| 七层转发（Ingress） | ELB型                         | 共享型    | 支持           | 支持                         | [ELB Ingress]  |
| 七层转发（Ingress） | ELB型                         | 独享型    | 支持           | 支持                         | [ELB Ingress]  |
| 七层转发（Ingress） | Nginx型（对接NGINX Ingress控制器插件） | 共享型    | 支持           | 暂不支持                       | [Nginx Ingress]                                                 |
| 七层转发（Ingress） | Nginx型（对接NGINX Ingress控制器插件） | 独享型    | 支持           | 支持                         | 默认开启，无需进行其他配置                                                                                                 |
| 四层转发（Service） | 负载均衡（LoadBalancer）           | 共享型    | 支持           | 暂不支持（使用hostNetwork的工作负载支持） | [负载均衡( LoadBalancer )]                   |
| 四层转发（Service） | 负载均衡（LoadBalancer）           | 独享型    | 支持           | 支持                         | [负载均衡( LoadBalancer )]                   |
| 四层转发（Service） | 节点访问（NodePort）               | -      | 支持           | 暂不支持（使用hostNetwork的工作负载支持） | [节点访问 ( NodePort )]                                            |
   
 #### ELB Ingress
对于ELB Ingress（即使用HTTP/HTTPS协议），ELB默认会开启获取客户端源IP，无需其他操作。
客户端源IP会被负载均衡放在HTTP头部的X-Forwarded-For字段，格式如下：
```
X-Forwarded-For: 客户端源IP, 代理服务器1-IP,  代理服务器2-IP, ...
```
X-Forwarded-For字段中获取的第一个地址就是获取客户端源IP。
 #### Nginx Ingress
![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
云原生网络2.0模型下（即CCE Turbo集群），**Ingress开启对接NGINX Ingress控制器插件时** **使用共享型ELB暂不支持获取源IP** ，参见[支持获取源IP地址的场景]。如需获取源IP，请卸载NGINX Ingress控制器插件并在重新安装时使用独享型ELB。
- Nginx Ingress使用独享型ELB时，默认开启源地址透传功能，无需其他配置即可获取客户端源IP。
- Nginx Ingress使用共享型ELB时，获取客户端源IP的操作步骤如下：
1. 以Nginx工作负载为例，未配置源IP访问前，使用以下命令查看访问日志，其中nginx-c99fd67bb-ghv4q为Pod名称： 
   ```
   kubectl logs nginx-c99fd67bb-ghv4q
   ```
   回显如下：
   ```
   ...
   10.0.0.7 - - [17/Aug/2023:01:30:11 +0000] "GET / HTTP/1.1" 200 19 "http://114.114.114.114:9421/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203" "100.125.**.**"
   ```
   其中**100.125.\*\*.\*\***为负载均衡的地址段，说明流量经过负载均衡转发。
   
   
2. 开启"获取客户端IP"功能。**仅使用共享型ELB时需操作，独享型ELB默认开启源地址透传功能，无需手动开启。**
   
   v1.23.17-r0、v1.25.12-r0、v1.27.9-r0、v1.28.7-r0、v1.29.3-r0及以上版本的集群操作步骤
   1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群。
   
   2. 在左侧导航栏中选择"插件中心"，在右侧找到**NGINX Ingress控制器**插件，单击"管理"。
   
   3. 单击已安装实例的"编辑"，在负载均衡器配置中开启"获取客户端源IP"开关。 ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001980681733.png "点击放大")
      
   
   4. 单击"确定"。
      ![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
      开启/关闭"获取客户端IP"的过程中，如果已经配置了后端服务，则访问流量会中断，请谨慎操作。
      
    
   v1.23.17-r0、v1.25.12-r0、v1.27.9-r0、v1.28.7-r0、v1.29.3-r0以下版本的集群操作步骤
   1. 在管理控制台左上角单击![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001663151254.png)图标，选择区域和项目。
   
   2. 选择"服务列表 \> 网络 \> 弹性负载均衡 ELB"。
   
   3. 在"弹性负载均衡器"界面，单击需要操作的负载均衡名称。
   
   4. 切换到"监听器"页签，单击需要修改的监听器名称右侧的"编辑"按钮。如果存在修改保护，请在监听器基本信息页面中关闭修改保护后重试。
   
   5. 开启"获取客户端IP"开关。
      图2开启开关   
      ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001662991542.png "点击放大") 
    
   
   
3. 重新访问工作负载，并查看新增的访问日志如下： 
   ```
   ...
   10.0.0.7 - - [17/Aug/2023:02:43:11 +0000] "GET / HTTP/1.1" 304 0 "http://114.114.114.114:9421/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203" "124.**.**.**"
   ```
   显示成功获取到客户端源IP。
   
   
![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
如果您需要为集群Nginx Ingress Controller所使用的ELB开启WAF功能，不同的WAF模式会影响Nginx Ingress Controller获取真实的客户端IP：
- **使用WAF云模式的CNAME接入**
  采用CNAME模式接入，会导致请求先通过WAF，经过WAF进行防护检查之后再转发给ELB。因此即使ELB已开启源地址透传，实际上客户端得到为WAF的回源IP，造成Nginx Ingress Controller将默认无法获得真实的客户端IP。此时您可以编辑NGINX Ingress控制器插件，在nginx配置参数处添加以下配置。
  ```
  {
       "enable-real-ip": "true",
       "use-forwarded-headers": "true",
       "proxy-real-ip-cidr": <您从WAF获取到的回源IP段> 
  }
  ```
  

- **使用WAF云模式ELB接入**
  该模式为透明接入（旁路部署），仅支持独享型ELB，Nginx Ingress Controller默认可以获得真实的客户端IP。
  
 
 #### 负载均衡( LoadBalancer )
负载均衡( LoadBalancer )的Service模式下，不同类型的集群获取源IP的场景不一，部分场景下暂不支持获取源IP，参见[支持获取源IP地址的场景]。
- CCE集群（VPC、容器隧道网络模型）：使用共享型和独享型ELB均支持获取源IP。
- CCE Turbo集群（云原生网络2.0模型）：使用独享型ELB时支持获取源IP；使用共享型ELB时，仅开启hostNetwork的工作负载支持获取源IP。
 
**VPC、容器隧道网络模型**
通过控制台开启获取源IP的步骤如下：
1. 在CCE控制台创建负载均衡类型的Service，服务亲和选择"**节点级别** "而不是"集群级别"。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001980610633.png "点击放大")
   
2. 前往ELB控制台，开启ELB实例对应监听器的"获取客户端IP"功能。**独享型ELB默认开启源地址透传功能，无需手动开启。**
   1. 在管理控制台左上角单击![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001221501677.png)图标，选择区域和项目。
   
   2. 选择"服务列表 \> 网络 \> 弹性负载均衡 ELB"。
   
   3. 在"弹性负载均衡器"界面，单击需要操作的负载均衡名称。
   
   4. 切换到"监听器"页签，单击需要修改的监听器名称右侧的"编辑"按钮。如果存在修改保护，请在监听器基本信息页面中关闭修改保护后重试。
   
   5. 开启"获取客户端IP"开关。
      图3开启开关   
      ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001568170057.png "点击放大") 
    
 
在v1.23.17-r0、v1.25.12-r0、v1.27.9-r0、v1.28.7-r0、v1.29.3-r0及以上版本的集群中，您也可以在通过YAML创建Service时，添加指定的annotation配置直接开启获取源IP（仅共享型ELB使用TCP/UDP协议时支持），示例如下：
```
apiVersion: v1 
kind: Service 
metadata: 
  name: nginx
  annotations:
    kubernetes.io/elb.id: <your_elb_id>              # ELB ID，替换为实际值
    kubernetes.io/elb.class: union                   # 负载均衡器类型
    kubernetes.io/elb.transparent-client-ip: 'true'  # 开启获取客户端源IP
spec:
  selector: 
     app: nginx
  externalTrafficPolicy: Local
  ports: 
  - name: service0 
    port: 80
    protocol: TCP 
    targetPort: 80
  type: LoadBalancer
```
**云原生网络2.0模型（CCE Turbo集群）**
云原生网络2.0模型集群中使用共享型ELB创建负载均衡时：
- 开启hostNetwork的工作负载：支持将服务亲和选项设置为"节点级别"，可获取源IP。
- 其他工作负载：无法将服务亲和选项设置为"节点级别"，因此无法获取源IP。
 
建议使用**独享型ELB**，外部访问可不经过转发直通容器。独享型ELB默认开启源地址透传，无需前往ELB控制台手动开启"获取客户端IP"开关，只需要在CCE控制台创建负载均衡服务时选择独享型负载均衡，即可获取客户端源IP。
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001980611305.png "点击放大")
 #### 节点访问 ( NodePort )
节点访问（NodePort）类型的Service的服务亲和需选择"**节点级别** "而不是"集群级别"，即Service的**spec.externalTrafficPolicy** 需要设置为**Local**。
![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
云原生网络2.0模型集群中使用节点访问（NodePort）类型的Service时，只有开启hostNetwork的工作负载支持设置"节点级别"的服务亲和，因此仅开启hostNetwork的工作负载支持获取源IP。
图4服务亲和选择节点级别   
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000001980492213.png "点击放大")
