Kubernetes Service 中的 external-traffic-policy 是什么?
【摘要】 external-traffic-policy,顾名思义“外部流量策略”,那这个配置有什么作用呢?以及external是指什么东西的外部呢,集群、节点、Pod?今天我们就来学习一下这个概念吧。
1、什么是external-traffic-policy
在k8s的Service对象(申明一条访问通道)中,有一个“externalTrafficPolicy”字段可以设置。有2个值可以设置:Cluster或者Local。
1)Cluster表示:流量可以转发到其他节点上的Pod。
2)Local表示:流量只发给本机的Pod。
图示一下:
2、这2种模式有什么区别
存在这2种模式的原因就是,当前节点的Kube-proxy在转发报文的时候,会不会保留原始访问者的IP。
2.1 选择Cluster
注:这个是默认模式,Kube-proxy不管容器实例在哪,公平转发。
Kube-proxy转发时会替换掉报文的源IP。即:容器收的报文,源IP地址,已经被替换为上一个转发节点的了。
原因是Kube-proxy在做转发的时候,会做一次SNAT,所以源IP变成了节点1的IP地址。SNAT确保回去的报文可以原路返回,不然回去的路径不一样,客户会认为非法报文的。(我发给张三的,怎么李四给我回应?丢弃!)
这种模式好处是负载均衡会比较好,因为无论容器实例怎么分布在多个节点上,它都会转发过去。当然,由于多了一次转发,性能会损失一丢丢。
2.2 选择Local
这种情况下,只转发给本机的容器,绝不跨节点转发。
Kube-proxy转发时会保留源IP。即:容器收到的报文,看到源IP地址还是用户的。
缺点是负载均衡可能不是很好,因为一旦容器实例分布在多个节点上,它只转发给本机,不跨节点转发流量。当然,少了一次转发,性能会相对好一丢丢。
注:这种模式下的Service类型只能为外部流量,即:LoadBalancer 或者 NodePort 两种,否则会报错。
同时,由于本机不会跨节点转发报文,所以要想所有节点上的容器有负载均衡,就需要上一级的Loadbalancer来做了。
不过流量还是会不太均衡,如上图,Loadbalancer看到的是2个后端(把节点的IP),每个Node上面几个Pod对Loadbalancer来说是不知道的。
想要解决负载不均衡的问题:可以给Pod容器设置反亲和,让这些容器平均的分布在各个节点上(不要聚在一起)。
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- my-app
topologyKey: kubernetes.io/hostname
像下面这样,负载均衡情况就会好很多~
3、示例
3.1 示例环境
当前示例Kubernetes集群节点信息如下(共五个节点,k8s版本为1.21.14):
[root@master1 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master1 Ready control-plane,master 19d v1.21.14 10.20.32.201 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
master2 Ready control-plane,master 19d v1.21.14 10.20.32.202 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
master3 Ready control-plane,master 19d v1.21.14 10.20.32.203 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
worker1 Ready worker 19d v1.21.14 10.20.32.204 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
worker2 Ready worker 19d v1.21.14 10.20.32.205 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
当前集群kube-proxy模式为ipvs:
[root@master1 ~]# kubectl get configmaps -n=kube-system kube-proxy -o yaml|grep mode
mode: ipvs
3.2 externalTrafficPolicy=Cluster(默认值)
当我们创建 Service 资源对象时,如果 type 值为 NodePort 或者 LoadBalancer,此时如果Service对象规格配置文件没有 externalTrafficPolicy 字段,则创建的 Service 对象会默认生成 externalTrafficPolicy 字段,值为 Cluster。
下面以 Service type 为 NodePort 为示例演示 externalTrafficPolicy=Cluster 的使用。
(1)创建 svc 并指定 externalTrafficPolicy=Cluster
[root@master1 ~]# kubectl get svc -n=tracing http-request-printer -o yaml
apiVersion: v1
kind: Service
metadata:
......
labels:
app: http-request-printer
version: v1
name: http-request-printer
namespace: tracing
.....
spec:
clusterIP: 10.234.131.36
clusterIPs:
- 10.234.131.36
externalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: http-80
nodePort: 32513
port: 80
protocol: TCP
targetPort: 80
selector:
app: http-request-printer
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
创建好此 svc 对象后,由于 type 是 NodePort 类型,我我们可以通过 Kubernetes 任意节点 IP 加 NodePort 端口访问此服务。
[root@master1 ~]# kubectl get svc -n=tracing
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-request-printer NodePort 10.234.131.36 <none> 80:32513/TCP 13d
查看 svc 关联 Pod 调度到哪个节点了。
[root@master1 ~]# kubectl get pods -n=tracing -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
http-request-printer-v1-7fb869f54f-8bhz4 2/2 Running 8 9d 10.233.1.6 worker1 <none> <none>
(2)通过非调度节点 ip:NodePort 访问服务
现在是用非调度节点 ip:nodePort 端口访问此服务,可以正常响应。
[root@master1 ~]# curl 10.20.32.202:32513
Hello, World!
(3)分析访问服务成功原因
下面连到 10.20.32.202 机器分析为什么访问能成功,其实是 kube-proxy 原理。
通过 ipvsadm -L -n 命令查看转发规则,可以看到客户端访问10.20.32.202:32513会做目标地址转换,直接将目标地址转换成了服务关联PodIp:Pod端口(nodePort -> podIp)。
......
TCP 10.20.32.202:32513 rr
-> 10.233.1.6:80 Masq 1 0 0
......
之后通过 K8s 网络组件(calico/flannel等)将外部客户端访问数据包转到对应节点 Pod 里。
3.3 externalTrafficPolicy=Local
当我们创建Service资源对象时,并且 svc type 值为 NodePort 或者 LoadBalancer,此时才能够为Service对象配置 externalTrafficPolicy 字段,下面以 Service type 为 NodePort 为示例演示 externalTrafficPolicy=Local 的使用,由于 Local 不是字段默认值,创建 svc 资源时必须指定 externalTrafficPolicy=Local 。
还是使用 3.2 中的示例,修改 http-request-printer 服务,将 externalTrafficPolicy=Cluster 修改为 externalTrafficPolicy=Local 。
(1)修改 svc 并指定 externalTrafficPolicy=Local
[root@master1 ~]# kubectl get svc -n=tracing http-request-printer -o yaml
apiVersion: v1
kind: Service
metadata:
......
labels:
app: http-request-printer
version: v1
name: http-request-printer
namespace: tracing
.....
spec:
clusterIP: 10.234.131.36
clusterIPs:
- 10.234.131.36
externalTrafficPolicy: Local
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: http-80
nodePort: 32513
port: 80
protocol: TCP
targetPort: 80
selector:
app: http-request-printer
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
修改好此 svc 对象后,由于 type 是 NodePort 类型,我们可以通过 Kubernetes 任意节点 IP 加 NodePort 端口访问此服务。
[root@master1 ~]# kubectl get svc -n=tracing
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-request-printer NodePort 10.234.131.36 <none> 80:32513/TCP 13d
查看 svc 关联 Pod 调度到哪个节点了。
[root@master1 ~]# kubectl get pods -n=tracing -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
http-request-printer-v1-7fb869f54f-8bhz4 2/2 Running 8 9d 10.233.1.6 worker1 <none> <none>
(2)通过非调度节点 ip:NodePort 访问服务
现在是用非调度节点 ip:nodePort 端口访问此服务,不能正常响应。
[root@master1 ~]# curl 10.20.32.202:32513
curl: (7) Failed to connect to 10.20.32.202 port 32513: Connection refused
(3)分析访问服务不成功原因
下面连到 10.20.32.202 机器分析为什么访问不成功,其实是 kube-proxy 原理。
通过 ipvsadm -L -n 命令查看转发规则,可以看到ipvs里面没有匹配到目标地址10.20.32.202:32513,数据包丢弃。
注意 1:访问 svc external-traffic-policy=Local 的服务时,一定要注意访问节点 Ip上面要有svc关联 Pod 调度。
(4)通过调度节点 ip:NodePort 访问服务
现在是用调度节点 ip:nodePort 端口访问此服务,服务正常响应。
[root@master1 ~]# curl 10.20.32.204:32513
Hello, World!
(5)分析访问服务成功原因
下面连到 10.20.32.204 机器分析为什么访问成功,通过 ipvsadm -L -n 命令查看转发规则,可以看到客户端访问10.20.32.204:32513会做目标地址转换,直接将目标地址转换成了服务关联PodIp:Pod端口(nodePort -> podIp)。
......
TCP 10.20.32.204:32513 rr
-> 10.233.1.6:80 Masq 1 0 0
......
由于 Pod 就在当前节点,之后借助当前节点虚拟网桥、veth pair 将请求数据包发送给对应 Pod 中的容器。
(6)抓包分析当svc externalTrafficPolicy=Local 时,进入容器中的包是否进行源地址转换
下面我们到容器网络命名空间中抓包来确定当svc externalTrafficPolicy=Local 时,进入容器中的包没有进行源地址转换。
进入容器网络命令空间:
[root@worker1 ~]# docker ps|grep http-request-printer
4cc538e5b2d1 25585bdfb0f7 "/usr/local/bin/pilo…" 2 days ago Up 2 days k8s_istio-proxy_http-request-printer-v1-7fb869f54f-8bhz4_tracing_88f571b7-1d20-4135-995b-037fc54e392c_4
9738a6f1dea0 6246a84777e8 "./http_request_prin…" 2 days ago Up 2 days k8s_container-rr19ea_http-request-printer-v1-7fb869f54f-8bhz4_tracing_88f571b7-1d20-4135-995b-037fc54e392c_4
e8b52192df02 10.20.32.201:80/cloudbases/pause:3.4.1 "/pause" 2 days ago Up 2 days k8s_POD_http-request-printer-v1-7fb869f54f-8bhz4_tracing_88f571b7-1d20-4135-995b-037fc54e392c_10
[root@worker1 ~]# docker inspect --format "{{.State.Pid}}" 9738a6f1dea0
308222
[root@worker1 ~]# nsenter -n -t 308222
[root@worker1 ~]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.233.1.6 netmask 255.255.255.0 broadcast 10.233.1.255
ether e6:17:93:ff:1b:e0 txqueuelen 0 (Ethernet)
RX packets 874214 bytes 525968831 (501.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 825020 bytes 867028023 (826.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 471020 bytes 1099949333 (1.0 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 471020 bytes 1099949333 (1.0 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@worker1 ~]#
抓包来确定当 svc externalTrafficPolicy=Local 时,进入容器中的包没有进行源地址转换(抓包时客户端 master2 通过 curl 10.20.32.204:32513 命令访问此服务)。
[root@worker1 ~]# tcpdump -i eth0 host 10.233.1.6 and dst port 80 -w svc_external_local.pcap
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C6 packets captured
6 packets received by filter
0 packets dropped by kernel
将抓的包下载到本地通过并使用 wireshark 软件进行分析,可以看到当 svc externalTrafficPolicy=Local 时,进入容器中的包没有进行源地址转换。
4、两种模式该怎么选
如何选择取决于你的应用程序需求和性能考虑。通常来说,大多数应用程序可以使用默认的 Cluster 模式,因为它可以提供相对平均的负载均衡。但在一些特定的场景中,比如对于具有特殊网络依赖的应用程序;对于特定部署在固定节点的应用程序(比如 Nginx Ingress Controller 通常以高可用形式部署在固定三个节点上面),Local 模式可能更适合,因为它可以减少跨节点的网络传输。
不过注意,选了这个就得考虑好怎么处理好负载均衡问题(ps:通常我们使用Pod间反亲和来达成),如果你是从外部LB接收流量的,那么使用:Local 模式 + Pod 反亲和,一般是足够的;另外,访问的时候确保当前节点调度此 Pod 了,否则访问歇菜。
————————————————
版权声明:本文主要参考CSDN博主「华为云开发者联盟」的原创文章,文章链接:【华为云技术分享】K8s中的external-traffic-policy是什么?
Kubernetes Service 中的 external-traffic-policy 是什么?的更多相关文章
- ASP.NET Core在Azure Kubernetes Service中的部署和管理
目录 ASP.NET Core在Azure Kubernetes Service中的部署和管理 目标 准备工作 注册 Azure 账户 AKS文档 进入Azure门户(控制台) 安装 Azure Cl ...
- (七)Kubernetes Service资源
Service概述 为什么要使用Service Kubernetes Pod是平凡的,由Deployment等控制器管理的Pod对象都是有生命周期的,它们会被创建,也会意外挂掉.虽然它们可以由控制器自 ...
- Docker Kubernetes Service 代理服务创建
Docker Kubernetes Service 代理服务创建 创建Service需要提前创建好pod容器.再创建Service时需要指定Pod标签,它会提供一个暴露端口默会分配容器内网访问的唯一 ...
- 浅谈 kubernetes service 那些事(上篇)
一.问题 首先,我们思考这样一个问题: 访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态.那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知? 二.k8 ...
- 【解构云原生】初识Kubernetes Service
编者按:云原生是网易杭州研究院(网易杭研)奉行的核心技术方向之一,开源容器平台Kubernetes作为云原生产业技术标准.云原生生态基石,在设计上不可避免有其复杂性,Kubernetes系列文章基于网 ...
- C# 开源一个基于 yarp 的 API 网关 Demo,支持绑定 Kubernetes Service
关于 Neting 刚开始的时候是打算使用微软官方的 Yarp 库,实现一个 API 网关,后面发现坑比较多,弄起来比较麻烦,就放弃了.目前写完了查看 Kubernetes Service 信息.创建 ...
- Docker Kubernetes Service 网络服务代理模式详解
Docker Kubernetes Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...
- CoreDNS for kubernetes Service Discovery
一.CoreDNS简介 Kubernetes包括用于服务发现的DNS服务器Kube-DNS. 该DNS服务器利用SkyDNS的库来为Kubernetes pod和服务提供DNS请求.SkyDNS2的作 ...
- 浅谈 kubernetes service 那些事 (下篇)
欢迎访问网易云社区,了解更多网易技术产品运营经验. 五.K8s 1.8 新特性--ipvs ipvs与iptables的性能差异 随着服务的数量增长,IPTables 规则则会成倍增长,这样带来的问题 ...
- Docker系列(十三):Kubernetes Service的负载均衡和网络路由的秘密
Kubernetes Service设计分析 什么是单体程序?所有的模块都在一个进程中 微服务,每一个服务是一个进程的模式 kubernetes中的service其实只是一个概念,是一组相同lable ...
随机推荐
- 其它——paramiko模块的使用
文章目录 paramiko 一 介绍 二 通过用户名密码方式远程执行命令 三 通过用户名密码方式上传下载文件 四 通过公钥私钥远程执行命令 五 通过公钥私钥远程上传下载文件 六 通过私钥字符串远程连接 ...
- 程序员必备:使用AI工具通义千问,没有广告没有假链接,比搜索引擎要便捷多了,回答还算满意
我提的问题是:使用Python连接Oracle,cx_Oracle和oracledb那个效率更高,功能更全,请列出他们的区别和实例代码 回复是: 以下是使用Python连接Oracle时,cx_Ora ...
- 调节LED的亮度
虽然Devices Plus已经介绍过Arduino的多种应用和作品示例,但是了解相关基础知识对于任何项目的构建仍然是非常重要的!这次,我们将为您介绍Arduino电子制作的基础知识.此次的分享嘉宾是 ...
- 数字时代的自我呈现:探索个人形象打造的创新工具——FaceChain深度学习模型工具
数字时代的自我呈现:探索个人形象打造的创新工具--FaceChain深度学习模型工具 1.介绍 FaceChain是一个可以用来打造个人数字形象的深度学习模型工具.用户仅需要提供最低一张照片即可获得独 ...
- Substring of Sorted String 题解
Substring of Sorted String 写篇题解纪念一下蒟蒻第一次赛时切出的 F 题. 题目简述 对一个字符串进行单点修改,区间判断操作. 修改操作为将一个字符修改为另一个,判断操作为判 ...
- go mod tidy总是安装最新依赖,如何查找哪个模块导致某个包安装最新依赖,提供一个小工具
安装: go install github.com/jan-bar/interesting/findModVer@latest 执行:findModVer d:\myproject 结果如下图所示: ...
- 使用ClosedXml查询Excel文件数据,匹配时间并显示
使用Nuget包管理器安装ClosedXml包,VS没网在https://www.nuget.org/ 下载后,包源本地安装至项目 函数: private void SelectGrab(Cancel ...
- 节能减排 | AIRIOT智慧工厂节能管理解决方案
工厂作为高能耗的生产型企业,降低能耗和提升资源利用率方面就显得很重要,对实施国家倡导的节能降耗.绿色发展有着很大程度上的必要性.然而,工厂能源管理从传统手段向智能化升级转型的过程中,企业也不可避免的面 ...
- 如何通过C++ 给PDF文档添加文字水印
因PDF文档具有较好的稳定性和兼容性,现在越来越多的合同.研究论文.报告等都采用PDF格式.为了进一步保护这些重要文档内容免受未经授权的复制或使用,我们可以添加水印以表明其状态.所有权或用途.针对工作 ...
- 【Javaweb】implements Serializable是什么意思?反序列化是什么意思?
为了保证数据传输的可靠 性,常常要implements Serializable,为什么? 对象本质上是虚无缥缈的,只是内存中的一个地址,如果想要让对象持久化,让对象在网络上传输,总不可能传送一个内存 ...