深入 K8s 网络原理(二)- Service iptables 模式分析
1. 概述
接上一篇《深入 K8s 网络原理(一)- Flannel VXLAN 模式分析》,今天我们继续来分析 Kubernetes Service 的实现原理。
2. 准备 Service 和 Pods 资源
镜像和上一篇一样;
Deployment 的 YAML 如下:
nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:test1
ports:
- containerPort: 80
对应的 Service YAML 如下:
nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
nodePort: 30007
3. K8s 里 Service 的实现原理
Kubernetes 提供了几种不同类型的 Service,包括:
ClusterIP:这是最常见的 Service 类型,为 Service 提供一个集群内部的 IP 地址,使得 Service 只能在集群内部访问。NodePort:这种类型的 Service 在每个节点上开放一个端口(NodePort),从而允许从集群外部通过 <NodeIP>:<NodePort> 访问 Service。LoadBalancer:这种类型的 Service 通常由云提供商支持,它会在集群外部创建一个负载均衡器,将外部流量分发到集群内的 Pods。ExternalName:通过返回一个名字(而非 IP 地址)来指向外部服务。
接着具体来看 Service 的实现。
3.1 kube-proxy 组件
Kubernetes 集群中每个节点上会运行一个关键组件 kube-proxy,它负责为 Service 对象实现网络代理,使得网络流量可以透明地定向到后端 Pods。kube-proxy 支持几种不同的代理模式,最常见的是 iptables 模式和 IPVS 模式。
- iptables 模式
- 在这种模式下,kube-proxy 使用 iptables 规则来捕获到达 Service 的流量,并将其重定向到后端 Pods。每当 Service 或 Pod 发生变化时,kube-proxy 都会更新 iptables 规则。
- iptables 模式是最简单且广泛使用的,但在大规模集群中可能会面临性能问题,因为每个网络包都需要通过不短的规则链进行处理。
- IPVS (IP Virtual Server) 模式
- IPVS 模式使用内核的 IPVS 功能,该功能提供了内置的负载均衡功能。与 iptables 相比,IPVS 可以处理更大规模的流量,拥有更好的性能和更复杂的负载均衡算法(最少连接等)。
- 在这种模式下,kube-proxy 会创建一个虚拟服务器,为每个 Service 分配一个虚拟 IP(VIP),并将流量负载均衡到后端 Pods。
以 kube-proxy 的 iptables 模式为例,我们具体来看下 Service 创建后,iptables 是如何将 Service 流量转到 pods 上的。
3.2 iptables 简介
简单介绍下 iptables:
iptables是一种在 Linux 系统中广泛使用的工具,它允许管理员配置内核的 netfilter 模块,以控制网络数据包的流入流出。这个工具提供了一个框架,用于定义规则,这些规则决定了如何处理经过网络接口的数据包。iptables 的核心功能主要包括:
- 数据包过滤:iptables 最常用于过滤数据包,即决定哪些数据包可以通过网络接口,哪些应该被阻止。
- 网络地址转换 (NAT):它可以用于修改数据包的源或目的地址,常用于路由和隐藏内部网络结构。
- 端口转发:iptables 可以重定向到特定端口的数据流,用于设置端口转发。
刚从铺灰的硬盘里发现一张三年前画的 iptables 相关的图(我都忘记这个图应该叫啥名字了):

