首页 > 其他分享 >Kubernetes Service中的 external-traffic-policy 是什么?

Kubernetes Service中的 external-traffic-policy 是什么?

时间:2023-08-17 19:46:18浏览次数:49  
标签:10.20 http Kubernetes Service svc externalTrafficPolicy traffic Local 节点

【摘要】 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是什么?

标签:10.20,http,Kubernetes,Service,svc,externalTrafficPolicy,traffic,Local,节点
From: https://www.cnblogs.com/zhangmingcheng/p/17637712.html

相关文章

  • [kubernetes]二进制部署k8s集群-基于containerd
    0.前言k8s从1.24版本开始不再直接支持docker,但可以自行调整相关配置,实现1.24版本后的k8s还能调用docker。其实docker自身也是调用containerd,与其k8s通过docker再调用containerd,不如k8s直接调用containerd,以减少性能损耗。除了containerd,比较流行的容器运行时还有podman,但是podm......
  • k8s Service(一) ClusterIP、NodePort、LoadBalancer、externalIPs 演示
    目录:Service简介kube-proxy3种不同的数据调度模式Service资源的定义格式示例1:ClusterIP演示示例2:NodePort演示示例3:LoadBalancer演示示例4:externalIPs演示Service简介Service:可以理解为pod的负债均衡器,标准资源类型,ServiceController为动态的一组Pod提......
  • 通过 TCPView 还发现个流氓 KPKIService.exe 删掉
    叫统一安全中间件,就是个第三方做的key的安全检查,谁知道是哪年装的资料https://baijiahao.baidu.com/s?id=1717384219148345375&wfr=spider&for=pc......
  • 基于Kubernetes云原生技术的低代码PaaS平台,快速构建企业级应用程序
    低代码开发平台只需要编写简单的配置文件即可构建企业级应用程序。低代码PaaS平台可以在云端开发、部署、运行低代码应用程序。使用独立数据库模型,基于Kubernetes云原生技术,每个租户均可拥有一套独立的存储、数据库、代码和命名空间,实现了100%的租户数据隔离,并可以随时迁移到私有部......
  • Kubernetes守护进程集 DaemonSet
    守护进程集DaemonSet守护进程集也有副本数概念,但是副本数概念并不是通过配置清单的方式人为去定义的,他是靠你当前集群的节点个数,比如我当前集群之前安装集群安装的网络插件calico[root@k8s-master1deployment]#kubectlgetpods-nkube-systemNAME......
  • 快速迁移自建Kubernetes资源上云及EKS资源备份恢复–基础篇
    越来越多公司进行应用现代化,微服务化改造,容器化部署,而这一切皆绕不开“容器调度管理平台”Kubernetes。那么如何快速将云下自建Kubernetes迁移上云,及上云后如果按需备份恢复,及在必要时可以快速克隆生产环境进行开发测试成为众多客户的需求点,本文将通过简单场景示例来介绍如何通过......
  • [Microsoft Azure] 快速上手创建Azure App Service服务
    本文将带您快速了解如何使用MicrosoftAzure创建AzureAppService服务,让您在短时间内掌握这一流行的云计算平台。 MicrosoftAzure是一个功能强大的云计算平台,提供了广泛的云服务,包括虚拟机、数据库、存储等。在本篇博客中,我们将重点介绍AzureAppService服务的创建过程。A......
  • 【Azure Service Fabric】关于Service Fabric的相关问题
    问题一:ServiceFabric是否支持PrivateLink?在AzurePrivateEndpoint文档中,罗列出了Azure上支持PrivateLink的服务。ServiceFabric不在其中。AzurePrivateLinkavailability:https://learn.microsoft.com/en-us/azure/private-link/availability 问题二:是否可以Disable......
  • 【Azure Service Fabric】关于Service Fabric的相关问题
    问题一:ServiceFabric是否支持PrivateLink?在AzurePrivateEndpoint文档中,罗列出了Azure上支持PrivateLink的服务。ServiceFabric不在其中。AzurePrivateLinkavailability:https://learn.microsoft.com/en-us/azure/private-link/availability 问题二:是否可以Dis......
  • [Microsoft Azure] 配置Azure App Service仅虚拟内网访问
    本文将介绍如何配置AzureAppService以仅允许虚拟内网访问,从而提高安全性和隐私性。我们将讨论配置过程的不同步骤以及注意事项,以便您可以轻松实现更安全的应用部署。 随着云计算的普及,越来越多的企业和开发者开始将其应用部署到云平台上。在这种情况下,如何确保应用安全性和......