Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >k8s_service网络原理

k8s_service网络原理

作者头像
leobhao
发布于 2024-08-02 03:10:00
发布于 2024-08-02 03:10:00
1860
举报
文章被收录于专栏:涓流涓流

k8s 中网络访问方式

如上图, K8s 目前有四种网络访问方式:

  1. 同一个 Node 内 Pod 访问
  2. 跨 Node 间 Pod 访问
  3. Pod 访问集群外服务
  4. 集群外访问集群内 Pod
网络空间的隔离

network namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。对于每个 network namespace 来说,它会有自己独立的网卡、路由表、arp表、iptables 等和网络相关的资源。相关的主要命令如下:

123

ip netns add net1ip netns showip netns exec net1 ip addr

不同网络空间的通信

为了实现不同 network namespace 之间的网络通信,linux提供了 veth pair,可以将 veth pair 当做一对虚拟网卡,这对虚拟网卡连通着不同的网命名络空间(Docker 与宿主机之间也是这种模式)

如下, 创建两个网络空间, 通过 veth pair 联通:

12345678910111213141516171819202122

// 创建2个网络命名空间sudo ip netns add net1sudo ip netns add net2// 创建veth pairsudo ip link add name veth1 type veth peer name veth2// 将veth pair的2个虚拟接口挪到新创建的2个网络命名空间中sudo ip link set veth1 netns net1sudo ip link set veth2 netns net2// 启动虚拟接口,并给veth pair配置ip地址,注意这里2个虚拟接口的ip必须是同网段的sudo ip netns exec net1 ip link set veth1 upsudo ip netns exec net2 ip link set veth2 upsudo ip netns exec net1 ip addr add 20.1.1.1/24 dev veth1sudo ip netns exec net2 ip addr add 20.1.1.2/24 dev veth2// veth pair接口配置的网络测试结果sudo ip netns exec net1 ping -c 3 20.1.1.2PING 20.1.1.2 (20.1.1.2) 56(84) bytes of data.64 bytes from 20.1.1.2: icmp_seq=1 ttl=64 time=0.033 ms64 bytes from 20.1.1.2: icmp_seq=2 ttl=64 time=0.028 ms

多个网络空间的通信

不同 namespace之间,两两之间直接通过veth pair相连,这种方式的缺点就是:当namespace很多时,veth pair数量呈指数增长。

通过linux bridge,相当于用一个交换机中转两个 namespace 的流量。这种方式就可以将veth pair的数量控制在n,n为网络命名空间的数量, 如:

容器(Pod)通信

同 Node 上通信

在同一个Node上: 虚拟网桥与各个Pod间建立veth pair。各个Pod的IP是由虚拟网桥分配的,这些Pod都连在同一个网桥上,在同一个网段内,它们可以进行IP寻址和互通。

整体流程如下:

  1. Node 会在 Docker/containerd 启动后, 创建默认的网桥 cbr0(custom bridge), 以连接当前 Node 上管理的所有容器
  2. Pod 创建后,会在 Pod Sandbox 初始化基础网络时,调用 CNI bridge 插件创建 veth-pair(两张虚拟网卡),一张默认命名 eth0 (如果 hostNetwork = false,则后续调用 CNI ipam 插件分配 IP)。另一张放在 Host 的 Root Network Namespace 内,然后连接到 cbr0。当 Pod 在同一个 Node 内通信访问的时候,直接通过 cbr0 即可完成网桥转发通信。
跨 Node 通信

跨 Node 的 Pod 通信, 流程如下:

  1. 跨 Node 间访问,Pod 访问流量通过 veth-pair 打到 cbr0
  2. 流量通过经过 cbr0 到宿主机的 eth0
  3. 通过 Node 之间的路由表 Route Table 进行转发, 到达目的 Node2 eth0
  4. Node2 eth0 转到 cbr0 再通过 veth-pair 到 Pod

Service 网络类型

Service 共有四种网络类型, 用来应对内外的网络访问:

  • ClusterIP(默认): k8s 集群可访问
  • NodePort: k8s 上所有 Node 可访问
  • LoadBalancer: k8s 外部访问的 vip
  • ExternalName: k8s 内部访问外部服务
ClusterIP

ClusterIP 表示在 K8s 集群内部通过 service.spec.clusterIP 进行访问,之后经过 kube-proxy 负载均衡到目标 Pod

当没有指定 service.type 的时候, 默认的 service 类型就是 ClusterIP