3.3 iptables 规则
下面具体看下 Service 对应的 iptables 规则。
3.3.1 Service,Pod 和 Host 信息
前面创建了 Service 和 Deployment,对应的 Service 和 Pod 资源如下:
kgsvc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.107.33.105 <none> 80:30007/TCP 152m
kgpoowide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-7fbb8f4b4c-89bds 1/1 Running 0 155m 10.244.2.4 minikube-m03
nginx-deployment-7fbb8f4b4c-d29zm 1/1 Running 0 155m 10.244.1.5 minikube-m02
此外,我的 K8s 集群包括3个节点,nodes 的 ip/hostname 信息如下:
192.168.49.2 minikube
192.168.49.3 minikube-m02
192.168.49.4 minikube-m03
3.3.2 从 NodePort 入手寻找 iptables 规则
现在进到 minikube 节点,也就是 K8s 主节点,查看下 nat 表的链信息,过滤下 NodePort 端口 30007:
sudo iptables -t nat -L | grep 30007
KUBE-EXT-V2OKYYMBY3REGZOG tcp -- anywhere anywhere /* default/nginx-service */ tcp dpt:30007
可以看到一条链:KUBE-EXT-V2OKYYMBY3REGZOG,具体看下这条链的信息:
sudo iptables -t nat -L KUBE-EXT-V2OKYYMBY3REGZOG -v
Chain KUBE-EXT-V2OKYYMBY3REGZOG (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-V2OKYYMBY3REGZOG all -- any any anywhere anywhere
从这里可以看到 KUBE-EXT-V2OKYYMBY3REGZOG 有一条子链 KUBE-SVC-V2OKYYMBY3REGZOG。继续看 KUBE-SVC-V2OKYYMBY3REGZOG 链:
sudo iptables -t nat -L KUBE-SVC-V2OKYYMBY3REGZOG -v
Chain KUBE-SVC-V2OKYYMBY3REGZOG (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-J2DHXTF62PN2AN4F all -- any any anywhere anywhere /* default/nginx-service -> 10.244.1.5:80 */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-A4R5AW5RLMEQF7RP all -- any any anywhere anywhere /* default/nginx-service -> 10.244.2.4:80 */
进一步可以找到两条 KUBE-SVC-V2OKYYMBY3REGZOG 的子链 KUBE-SEP-J2DHXTF62PN2AN4F 和 KUBE-SEP-A4R5AW5RLMEQF7RP,这里对应2个 pods。以 KUBE-SEP-J2DHXTF62PN2AN4F 为例继续跟:
sudo iptables -t nat -L KUBE-SEP-J2DHXTF62PN2AN4F -v
Chain KUBE-SEP-J2DHXTF62PN2AN4F (1 references)
pkts bytes target prot opt in out source destination
0 0 DNAT tcp -- any any anywhere anywhere /* default/nginx-service */ tcp to:10.244.1.5:80
到这里 target 不再是其他链,而是 DNAT,也就是请求 Service 的 NodePort 最终流量被 DNAT 到了 10.244.1.5:80 和 10.244.2.4:80 这两个 Endpoints,它们分别对应2个 pods。
3.3.3 从 PREROUTING 和 OUTPUT 链寻找 K8s 相关子链
先看 PREROUTING:
sudo iptables -t nat -L PREROUTING -v
Chain PREROUTING (policy ACCEPT 5 packets, 300 bytes)
pkts bytes target prot opt in out source destination
99 5965 KUBE-SERVICES all -- any any anywhere anywhere /* kubernetes service portals */
可以看到入向流量全部都会经过 KUBE-SERVICES 链处理。继续看 OUTPUT:
sudo iptables -t nat -L OUTPUT -v
Chain OUTPUT (policy ACCEPT 3355 packets, 202K bytes)
pkts bytes target prot opt in out source destination
29961 1801K KUBE-SERVICES all -- any any anywhere anywhere /* kubernetes service portals */
同样全部出向流量也被 KUBE-SERVICES 链处理。继续看下 KUBE-SERVICES 链:
sudo iptables -t nat -L KUBE-SERVICES -v
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-V2OKYYMBY3REGZOG tcp -- any any anywhere 10.107.33.105 /* default/nginx-service cluster IP */ tcp dpt:http
3391 203K KUBE-NODEPORTS all -- any any anywhere anywhere /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
可以看到2条子链,一个是表示 Nginx Service 的 Cluster IP 的子链 KUBE-SVC-V2OKYYMBY3REGZOG,另外一个是表示集群 NodePort 的 KUBE-NODEPORTS 子链。KUBE-SVC-V2OKYYMBY3REGZOG 在前面已经具体看过了,那么 KUBE-NODEPORTS 子链具体又包含啥信息呢:
sudo iptables -t nat -L KUBE-NODEPORTS -v
Chain KUBE-NODEPORTS (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-EXT-V2OKYYMBY3REGZOG tcp -- any any anywhere anywhere /* default/nginx-service */ tcp dpt:30007
可以看到当 TCP 流量的目的端口是 30007 的时候,就会匹配到 KUBE-EXT-V2OKYYMBY3REGZOG 子链,KUBE-EXT-V2OKYYMBY3REGZOG 子链的内容前面已经具体看过了。换言之,每多创建一个 NodePort 类型的 Service,kube-proxy 就会在 KUBE-NODEPORTS 子链下新挂一条 KUBE-EXT-XXX 子链。
3.3.4 总结下
IP 包进出主机都会经过 KUBE-SERVICES 链,进而根据 destination 地址匹配到不同的子链:
- 如果目的地址是某个 Service 的 Cluster IP,那么就匹配到具体的 KUBE-SVC-XXX 处理;
- 否则,就匹配到 KUBE-NODEPORTS 处理;流量匹配到 KUBE-NODEPORTS 后,会进一步根据 tcp 目的端口 来匹配具体的子链 KUBE-EXT-XXX;
如果流量匹配到 KUBE-EXT-XXX 子链,端口命中,那么下一条依旧是表示 Cluster IP 的 KUBE-SVC-XXX,所以两条子链在这里汇合。而 KUBE-SVC-XXX 链上的规则会进一步将 IP 包匹配到 KUBE-SEP-XXX 子链上,这些子链表达的是“Service Endpoints”。默认情况下 KUBE-SVC-XXX 会根据 Pod 数量按照相等的概率将流量分流到多个 KUBE-SEP-XXX 上进一步匹配。而 KUBE-SEP-XXX 链会执行类似“DNAT to:10.244.1.5:80”过程,最终将一开始请求 Service 的流量就丢给了 Pod。
所以,当你通过 NodePort/ClusterIP 方式访问 pods 的时候,以两副本为例,整体流量匹配过程大致如下图:

4. 总结
不总结。明天见。
深入 K8s 网络原理(二)- Service iptables 模式分析的更多相关文章
- k8s网络原理
https://blog.csdn.net/watermelonbig/article/details/80646988 k8s中,每个 Pod 都有一个独立的 IP 地址,所有 Pod 在一个网络空 ...
- K8S网络排故障一则--iptables规则
这个故障源起来在k8s上同时安装ceph群集(测试的时候机器不多啊) 当这两者都OK之后,原来k8s上的服务实例,则有的通,有的不通了. ==================== 所有可能的故障点,f ...
- 一次客户需求引发的K8S网络探究
前言 在本次案例中,我们的中台技术工程师遇到了来自客户提出的打破k8s产品功能限制的特殊需求,面对这个极具挑战的任务,攻城狮最终是否克服了重重困难,帮助客户完美实现了需求?且看本期K8S技术案例分享! ...
- Kubernetes(k8s)底层网络原理刨析
目录 1 典型的数据传输流程图 2 3种ip说明 3 Docker0网桥和flannel网络方案 4 Service和DNS 4.1 service 4.2 DNS 5 外部访问集群 5.1 外部访问 ...
- k8s Nodeport方式下service访问,iptables处理逻辑(转)
原文 https://www.myf5.net/post/2330.htm k8s Nodeport方式下service访问,iptables处理逻辑 2017年07月11日 0条评论 976次阅读 ...
- ASP.NET Core on K8S深入学习(11)K8S网络知多少
本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.Kubernetes网络模型 我们都知道Kubernetes作为容器编排引 ...
- docker+k8s基础篇二
Docker+K8s基础篇(二) docker的资源控制 A:docker的资源限制 Kubernetes的基础篇 A:DevOps的介绍 B:Kubernetes的架构概述 C:Kubernetes ...
- linux基础-第十四单元 Linux网络原理及基础设置
第十四单元 Linux网络原理及基础设置 三种网卡模式图 使用ifconfig命令来维护网络 ifconfig命令的功能 ifconfig命令的用法举例 使用ifup和ifdown命令启动和停止网卡 ...
- k8s网络之Flannel网络
k8s网络主题系列: 一.k8s网络之设计与实现 二.k8s网络之Flannel网络 三.k8s网络之Calico网络 简介 Flannel是CoreOS团队针对Kubernetes设计的一个网络规划 ...
- k8s网络之Calico网络
k8s网络主题系列: 一.k8s网络之设计与实现 二.k8s网络之Flannel网络 三.k8s网络之Calico网络 简介 Calico 是一种容器之间互通的网络方案.在虚拟化平台中,比如 Open ...
随机推荐
- API接口设计规范,看这篇就足以了
优秀的设计是产品变得卓越的原因.设计API意味着提供有效的接口,可以帮助API使用者更好地了解.使用和集成,同时帮助人们有效地维护它.每个产品都需要使用手册,API也不例外. 在API领域,可以将 ...
- wget 命令的使用:HTTP文件下载、FTP文件下载--九五小庞
1. wget 命令简介与安装wget是用于在命令行终端下载网络文件的开源免费的命令工具,支持 HTTP/HTTPS.FTP/FTPS 协议的下载.wget 与 curl 相似,curl 可以理解为是 ...
- Solution -「九省联考 2018」劈配
Description Link. 一年一度的综艺节目<中国新代码>又开始了.Zayid 从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 轻车熟路的 Za ...
- Solution -「CSP 2019」Partition
Description Link. 给出一个数列,要求将其分成几段,使每段的和非严格递增,求最小的每段的和的平方和. Solution 注意到 \(a_{i}\) 为正,对于正数有这样的结论: \[a ...
- Solution -「洛谷 P3600」随机数生成器
Desciption Link. 给定一个值域在 \([1,x]\) 的长度为 \(n\) 的序列(由随机数构成),求给定一组区间中的最小值的最大值的期望. Solution 记: \[w=\max\ ...
- 一个 println 竟然比 volatile 还好使?
前两天一个小伙伴突然找我求助,说准备换个坑,最近在系统复习多线程知识,但遇到了一个刷新认知的问题-- 小伙伴:Effective JAVA 里的并发章节里,有一段关于可见性的描述.下面这段代码会出现死 ...
- 08-03_阅读flask上下文前夕补充、flask请求上下文、数据库连接池
文章目录 阅读flask上下文前夕补充 01 偏函数 02 __add__的使用 03 chain函数 2 flask请求上下文 1 首先分析请求上下文对象(ctx)创立 2 把请求对象(ctx)添加 ...
- MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录-3
接上文,单节点升级到80版本之后,构建新版本的80集群就水到渠成.相对简单了,详情可参见之前的集群构建博文. 本文在修改配置集群的新参数时,修改了pxc_strict_mode为默认的ENFORCIN ...
- [ABC205E] White and Black Balls 题解
White and Black Balls 题目大意 将 \(n\) 个白球,\(m\) 个黑球排成一列,要求满足 \(\forall i\in[1,n+m],w_i\le b_i+k\),问存在多少 ...
- .then()方法的意思和用法
then()方法是异步执行. 意思是:就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题. 语法:promise.then(onCompleted, ...