系列文章目录
前言
在一个k8s集群中,微服务以 Pod形式 运行在我们的集群中,这些 Pod 的副本通过Service 服务暴露,当一个外部请求到达 Service 的虚拟 IP 时,如何将请求转发到其中一个底层 Pod?这便是本篇文章的核心思想。
一、kube-proxy介绍
kube-proxy是k8s网络代理核心组件,部署在每个Node节点上,主要维护节点上的网络规则。它是实现service的通信与负载均衡机制的重要组件
kube-proxy负责为pod创建代理服务,通过watch机制会根据 service 和 endpoints,node资源对象的改变来实时刷新iptables或者ipvs规则
使发往 Service 的流量(通过ClusterIP和NodePort)负载均衡到正确的后端Pod。
1、kube-proxy三种工作模式
userspace(目前已经弃用)
请求是从用户态-->内核态-->用户态,转发是在用户态进行的,效率不高且容易丢包
iptables(默认工作模式)
相比于userspace免去了一次内核态-->用户态的切换
1、kube-proxy通过Api-server的watch接口实时监测service和endpoint对象的变化,当有service创建时,kube-proxy在iptables中追加新的规则
2、在该模式下,kube-proxy为service后端的每个pod创建对应的iptables规则,直接将发向cluster ip的请求重定向到一个pod ip
3、在该模式下,kube-proxy不承担四层代理的角色,只负责创建iptables规则
补充:
在iptables模式下,会根据service以及endpoints对象的改变来实时刷新规则,kube-proxy使用了iptables的filter表和nat表,
并对 iptables 的链进行了扩充,自定义了 KUBE-SERVICES、KUBE-EXTERNAL-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING、
KUBE-MARK-MASQ、KUBE-MARK-DROP、KUBE-FORWARD 七条链。
另外还新增了以“KUBE-SVC-xxx”和“KUBE-SEP-xxx”开头的数个链,除了创建自定义的链以外还将自定义链插入到已有链的后面以便劫持数据包。
ipvs
1、kube-proxy ipvs模式是基于NAT实现的,对访问k8s service的请求进行虚拟ip到pod ip的转发
工作原理:
当创建一个svc后,ipvs模式的kube-proxy会做以下三件事:
1、确保kube-ipvs0网卡的存在。因为ipvs的netfilter钩子挂载input链.需要把svc的访问IP绑定在该网卡上让内核觉得虚IP就是本机IP,从而进入input链。
2、把svc的访问ip绑定在该网卡上
3、通过socket调用,创建ipvs的虚拟服务和真实服务,分别对应svc和endpoints
注意事项:
ipvs用于流量转发,无法处理kube-proxy中的其他问题,例如把包过滤、SNAT等。因此在以下四种情况下kube-proxy依赖iptables:
1、kube-proxy配置启动参数masquerade-all=true,即集群中所有经过kube-proxy的包都做一次SNAT;
2、kube-proxy启动参数指定集群IP地址范围;
3、支持loadbalance类型的服务
4、支持nodeport类型的服务
2、iptables中k8s相关的链
名称 | 含义 |
---|---|
KUBE-SERVICES | 是服务数据包的入口点。它的作用是匹配 目标 IP:port 并将数据包分派到对应的 KUBE-SVC-* 链 |
KUBE-SVC-* | 充当负载均衡器,将数据包分发到 KUBE-SEP-* 链。KUBE-SEP-* 的数量等于后面的端点数量 服务。选择哪个 KUBE-SEP-* 是随机决定的 |
KUBE-SEP-* | 表示 Service EndPoint。它只是执行 DNAT,将 服务 IP:端口,以及 Pod 的端点 IP:端口 |
KUBE-MARK-MASQ | 将 Netfilter 标记添加到发往该服务的数据包中,该标记 源自集群网络之外。带有此标记的数据包将被更改 在 POSTROUTING 规则中使用源网络地址转换 (SNAT) 和 node 的 IP 地址作为其源 IP 地址 |
KUBE-MARK-DROP | 为没有目的地的数据包添加 Netfilter 标记 此时已启用 NAT。这些数据包将在 KUBE-FIREWALL 中被丢弃 链 |
KUBE-FW-* | chain 在 service 部署时执行 LoadBalancer 类型,则 将目标 IP 与服务的负载均衡器 IP 匹配,并分配 数据包到对应的 KUBE-SVC-* 链或 KUBE-XLB-* 链的 KEY-XLB-* 链 |
KUBE-NODEPORTS | 发生在服务部署在 NodePort 和 LoadBalancer 的 LoadPort 共享 LoadPort 和 LoadBalancer 的有了它,外部源可以访问该服务 按 Node Port 的 NODE 端口。它匹配节点端口并分发 数据包到对应的 KUBE-SVC-* 链或 KUBE-XLB-* 链 的 KEY-XLB-* 链 的 |
KUBE-XLB-* | 在 externalTrafficPolicy 设置为 Local 时工作。有了这个 链式编程,如果节点没有相关端点,则数据包将被丢弃 保留 |
3、MASQUERADE 与 SNAT、DNAT 的区别是?
KUBE-MARK-MASQ 是 K8s 中使用 iptables MASQUERADE 动作的一种方式,先进行标记 MARK (0x4000),
然后在 POSTROUTING 链根据 MARK 进行真正的 MASQUERADE。
可以简单理解为 MASQUERADE 是 SNAT 的一个特例,表示 从 Pod 访问出去的时候伪装 Pod 源地址。
MASQUERADE 与 SNAT 的区别:
SNAT 需要指定转换的网卡 IP,而 MASQUERADE 可以自动获取到发送数据的网卡 IP,不需要指定 IP,特别适合 IP 动态分配或会发生变化的场景。
KUBE-MARK-MASQ:
流量从目标 Pod 出去的 SNAT 转换,表示将 Pod IP -> Node IP。
DNAT:
流量进入目标 Pod 的 DNAT 转换,表示将 Node IP -> Pod IP
二、kube-proxy的iptables模式剖析
首先请查看顶部文章链接iptables基本知识,对出入栈、四表五链有个认知,然后再看下文
包含整改service模式的流程图
只包含cluster IP、NodePort模式的流程图
流程图结合iptables示例图
结合上述流程图,主要分两部分对kube-proxy的iptables模式进行剖析
1.集群内部通过clusterIP访问到pod的流程
资源准备,如下图所示
需求: 当在集群pod1访问curl http://10.102.172.63:8088时,请求是怎么到达后端pod2的?
1.1.流程分析
确定kube-proxy的工作模式两种方式
[root@master ~]# curl http://127.0.0.1:10249/proxyMode
iptables
[root@master ~]# kubectl get configmaps -n kube-system kube-proxy -oyaml |grep mode
mode: "" #默认为空就是iptables模式
a、进入到pod1,执行curl请求
[root@master ~]# kubectl exec -it -n xx xx-xx-6c57d9ddc6-2495v bash
bash-4.2$ curl http://10.102.172.63:8088
xshell多开一个窗口,登录到pod1宿主机,查看iptables规则
b、因为从上述iptables流程图可知,当请求从集群内部发出时,先进入的是NAT表中的OUTPUT链---->到达KUBE-SERVICE自定义链
那么在pod1宿主机中查看output链规则如下所示
[root@xmhl-std12 ~]# iptables -t nat -S |grep -i output
-P OUTPUT ACCEPT