Kubernetes 从懵圈到熟练:集群服务的三个要点和一种实现

做者 | 声东 阿里云售后技术专家前端


以个人经验来说,理解 Kubernetes 集群服务的概念,是比较不容易的一件事情。尤为是当咱们基于似是而非的理解,去排查服务相关问题的时候,会很是不顺利。算法

这体如今,对于新手来讲,ping 不通服务的 IP 地址这样基础的问题,都很难理解;而就算对经验很丰富的工程师来讲,看懂服务相关的 iptables 配置,也是有至关的挑战的。编程

今天这边文章,我来深刻解释一下 Kubernetes 集群服务的原理与实现,便于你们理解。后端

 

Kubernetes 集群服务的本质是什么

概念上来说,Kubernetes 集群的服务,其实就是负载均衡、或反向代理。这跟阿里云的负载均衡产品,有不少相似的地方。和负载均衡同样,服务有它的 IP 地址以及前端端口;服务后边会挂载多个容器组 Pod 做为其“后端服务器”,这些“后端服务器”有本身的 IP 以及监听端口。服务器

image

当这样的负载均衡和后端的架构,与 Kubernetes 集群结合的时候,咱们能够想到的最直观的实现方式,就是集群中某一个节点专门作负载均衡(相似 LVS)的角色,而其余节点则用来负载后端容器组。网络

image

这样的实现方法,有一个巨大的缺陷,就是单点问题。Kubernetes 集群是 Google 多年来自动化运维实践的结晶,这样的实现显然与其智能运维的哲学相背离的。架构

 

自带通讯员


边车模式(Sidecar)是微服务领域的核心概念。边车模式,换一句通俗一点的说法,就是自带通讯员。熟悉服务网格的同窗确定对这个很熟悉了。可是可能比较少人注意到,其实 Kubernetes 集群原始服务的实现,也是基于 Sidecar 模式的。负载均衡

image

在 Kubernetes 集群中,服务的实现,其实是为每个集群节点上,部署了一个反向代理 Sidecar。而全部对集群服务的访问,都会被节点上的反向代理转换成对服务后端容器组的访问。基本上来讲,节点和这些 Sidecar 的关系以下图所示。框架

image

 

把服务照进现实


前边两节,咱们看到了,Kubernetes 集群的服务,本质上是负载均衡,即反向代理;同时咱们知道了,在实际实现中,这个反向代理,并非部署在集群某一个节点上,而是做为集群节点的边车,部署在每一个节点上的。运维

在这里把服务照进反向代理这个现实的,是 Kubernetes 集群的一个控制器,即 kube-proxy。关于 Kubernetes 集群控制器的原理,请参考我另一篇关于控制器的文章。简单来讲,kube-proxy 做为部署在集群节点上的控制器,它们经过集群 API Server 监听着集群状态变化。当有新的服务被建立的时候,kube-proxy 则会把集群服务的状态、属性,翻译成反向代理的配置。

image

那剩下的问题,就是反向代理,即上图中 Proxy 的实现。

 

一种实现

Kubernetes 集群节点实现服务反向代理的方法,目前主要有三种,即 userspace、iptables 以及 IPVS。今天咱们只深刻分析 iptables 的方式,底层网络基于阿里云 Flannel 集群网络。

 

过滤器框架

如今,咱们来设想一种场景。咱们有一个屋子。这个屋子有一个入水管和出水管。从入水管进入的水,是不能直接饮用的,由于有杂质。而咱们指望,从出水管流出的水,能够直接饮用。为了达到目的,咱们切开水管,在中间加一个杂质过滤器。

image

过了几天,咱们的需求变了,咱们不止要求从屋子里流出来的水能够直接饮用,咱们还但愿水是热水。因此咱们不得再也不在水管上增长一个切口,而后增长一个加热器。

image

很明显,这种切开水管,增长新功能的方式是很丑陋的。由于需求可能随时会变,咱们甚至很难保证,在通过一年半载以后,这跟水管还能找获得能够被切开的地方。

因此咱们须要从新设计。首先咱们不能随便切开水管,因此咱们要把水管的切口固定下来。以上边的场景为例,咱们确保水管只能有一个切口位置。其次,咱们抽象出对水的两种处理方式:物理变化和化学变化。

image

基于以上的设计,若是咱们须要过滤杂质,就能够在化学变化这个功能模块里增长一条过滤杂质的规则;若是咱们须要增长温度的话,就能够在物理变化这个功能模块里增长一条加热的规则。

以上的过滤器框架,显然比切水管的方式,要优秀不少。设计这个框架,咱们主要作了两件事情,一个是固定水管切口位置,另一个是抽象出两种水处理方式。

理解这两件事情以后,咱们能够来看下 iptables,或者更准确的说法,netfilter 的工做原理。netfilter 实际上就是一个过滤器框架。netfilter 在网络包收发及路由的管道上,一共切了 5 个口,分别是 PREROUTING,FORWARD,POSTROUTING,INPUT 以及 OUTPUT;同时 netfilter 定义了包括 nat、filter 在内的若干个网络包处理方式。

