准备工作

你必须拥有一个正常工作的 Kubernetes 1.5 集群,用来运行本文中的示例。该示例使用一个简单的 nginx webserver 回送它接收到的请求的 HTTP 头中的源 IP 地址。你可以像下面这样创建它:

$ kubectl run ``source``-ip-app --image=k8s.gcr.io``/echoserver``:1.4``deployment ``"source-ip-app"` `created

Type=ClusterIP 类型 Services 的 Source IP

如果你的 kube-proxy 运行在 iptables 模式下,从集群内部发送到 ClusterIP 的包永远不会进行源地址 NAT,这从 Kubernetes 1.2 开始是默认选项。Kube-proxy 通过一个 proxyMode endpoint 暴露它的模式。

$ kubectl get nodes``NAME                           STATUS     AGE     VERSION``kubernetes-minion-group-6jst   Ready      2h      v1.6.0+fff5156``kubernetes-minion-group-cx31   Ready      2h      v1.6.0+fff5156``kubernetes-minion-group-jj1t   Ready      2h      v1.6.0+fff5156``kubernetes-minion-group-6jst $ curl localhost:10249``/proxyMode``iptables

你可以通过在 source IP 应用上创建一个服务来测试源 IP 保留。

$ kubectl expose deployment ``source``-ip-app --name=clusterip --port=80 --target-port=8080``service ``"clusterip"` `exposed
$ kubectl get svc clusterip``NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE``clusterip 10.0.170.92 <none> 80``/TCP` `51s

从相同集群中的一个 pod 访问这个 ClusterIP:

$ kubectl run busybox -it --image=busybox --restart=Never --``rm``Waiting ``for` `pod default``/busybox` `to be running, status is Pending, pod ready: ``false``If you don't see a ``command` `prompt, try pressing enter.``# ip addr``1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue``    ``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``    ``inet6 ::1``/128` `scope host``       ``valid_lft forever preferred_lft forever``3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue``    ``link``/ether` `0a:58:0a:f4:03:08 brd ff:ff:ff:ff:ff:ff``    ``inet 10.244.3.8``/24` `scope global eth0``       ``valid_lft forever preferred_lft forever``    ``inet6 fe80::188a:84ff:feb0:26a5``/64` `scope link``       ``valid_lft forever preferred_lft forever
# wget -qO - 10.0.170.92``CLIENT VALUES:``client_address=10.244.3.8``command``=GET``...

如果客户端 pod 和 服务端 pod 在相同的节点上,client_address 就是客户端 pod 的 IP 地址。但是,如果它们在不同的节点上, client_address 将会是客户端 pod 所在节点的 flannel IP 地址。

Type=NodePort 类型 Services 的 Source IP

​ 对于 Kubernetes 1.5,发送给类型为 Type=NodePort Services 的数据包默认进行源地址 NAT。你可以创建一个 NodePort Service 来进行测试:

$ 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=="ExternalIP")].address }'``)

如果你的集群运行在一个云服务上,你可能需要为上面报告的 nodes:nodeport 开启一条防火墙规则。 现在,你可以通过上面分配的节点端口从外部访问这个 Service。

$ ``for` `node ``in` `$NODES; ``do` `curl -s $node:$NODEPORT | ``grep` `-i client_address; ``done``client_address=10.180.1.1``client_address=10.240.0.5``client_address=10.240.0.3

请注意,这些并不是正确的客户端 IP,它们是集群的内部 IP。这是所发生的事情:

1、客户端发送数据包到 node2:nodePort

2、node2 使用它自己的 IP 地址替换数据包的源 IP 地址(SNAT)

3、node2 使用 pod IP 地址替换数据包的目的 IP 地址

4、数据包被路由到 node 1,然后交给 endpoint

5、Pod 的回复被路由回 node2

6、Pod 的回复被发送回给客户端

形象的:

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

设置 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=104.132.1.79

请注意,你只从 endpoint pod 运行的那个节点得到了一个回复,这个回复有正确的客户端 IP。

这是发生的事情:

1、客户端发送数据包到 node2:nodePort,它没有任何 endpoints

2、数据包被丢弃

3、客户端发送数据包到 node1:nodePort,它endpoints

4、node1 使用正确的源 IP 地址将数据包路由到 endpoint

形象的:

Type=LoadBalancer 类型 Services 的 Source IP