NodePort

当业务需要从 K8s 集群外访问内部服务时,通过 NodePort 方式可以先将访问流量转发到对应的 Node IP,然后再通过 service.spec.ports[].nodePort 端口,通过 kube-proxy 负载均衡到目标 Pod:

12345678910111213

apiVersion: v1kind: Servicemetadata: name: nodeport-servicespec: selector: app: nginx ports: - nodePort: 30800 port: 8080 protocol: TCP targetPort: 80 type: NodePort

上述 yaml 中各个 port 的区别:

  • nodePort:NodePort/LoadBalancer 类型的 Service 在 Node 节点上动态(默认)或指定创建的端口,负责将节点上的流量转发到容器
  • port:Service 自身关联的端口,通过 Service 的 ClusterIP:port 进行集群内的流量转发。
  • targetPort:目标 Pod 暴露的端口,承载 Service 转发过来的流量;未指定时与 port 相同。

NodePort 本质上是靠 kube-proxy 监听集群每个节点上的静态端口(一般是 30000-32767), 然后将流量根据 service 的配置转发到对应 pod, 这种模式比较简单提供了集群外访问 pod 的能力

LoadBalancer

上面介绍的 NodePort 模式能够暴露集群外访问的能力, 不过有如下缺点:

  1. 无法高可用, 如果对外暴露的 Node IP 所在的 Node down 了就无法提供服务了
  2. 无法负载均衡,需要用户手动在 NodePort 之上配置负载均衡转发
  3. 端口限制: NodePort的端口范围是固定的(30000-32767),可能不足以支持大量的服务

LoadBalancer 模式可以解决以上问题, 创建了 LoadBalancer 的 Service 后, 会调用云厂商的能力创建一个 LB 与之关联。 相当于复用了云厂商 LB 的负载均衡能力:

12345678910111213141516171819

apiVersion: v1kind: Servicemetadata: name: my-servicespec: selector: app.kubernetes.io/name: MyApp ports: - protocol: TCP nodePort: 30931 port: 80 targetPort: 9376 clusterIP: 10.0.171.239 type: LoadBalancerstatus: loadBalancer: -- 这里用的是 ingress 的实现 ingress: - ip: 10.1.163.12

ExternalName

当业务需要从 K8s 内部访问外部服务的时候,可以通过 ExternalName 的方式实现:

12345678

apiVersion: v1kind: Servicemetadata: name: my-service namespace: prodspec: type: ExternalName externalName: api.example.com

service.spec.externalName 字段值会被解析为 DNS 对应的 CNAME 记录,之后就可以访问到外部对应的服务了

DNS 机制: CoreDNS

在 K8s 中访问 Service 一般通过域名方式如 svc.namespace.svc.cluster.local,从域名结构可以看出对应 Service 的 namespace + name,通过这样的域名方式可以大大简化集群内部 Service-Pod 之间的访问配置,并且域名屏蔽了后端 Pod IP 的变更。

该能力最早是由 kube-dns 组件实现的, 在 1.12 版本以后就由 coreDNS 方案来实现

CoreDNS 通过以 Pod 独立部署在集群中, 当 Kubernetes 集群中的应用程序或服务需要解析另一个服务或资源的名称时,它们会发送 DNS 查询请求到 CoreDNS, CoreDNS使用配置文件(如Corefile)来定义DNS解析规则和插件。这些规则指定了如何处理不同类型的DNS查询请求。 CoreDNS与Kubernetes API服务器集成,可以从Kubernetes API获取服务、端点和其他资源的信息

CoreDNS 机制原理:

  1. 服务发现:CoreDNS通过监听 Kubernetes API服务器的变化,实时获取集群中服务的信息。当服务发生变化时,CoreDNS会自动更新其DNS记录
  2. DNS记录生成:CoreDNS根据 Kubernetes 服务的元数据生成DNS记录。例如,对于每个 Kubernetes 服务,CoreDNS会生成一个A记录(IPv4)和一个AAAA记录(IPv6),指向服务的IP地址。此外,还会生成SRV记录,表示服务的端口号
  3. DNS查询处理:当接收到DNS查询请求时,CoreDNS会根据查询类型和域名查找相应的DNS记录。对于服务名称查询,CoreDNS会返回与该服务关联的Pod的IP地址
  4. 插件机制:CoreDNS支持插件机制,允许开发者扩展其功能。例如,可以使用插件实现日志记录、缓存、负载均衡等功能