image

须要注意的是,routing 和 forwarding 很大程度上增长了以上 netfilter 的复杂程度,若是咱们不考虑 routing 和 forwarding,那么 netfilter 会变得跟咱们的水质过滤器框架同样简单。

 

节点网络大图

如今咱们看一下 Kubernetes 集群节点的网络全貌。横向来看,节点上的网络环境,被分割成不一样的网络命名空间,包括主机网络命名空间和 Pod 网络命名空间;纵向来看,每一个网络命名空间包括完整的网络栈,从应用到协议栈,再到网络设备。

在网络设备这一层,咱们经过 cni0 虚拟网桥,组建出系统内部的一个虚拟局域网。Pod 网络经过 veth 对链接到这个虚拟局域网内。cni0 虚拟局域网经过主机路由以及网口 eth0 与外部通讯。

在网络协议栈这一层,咱们能够经过编程 netfilter 过滤器框架,来实现集群节点的反向代理。

image

实现反向代理,归根结底,就是作 DNAT,即把发送给集群服务 IP 和端口的数据包,修改为发给具体容器组的 IP 和端口。

参考 netfilter 过滤器框架的图,咱们知道,在 netfilter 里,能够经过在 PREROUTING,OUTPUT 以及 POSTROUGING 三个位置加入 NAT 规则,来改变数据包的源地址或目的地址。

由于这里须要作的是 DNAT,即改变目的地址,这样的修改,必须在路由(ROUTING)以前发生以保证数据包能够被路由正确处理,因此实现反向代理的规则,须要被加到 PREROUTING 和 OUTPUT 两个位置。

其中,PREOURTING 的规则,用来处理从 Pod 访问服务的流量。数据包从 Pod 网络 veth 发送到 cni0 以后,进入主机协议栈,首先会通过 netfilter PREROUTING 来作处理,因此发给服务的数据包,会在这个位置作 DNAT。通过 DNAT 处理以后,数据包的目的地址变成另一个 Pod 的地址,从而通过主机路由,转发到 eth0,发送给正确的集群节点。

而添加在 OUTPUT 这个位置的 DNAT 规则,则用来处理从主机网络发给服务的数据包,原理也是相似,即通过路由以前,修改目的地址,以方便路由转发。

 

升级过滤器框架

在过滤器框架一节,咱们看到 netfilter 是一个过滤器框架。netfilter 在数据“管到”上切了 5 个口,分别在这 5 个口上,作一些数据包处理工做。虽然固定切口位置以及网络包处理方式分类已经极大的优化了过滤器框架,可是有一个关键的问题,就是咱们仍是得在管道上作修改以知足新的功能。换句话说,这个框架没有作到管道和过滤功能二者的完全解耦。

为了实现管道和过滤功能二者的解耦,netfilter 用了表这个概念。表就是 netfilter 的过滤中心,其核心功能是过滤方式的分类(表),以及每种过滤方式中,过滤规则的组织(链)。

image

把过滤功能和管道解耦以后,全部对数据包的处理,都变成了对表的配置。而管道上的5个切口,仅仅变成了流量的出入口,负责把流量发送到过滤中心,并把处理以后的流量沿着管道继续传送下去。

如上图,在表中,netfilter 把规则组织成为链。表中有针对每一个管道切口的默认链,也有咱们本身加入的自定义链。默认链是数据的入口,默认链能够经过跳转到自定义链来完成一些复杂的功能。这里容许增长自定义链的好处是显然的。为了完成一个复杂过滤功能,好比实现 Kubernetes 集群节点的反向代理,咱们可使用自定义链来模块化咱们规则。

 

用自定义链实现服务的反向代理

集群服务的反向代理,实际上就是利用自定义链,模块化地实现了数据包的 DNAT 转换。KUBE-SERVICE 是整个反向代理的入口链,其对应全部服务的总入口;KUBE-SVC-XXXX 链是具体某一个服务的入口链,KUBE-SERVICE 链会根据服务 IP,跳转到具体服务的 KUBE-SVC-XXXX 链;而 KUBE-SEP-XXXX 链表明着某一个具体 Pod 的地址和端口,即 endpoint,具体服务链 KUBE-SVC-XXXX 会以必定算法(通常是随机),跳转到 endpoint 链。

image

而如前文中提到的,由于这里须要作的是 DNAT,即改变目的地址,这样的修改,必须在路由以前发生以保证数据包能够被路由正确处理。因此 KUBE-SERVICE 会被 PREROUTING 和 OUTPUT 两个默认链所调用。

 

总结


经过这篇文章,你们应该对 Kubernetes 集群服务的概念以及实现,有了更深层次的认识。咱们基本上须要把握三个要点:

  • 服务本质上是负载均衡;
  • 服务负载均衡的实现采用了与服务网格相似的 Sidecar 的模式,而不是 LVS 类型的独占模式;
  • kube-proxy 本质上是一个集群控制器。除此以外,咱们思考了过滤器框架的设计,并在此基础上,理解使用 iptables 实现的服务负载均衡的原理。

 

原文连接

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索