​ 对于 Kubernetes 1.5,发送给类型为 Type=LoadBalancer Services 的数据包默认进行源地址 NAT,这是由于所有处于 Ready 状态的 Kubernetes 节点对于负载均衡的流量都是符合条件的。所以如果数据包到达一个没有 endpoint 的节点,系统将把这个包代理到有 endpoint 的节点,并替换数据包的源 IP 为节点的 IP(如前面章节所述)。

​ 你可以通过在一个 loadbalancer 上暴露这个 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           CLUSTER-IP    EXTERNAL-IP       PORT(S)   AGE``loadbalancer   10.0.65.118   104.198.149.140   80``/TCP`    `5m``$ curl 104.198.149.140``CLIENT VALUES:``client_address=10.240.0.5``...

​ 然而,如果你的集群运行在 Google Kubernetes Engine/GCE 上,设置 service.spec.externalTrafficPolicy 字段值为 Local 可以强制使没有 endpoints 的节点把他们自己从负载均衡流量的可选节点名单中删除。这是通过故意使它们健康检查失败达到的。

形象的:

你可以设置 annotation 来进行测试:

$ kubectl patch svc loadbalancer -p ``'{"spec":{"externalTrafficPolicy":"Local"}}'

你应该能够立即看到 Kubernetes 分配的 service.spec.healthCheckNodePort 字段:

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

service.spec.healthCheckNodePort 字段指向每个节点在 /healthz 路径上提供的用于健康检查的端口。你可以这样测试:

$ kubectl get pod -o wide -l run=``source``-ip-app``NAME                            READY     STATUS    RESTARTS   AGE       IP             NODE``source``-ip-app-826191075-qehz4   1``/1`       `Running   0          20h       10.180.1.136   kubernetes-minion-group-6jst``kubernetes-minion-group-6jst $ curl localhost:32122``/healthz``1 Service Endpoints found``kubernetes-minion-group-jj1t $ curl localhost:32122``/healthz``No Service Endpoints Found

​ 主节点运行的 service 控制器负责分配 cloud loadbalancer。在这样做的同时,它也会分配指向每个节点的 HTTP 健康检查的 port/path。等待大约 10 秒钟之后,没有 endpoints 的两个节点的健康检查会失败,然后 curl 负载均衡器的 ip:

$ curl 104.198.149.140``CLIENT VALUES:``client_address=104.132.1.79``...

跨平台支持

​ 由于 Kubernetes 1.5 在类型为 Type=LoadBalancer 的 Services 中支持源 IP 保存的特性仅在 cloudproviders 的子集中实现(GCP and Azure)。你的集群运行的 cloudprovider 可能以某些不同的方式满足 loadbalancer 的要求:

1、使用一个代理终止客户端连接并打开一个到你的 nodes/endpoints 的新连接。在这种情况下,源 IP 地址将永远是云负载均衡器的地址而不是客户端的。

2、使用一个包转发器,因此从客户端发送到负载均衡器 VIP 的请求在拥有客户端源 IP 地址的节点终止,而不被中间代理。

​ 第一类负载均衡器必须使用一种它和后端之间约定的协议来和真实的客户端 IP 通信,例如 HTTP X-FORWARDED-FOR 头,或者 proxy 协议。 第二类负载均衡器可以通过简单的在保存于 Service 的 service.spec.healthCheckNodePort 字段上创建一个 HTTP 健康检查点来使用上面描述的特性。

原文地址:

http://www.damonyi.cc/kubernetes中的source-ip机制/

