在Kubernetes 的 Service 对 externalTrafficPolicy 设置,以及和获取客户端IP相关知识点

栏目: 编程工具 · 发布时间: 4年前

内容简介:[TOC]本文主要内容翻译自:您必须具有可用的

目录

[TOC]

1、先决条件
2、具有 Type = ClusterIP 服务的客户端IP
3、通过 Type=NodePort 获取客户端IP
4、通过 Type = LoadBalancer 获取客户端IP
5、删除服务
6、参考文章

本文主要内容翻译自: source-ip

1、先决条件

  您必须具有可用的 Kubernetes 1.5 集群才能运行本文档中的示例。这些示例使用一个小的 Nginx Web 服务器,它会显示通过HTTP头接收的请求的一切信息,包括客户端IP。您可以按如下方式创建它:

$ kubectl create deployment source-ip-app --image=idoall/echoserver:1.10
deployment.apps/source-ip-app created

  

2、具有 Type = ClusterIP 服务的客户端IP

  如果您在 iptables 模式下运行 kube-proxy ,则从群集内发送到 ClusterIP 的数据包永远不会来自 DNAT ,这是 Kubernetes 1.2 以来的默认设置。 Kube-proxy 通过访问proxyMode endpoint 可以查看公开模式:

$ curl localhost:10249/proxyMode
iptables

    接下来我们创建一个服务来测试客户端IP:

$ kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
service/clusterip exposed

$ kubectl get svc clusterip
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
clusterip   ClusterIP   10.245.180.210   <none>        80/TCP    8s

刚才我们只是部署了一个名为 source-ip-app 的Pod ,通过 kubectl expose 将资源暴露为新的 Kubernetes Service ,名称为 clusterip

    接下来创建一个 pod 尝试获取 clusterip 测试

$  kubectl run busybox -it --image=busybox --restart=Never --rm
If you don't see a command prompt, try pressing enter.
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: eth0@if31: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
    link/ether 5e:69:18:64:dd:94 brd ff:ff:ff:ff:ff:ff
    inet 10.244.5.27/24 scope global eth0
       valid_lft forever preferred_lft forever

/ # wget -qO - 10.245.180.210


Hostname: source-ip-app

Pod Information:
    -no pod information available-

Server values:
    server_version=nginx: 1.13.3 - lua: 10008

Request Information:
    client_address=10.244.5.27
    method=GET
    real path=/
    query=
    request_version=1.1
    request_scheme=http
    request_uri=http://10.245.180.210:8080/

Request Headers:
    connection=close
    host=10.245.180.210
    user-agent=Wget

Request Body:
    -no body in request-

/ #

  无论何种访问方式,可以发现获取到的 client_address 地址,永远都是客户端所在容器的IP 10.244.5.27 。  

3、通过 Type=NodePort 获取客户端IP

  从 Kubernetes 1.5 开始, 默认情况下,发送到 Type = NodePort 的服务数据包是来自 DNAT 。接下来我们再创建一个类型是 NodePort 的服务,来对应刚才创建的部署 source-ip-app

$ kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
service/nodeport exposed

  

$ NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
$ NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address}')
$ for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done
    client_address=10.244.3.0
    client_address=10.244.4.0
    client_address=10.244.5.1
    client_address=10.244.0.0
    client_address=10.244.1.0
    client_address=10.244.2.0

通过上面的方法能够看到,我们从不同节点去访问 NodePort ,得到的也并不是真正的客户端IP,而是集群IP

  

  处理流程如下:

* 客户端发送数据包 node2:nodePort

* node2 用自己的IP地址替换数据包中的源IP地址(SNAT)

* node2 使用 pod IP 替换数据包上的目标 IP

* 数据包路由到 node1 ,然后路由到 endpoint
* pod的回复被路由回 node2

* pod的回复被发送回客户端

client
             \ ^
              \ \
               v \
   node 1 <--- node 2
    | ^   SNAT
    | |   --->
    v |
 endpoint
  

  为避免这种情况, Kubernetes 具有保留客户端IP 的功能。设置 service.spec.externalTrafficPolicyLocal 会将请求代理到本地端点,不将流量转发到其他节点,从而保留原始IP地址。如果没有本地端点,则丢弃发送到节点的数据包,因此您可以在任何数据包处理规则中依赖正确的客户端IP。

  设置 service.spec.externalTrafficPolicy 字段如下:

$ kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'
service/nodeport patched

    现在,重新运行测试:

for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done
    client_address=10.0.0.100
    client_address=10.0.0.100
  

  这时获取到的正确IP地址,只能是在当前节点的IP地址。

  处理流程如下:

* 客户端发送数据包 node2:nodePort ,没有任何 endpoint

* 数据包被丢

* 客户端发送数据包 node1:nodePort ,存在 endpoint

* node1 使用正确的源IP将数据包路由到 endpoint

client
       ^ /   \
      / /     \
     / v       X
   node 1     node 2
    ^ |
    | |
    | v
 endpoint

  

4、通过 Type = LoadBalancer 获取客户端IP

  从 Kubernetes 1.5 开始,默认情况下,发送到具有 Type = LoadBalancer 的服务的数据包来源是 DNAT,因为该 Ready 状态中的所有可调度 Kubernetes 节点都能获得负载平衡流量。因此,如果数据包到达没有 endpointNode ,系统会将其代理到具有 endpointNode ,用这个 Node 的IP替换数据包上的源IP(如上一节所述)。

  您可以通过负载均衡器公开 source-ip-app 来测试这一点

$ kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer
service/loadbalancer exposed

$ kubectl get svc loadbalancer
NAME           TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
loadbalancer   LoadBalancer   10.245.176.219   192.168.11.221   80:30821/TCP   57s

$ curl -s 192.168.11.221 | grep -i client_address
    client_address=10.244.0.0

通过上面的实例可以看到,获取到的 client_address 还是集群内的IP。

    通过设置相同的 service.spec.externalTrafficPolicy 字段以 Local 强制没有服务端点的节点通过故意失败的运行状况检查将自己从符合加载平衡流量的节点列表中删除。

client
                        |
                      lb VIP
                     / ^
                    v /
health check --->   node 1   node 2 <--- health check
        200  <---   ^ |             ---> 500
                    | V
                 endpoint

    您可以通过下面的代码来测试:

$ kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}'
service/loadbalancer patched

    你应该立即看到 service.spec.healthCheckNodePortKubernetes 分配的字段

$ kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort
  healthCheckNodePort: 32131

    该 service.spec.healthCheckNodePort 字段指向服务于运行状况检查的每个节点上的端口 /healthz 。可以通过以下字段测试:

$ kubectl get pod -o wide -l run=source-ip-app
NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE                  NOMINATED NODE   READINESS GATES
source-ip-app                   1/1     Running   0          47m   10.244.4.179   k8s-dev-datanode-02   <none>           <none>
source-ip-app-784589f58-rk95c   1/1     Running   0          47m   10.244.5.26    k8s-dev-datanode-03   <none>           <none>

[root@k8s-dev-datanode-01 ~]# curl localhost:32131
{
    "service": {
        "namespace": "default",
        "name": "loadbalancer"
    },
    "localEndpoints": 0

[root@k8s-dev-datanode-02 ~]# curl localhost:32131
{
    "service": {
        "namespace": "default",
        "name": "loadbalancer"
    },
    "localEndpoints": 1

    在 master 服务器上会进行负载均衡分配 ,当执行此操作时,它会分配指向每个节点上的端口/路径的HTTP运行状况检查。对于没有端点的2个节点等待大约10秒钟的健康检查失败,然后会指向正确的IP地址:

$ curl -s 192.168.11.221 | grep -i client_address
    client_address=192.168.11.175

只有在所在节点 datanode-02 上运行,才可以访问

  

5、删除服务

$ kubectl delete svc -l app=source-ip-app

删除标签是 app: source-ip-app 的服务

    删除 DeploymentReplicaSetPod

$ kubectl delete deployment source-ip-app

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go语言学习笔记

Go语言学习笔记

雨痕 / 电子工业出版社 / 2016-6 / 89

作为时下流行的一种系统编程语言,Go 简单易学,性能很好,且支持各类主流平台。已有大量项目采用 Go 编写,这其中就包括 Docker 等明星作品,其开发和执行效率早已被证明。本书经四年多逐步完善,内容覆盖了语言、运行时、性能优化、工具链等各层面知识。且内容经大量读者反馈和校对,没有明显的缺陷和错误。上卷细致解析了语言规范相关细节,便于读者深入理解语言相关功能的使用方法和注意事项。下卷则对运行时源......一起来看看 《Go语言学习笔记》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换