kube-proxy

我们从上面的章节可以看出 Service 最终负载均衡到后端的目标 Pods 是靠 kube-proxy 实现的。

随着 K8s 版本不断演进,kube-proxy 分别支持了多种工作模式:

  • userspace
  • iptables(当前的默认模式)
  • ipvs
userspace

在 K8s v1.2 版本之前的默认模式,这种模式下 Service 的请求会先从用户空间进入内核 iptables,然后再回到用户空间,由 kube-proxy 完成后端 Endpoints 的选择和代理工作。

这样流量从用户空间进出内核带来的性能损耗是不可接受的,因此从 v1.2 版本之后默认改为 iptables 模式

iptables

iptables 是 K8s 中当前默认的 kube-proxy 模式,核心逻辑是使用 iptables 中 PREROUTING 链 nat 表,实现 Service => Endpoints (Pod IP) 的负载均衡:

具体来说,访问 Service 的流量到达 Node 后,首先在 iptables PREROUTING 链中 KUBE-SERVICES 子链进行过滤:

1234

iptables -t nat -nvL PREROUTINGChain PREROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 2907M 152G KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */

接着,KUBE-SERVICES 链中会将所有 Service 建立对应的 KUBE-SVC-XXX 子链规则(KUBE-SVC-XXX 或其他 KUBE-XXX 相关的 Chain,后面的 XXX 是统一将部分字段(如 servicePortName + protocol)经过 Sum256 + encode 后取其前 16 位得到。 ),若 Service 类型是 NodePort,则命中最下面的 KUBE-NODEPORTS 子链:

12345678

iptables -t nat -nvL KUBE-SERVICESChain KUBE-SERVICES (2 references) pkts bytes target prot opt in out source destination 0 0 KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- * * 0.0.0.0/0 9.165.28.1 /* default/kubernetes:https cluster IP */ tcp dpt:443 0 0 KUBE-SVC-MYCX2RXADSOJAHT3 tcp -- * * 0.0.0.0/0 9.165.28.109 /* cloud-mt/rpc-client-api:rpc-client-api-http-port cluster IP */ tcp dpt:8080 0 0 KUBE-SVC-KA2XGWAJDV5QLLFK tcp -- * * 0.0.0.0/0 9.165.31.189 /* default/kubernetes-intranet:https cluster IP */ tcp dpt:443 0 0 KUBE-EXT-KA2XGWAJDV5QLLFK tcp -- * * 0.0.0.0/0 11.155.136.98 /* default/kubernetes-intranet:https loadbalancer IP */ tcp dpt:44323491 1217K KUBE-NODEPORTS all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

接着,某个 Service 对应的 KUBE-SVC-XXX 子链的目的地 (target) 将指向 KUBE-SEP-XXX,表示 Service 对应的 Endpoints,一条 KUBE-SEP-XXX 子链代表一条后端 Endpoint IP。

1234

iptables -t nat -nvL KUBE-SVC-MYCX2RXADSOJAHT3Chain KUBE-SVC-MYCX2RXADSOJAHT3 (2 references) pkts bytes target prot opt in out source destination 6822 355K KUBE-SEP-ZA4HDVB3YCYB4PTF all -- * * 0.0.0.0/0 0.0.0.0/0 /* cloud-mt/rpc-client-api:rpc-client-api-http-port -> 9.165.16.189:8080 */

可以看到上面的包含一条 KUBE-SEP-xxx 子链, 代表这个 Service 后面就一个 Pod

继续查看某个 KUBE-SEP-XXX 子链的规则如下:

12345

ptables -t nat -nvL KUBE-SEP-ZA4HDVB3YCYB4PTFChain KUBE-SEP-ZA4HDVB3YCYB4PTF (1 references) pkts bytes target prot opt in out source destination 0 0 KUBE-MARK-MASQ all -- * * 9.165.16.189 0.0.0.0/0 /* cloud-mt/rpc-client-api:rpc-client-api-http-port */ 7279 379K DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* cloud-mt/rpc-client-api:rpc-client-api-http-port */ tcp to:9.165.16.189:8080

命中某个 KUBE-SEP-XXX 子链后,可以看到其目的地有两个:

  • KUBE-MARK-MASQ:流量从目标 Pod 出去的 SNAT 转换,表示将 Pod IP -> Node IP。
  • DNAT:流量进入目标 Pod 的 DNAT 转换,表示将 Node IP -> Pod IP
ipvs