【转】干货,Kubernetes中的Source Ip机制。的更多相关文章

  1. kubernetes 中的证书工作机制

    一文带你彻底厘清 Kubernetes 中的证书工作机制 搬砖者: 张首富 时 间: 2020-05-26 w x: y18163201 原文地址:https://zhaohuabing.com/po ...

  2. Kubernetes中的垃圾回收机制

    本文所讨论垃圾回收(GC,Garbage Collection)机制针对Kubernetes1.1.7,docker容器. 一.Tips 01. Kubernetes的垃圾回收由kubelet进行管理 ...

  3. 深入解析kubernetes中的选举机制

    Overview 在 Kubernetes的 kube-controller-manager , kube-scheduler, 以及使用 Operator 的底层实现 controller-rumt ...

  4. 关于 Kubernetes 中的 Volume 与 GlusterFS 分布式存储

    容器中持久化的文件生命周期是短暂的,如果容器中程序崩溃宕机,kubelet 就会重新启动,容器中的文件将会丢失,所以对于有状态的应用容器中持久化存储是至关重要的一个环节:另外很多时候一个 Pod 中可 ...

  5. Prometheus在Kubernetes下的服务发现机制

    Prometheus作为容器监控领域的事实标准,随着以Kubernetes为核心的云原生热潮的兴起,已经得到了广泛的应用部署.灵活的服务发现机制是Prometheus和Kubernetes两者得以连接 ...

  6. 探索 OpenStack 之(17):计量模块 Ceilometer 中的数据收集机制

    本文将阐述 Ceilometer 中的数据收集机制.Ceilometer 使用三种机制来收集数据: Notifications:Ceilometer 接收 OpenStack 其它服务发出的 noti ...

  7. Kubernetes 中的核心组件与基本对象概述

    Kubernetes 是 Google 基于 Borg 开源的容器编排调度,用于管理容器集群自动化部署.扩容以及运维的开源平台.作为云原生计算基金会 CNCF(Cloud Native Computi ...

  8. Kubernetes中的网络

    一.引子 既然Kubernetes中将容器的联网通过插件的方式来实现,那么该如何解决这个的联网问题呢? 如果你在本地单台机器上运行docker容器的话注意到所有容器都会处在docker0网桥自动分配的 ...

  9. [转帖]Kubernetes中安装Helm及使用

    Kubernetes中安装Helm及使用 2018年07月02日 17:41:09 灬勿忘丶心安 阅读数 3699更多 分类专栏: K8S   版权声明:本文为博主原创文章,遵循CC 4.0 BY-S ...

随机推荐

  1. Django之代码风格

    1 代码风格 稍微关注一下下面这些代码标准风格指导规则将会对你大有益处,我们高度建议你通读词章,即便你此时可能正想跳过它. 1.1 让你的代码保持可读性的重要性 代码在读方面的重要性胜过写.一个代码块 ...

  2. Ocelot中文文档-委托处理程序

    Ocelot允许用户将委托处理程序添加到HttpClient传输中. 这个功能在github #208中提出,我确定它会以各种方式被使用.之后我们在GitHub#264中进行了扩展. 用法 为了将委托 ...

  3. MySQL快速生成本地测试数据

    利用数据的存储过程生成测试数据: 我们可以通过数据库的的 INSERT 语句直接在存储过程中向普通数据表中添加数据,但是 当我们添加到百万数据后,往普通表插入测试数据的性能就会明显降低.所以在这里建议 ...

  4. 从 <sofa:XXX> 标签开始看 SOFA-Boot 如何融入 Spring

    前言 SOFA-Boot 现阶段支持 XML 的方式在 Spring 中定义 Bean,通过这些标签,我们就能从 Spring 容器中取出 RPC 中的引用,并进行调用,那么他是如何处理这些自定义标签 ...

  5. 妙用this关键字

    妙用this关键字 ## this关键字一般this关键字都是指的是对象的本身,在类的所有方法.构造器都可以拿到this引用,这是jvm"偷偷"帮我们传递进来的引用,指向调用方法对 ...

  6. mac下安装Python3.*(最新版本)

    前言:mac系统自带python,不过以当前mac系统的最新版本为例,自带的python版本都是2.*版本,虽然不影响老版本项目的运行,但是python最新的3.*版本的一些语法与2.*版本并不相同, ...

  7. nginx+php+mysql+wordpress搭建简单站点 安装及配置过程

    环境 阿里云ECS云服务器 CPU:1核 内存:2G 操作系统:Centos 7.3 x64 地域:华北 2(华北 2 可用区 A) 系统盘:40G 安装及配置 主要使用 nginx . php 和 ...

  8. (十分钟视频教程)nodejs基础实战教程3:react服务端渲染入门篇

    视频截图如下: (具体视频见文末) 前言: 这是小猫的第三篇node教程,本篇内容是由公众号粉丝票选得出的,相信大家对这篇教程是抱有较大希望的,这篇教程由小猫和一位多年的好朋友合作完成(笔名:谷雨,博 ...

  9. 快速失败(fail-fast)和安全失败(fail-safe)的区别

    1.fail-fast和fail-safe比较 Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响.java.util包下面的所有的集合类都是快速失败的,而java.ut ...

  10. java中判断文件及所在文件夹是否存在

    File file=new File(filePath);if (file.exists()) {}else { File fileParent =new File(file.getParent()) ...