ipvs (IP Virtual Server) 是 LVS (Linux Virtual Server) 内核模块的一个子模块,建立于 Netfilter 之上的高效四层负载均衡器,支持 TCPUDP 协议,在这种模式下,kube-proxy 将规则插入到 ipvs 而非 iptables。

ipvs 具有优化的查找算法(哈希),复杂度为 O(1)。这意味着无论插入多少规则,它几乎都提供一致的性能。ipvs 支持多种负载均衡策略,如轮询 (rr)、加权轮询 (wrr)、最少连接 (lc)、源地址哈希 (sh)、目的地址哈希 (dh)等,K8s 中默认使用了 rr 策略。

尽管它有优势,但是 ipvs 可能不在所有 Linux 系统中都存在。与几乎每个 Linux 操作系统都有的 iptables 相比,ipvs 可能不是所有 Linux 系统的核心功能。如果集群中 Service 数量不太多,iptables 应该就够用了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-7-8,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入理解kubernetes(k8s)网络原理之二-service原理
上一篇文章中我们介绍了pod与主机互通及pod访问外网的原理,在这一章我们将介绍pod与pod的相互访问以及外部服务访问pod的方式,由此引出k8s的service的几种类型、使用场景和相关的实现原理。
一生无聊
2021/08/30
2.3K0
深入理解kubernetes(k8s)网络原理之二-service原理
K8S原来如此简单(四)Service+Ingress
上一篇我们通过deployment实现了pod的横向扩展,但是仍然不能负载,也不能对外提供服务,现在我们来看看如何通过k8s实现负载与外网访问
Chester Chen
2022/08/18
5030
K8S原来如此简单(四)Service+Ingress
Kubernetes 网络疑难杂症排查分享
到目前为止,本人见到的最有诚意的 K8s 网络问题分享,而且还有小图片呢!迫不及待的申请了转载授权。
崔秀龙
2019/08/16
1.9K0
Kubernetes 网络疑难杂症排查分享
K8s网络模型
k8s网络模型设计基础原则:每个Pod都拥有一个独立的 IP地址,而且 假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中 。 所以不管它们是否运行在同 一 个 Node (宿主机)中,都要求它们可以直接通过对方的 IP 进行访问。设计这个原则的原因 是,用户不需要额外考虑如何建立 Pod 之间的连接,也不需要考虑将容器端口映射到主机端口等问题。
加多
2019/04/18
3.7K2
K8s网络模型
k8s实践(12)--K8s service服务详解
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行)。 每个 滚动升级 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?
黄规速
2022/04/14
9.4K0
k8s实践(12)--K8s service服务详解
《Kubernetes》,你需要掌握的 Service 和 Ingress
k8s 我们已经从 NameSpace、Pod、PodController到Volumn都介绍过了,相信看完的小伙伴们也会很有收获的~那么今天我们继续来到k8s的课堂,这节我们将要来说下 k8S 搭建完服务后如何访问!
潜行前行
2021/06/25
1.3K0
《Kubernetes》,你需要掌握的 Service 和 Ingress
[译] 利用 eBPF 支撑大规模 K8s Service
K8S 当前重度依赖 iptables 来实现 Service 的抽象,对于每个 Service 及其 backend pods,在 K8s 里会生成很多 iptables 规则。例如 5K 个 Service 时,iptables 规则将达到 25K 条,导致的后果:
CNCF
2021/01/27
9670
[译] 利用 eBPF 支撑大规模 K8s Service
K8s的Service详解
● 在kubernetes中,Pod是应用程序的载体,我们可以通过Pod的IP来访问应用程序,但是Pod的IP地址不是固定的,这就意味着不方便直接采用Pod的IP对服务进行访问。
大忽悠爱学习
2022/09/28
1.4K0
K8s的Service详解
K8S的服务注册
每个 Kubernetes 服务都会自动注册到集群 DNS 之中。注册过程大致如下:
灰子学技术
2021/09/22
2.4K0
K8S的服务注册
优雅!太优雅了!竟能如此顺滑攻破K8s疑难杂症!
👉腾小云导读 作者经常帮助用户解决各种 K8s 各类「疑难杂症」,积累了丰富经验。本文将分享几个网络相关问题的排查和解决思路,深入分析并展开相关知识,实用性较强。此外,本文几个情况是在使用 TKE 时遇到的。不同厂商的网络环境可能不一样,文中会对不同问题的网络环境进行说明。欢迎继续往下阅读。 👉看目录点收藏,随时涨技术 1 跨 VPC 访问 NodePort 经常超时 2 LB 压测 CPS 低 3 DNS 解析偶尔 5S 延时 4 Pod 访问另一个集群的 apiserver 有延时 5 DNS 解析异常
腾讯云开发者
2023/05/29
1.4K0
优雅!太优雅了!竟能如此顺滑攻破K8s疑难杂症!
Service 的应用
​clusterIP 主要在每个 node 节点使用 ipvs,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口。
星哥玩云
2022/09/15
2680
Service 的应用
【重识云原生】第六章容器基础6.4.9节——Service
在k8s中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
江中散人_Jun
2022/11/16
1.2K0
【重识云原生】第六章容器基础6.4.9节——Service
Kubernetes之kube-proxy service实现原理
我们生产k8s对外暴露服务有多种方式,其中一种使用external-ips clusterip service ClusterIP Service方式对外暴露服务,kube-proxy使用iptables mode。这样external ips可以指定固定几台worker节点的IP地址(worker节点服务已经被驱逐,作为流量转发节点不作为计算节点),并作为lvs vip下的rs来负载均衡。根据vip:port来访问服务,并且根据port不同来区分业务。相比于NodePort Service那样可以通过所有worker节点的node_ip:port来访问更高效,也更容易落地生产。但是,traffic packet是怎么根据集群外worker节点的node_ip:port或者集群内cluster_ip:port访问方式找到pod ip的?
kubernetes中文社区
2021/06/21
8360
Kubernetes之kube-proxy service实现原理
Kubernetes K8S之Service服务详解与示例
Kubernetes Service定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常被称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 selector实现的。
踏歌行
2020/10/15
3.9K0
Kubernetes K8S之Service服务详解与示例
kubernetes service 原理解析
在 kubernetes 中,当创建带有多个副本的 deployment 时,kubernetes 会创建出多个 pod,此时即一个服务后端有多个容器,那么在 kubernetes 中负载均衡怎么做,容器漂移后 ip 也会发生变化,如何做服务发现以及会话保持?这就是 service 的作用,service 是一组具有相同 label pod 集合的抽象,集群内外的各个服务可以通过 service 进行互相通信,当创建一个 service 对象时也会对应创建一个 endpoint 对象,endpoint 是用来做容器发现的,service 只是将多个 pod 进行关联,实际的路由转发都是由 kubernetes 中的 kube-proxy 组件来实现,因此,service 必须结合 kube-proxy 使用,kube-proxy 组件可以运行在 kubernetes 集群中的每一个节点上也可以只运行在单独的几个节点上,其会根据 service 和 endpoints 的变动来改变节点上 iptables 或者 ipvs 中保存的路由规则。
田飞雨
2019/12/15
1.6K0
kubernetes service 原理解析
Kubernetes Service解析
我们都知道,在K8S集群中,每个Pod都有自己的私有IP地址,并且这些IP地址不是固定的。这意味着其不依赖IP地址而存在。例如,当我们因某种业务需求,需要对容器进行更新操作,则容器很有可能在随后的启动运行过程中被分配到其他IP地址。此外,在K8S集群外部看不到该Pod。因此,Pod若单独运行于K8S体系中,在实际的业务场景中是不现实的,故我们需要通过其他的策略去解决,那么解决方案是什么? 由此,我们引入了Serivce这个概念以解决上述问题。
Luga Lee
2021/12/09
4710
Kubernetes Service解析
k8s-service
Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略-通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label selector
eadela
2019/12/11
9010
Kubernetes | Service - Ingress
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略——通常称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector。
Zkeq
2023/05/11
6180
Kubernetes | Service - Ingress
service mesh框架对比_k8s外部访问内部service
在kubernetes中,Pod是应用程序的载体,我们可以通过Pod的IP来访问应用程序,但是Pod的IP地址不是固定的,这就意味着不方便直接采用Pod的IP对服务进行访问。
全栈程序员站长
2022/09/22
9220
service mesh框架对比_k8s外部访问内部service
Kubernetes资源之服务发现service详解
Kubernetes中一个应用服务会有一个或多个实例(Pod),每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象,如下所示:
mikelLam
2022/10/31
1.4K0
Kubernetes资源之服务发现service详解
相关推荐
深入理解kubernetes(k8s)网络原理之二-service原理
更多 >
LV.1
腾讯云后台开发工程师
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档