【k8s系列十二】k8s 之 Service

118 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

什么是Service

k8s service 定义了这样一种抽象: 我们可以将pod分组,然后定义pod的访问策略, 通常这一组可以访问的服务叫做微服务. service能够访问到他下面管理的pod, 他们通常是通过"label selector"进行匹配的.

image.png

分析: Deployment控制器一创建就会创建RS控制器, RS控制器根据要求创建并管理pod. 这时创建一个svc, svc会通过标签选择器, 匹配满足条件的pod. 然后我们通过service就可以访问pod了。

对于svc来说, 现在我们可以简单的实现service控制pod, 但svc也是经过了几轮的核心迭代才发展到现在的, 下面我们来看看几轮核心迭代的区别.

svc核心迭代

在k8s集群中, 每个node都会运行一个kube-proxy进程, kube-proxy负责为service实现VIP, 也就是虚拟ip. 而不是ExternalName. 在k8s v1版本, 代理完全在userspace; 在k8s v1.1版本, 新增了iptables代理, 但并不是默认的运行模式; 在 k8s v1.2版本, 默认就是iptables代理. 在k8s v1.8.0-beta.0 版本中, 增加了ipvs代理. 在k8s v1.14版本中, 开始默认使用ipvs代理.

image

在k8s v1.0版本,service是"4层" (TCP/UDP over IP)的概念, 到了 k8s v1.1版本, 新增了Ingress API(beta版), 用来表示"7层"(http)服务

综上所述: 其实总共经历了三个版本, 第一个版本, 使用userspace用户空间代理; 第二个版本, 使用iptables代理; 第三个版本, 使用ipvs代理. 其实我们记录最后一个版本就可以, 但是, 我们要知道他们的变化.

第一代. userspace-用户空间代理模式

首先, 有一个kube-apiservier的组件, 有一个kube-proxy的组件(k8s的每一个node都会有一个kube-proxy组件)。 这两个组件的作用是什么呢?

kube-apiserver要被kube-proxy监听。也就是说, proxy会实时监听apiserver, 监听什么内容呢? 监听pod和svc的变化。比如有些pod死了,proxy要把这个pod移除掉。有些pod更新了, proxy也要跟着更新。监听到变化,就有可能要去修改对应的规则。

假设现在有一个客户端的pod想要去访问服务端的pod. 首先客户端的pod要访问到当前的防火墙规则. 防火墙规则是被谁修改的呢? 被kube-proxy组件修改的, 通过net-link接口. 访问到防火墙以后, 这个访问会被代理到当前所在机器的kube-proxy组件, 组件再把流量分发给pod1, 或者是pod2, 或者是pod3. 所以,所有的请求都要发到kube-proxy, 他帮我们去代理一下. 所以, 这时候kube-proxy的压力是很大的. 这有点像lvs-net模型. 流量经过了server, 但是他又不需要去搬运流量.

这就是第一种模式, kube-proxy的压力比较大.

第二代: iptables代理模式

第二代, 依然有kube-apiserver组件和kube-proxy组件. kube-proxy依然要监听apiserver, 进而监听pod和svc的变化. 当pod或者servic发生变化时, proxy会将变化信息通过net-link接口给到iptabls, 修改当前机器的防火墙规则. 规则更新以后, 当客户端pod要访问服务端pod的时候, pod会发送给防火墙, 只需要通过防火墙进行转发.

和第一代相比, kube-proxy的压力小了很多. 因为当前的访问流量不需要都经过他.

然而, iptabls和ipvs比较, 负载均衡方面还是要差一些的. 所以,第三代ipvs组件出现了.

第三代: ipvs代理模式

同样的, proxy组件要去监听apiserver, 进而监听pod和svc. 当有变化发生的时候, proxy会通过ipvs修改相应的规则. 客户端pod向服务端pod发出请求, 直接通过ipvs转发请求到服务端pod, 可以是pod1,也可以是pod2和pod3

以上三代, 最主要的区别是 第一代和第二代相比, 解放了kube-proxy, kube-proxy不用承担那么多的流量了 第二代和第三代相比, 是底层的流量转发机制从iptables变成了ipvs. ipvs就是我们现在最稳定的版本了.

如果配置ipvs呢?参考下一篇。

四层网络和七层网络

在第一代用户空间代理模式, 是典型的的4层代理. 她的kube-proxy也是实现的类似于lvs-net模型. 这里只是类似于, 不是真的用的lvs-net, 只是流量转发的方式很像. 说的简单点, 这里只有一次的tcp代理, 没有两次链接. 典型的是一个4层网络. 如果我们想实现7层的怎么办呢? 7层在很多场景下还是很有必要的, 比如https会话, 虚拟主机, 他们都需要有主机名和域名的实现. 这个怎么实现呢? 在v1.1版本中, 增加了一个ingress的接口, 用来表示7层的服务. 就相当于集群里做好了接口, 我们只需要把组件对接到接口上, 就可以帮我们实现8层代理. 这个组件可以是谁呢? 有很多, nginx, kube-proxy等只要是具备七层代理服务都可以在这里变成我们7层的工具. 后面会通过案例实现nginx的ingress版本. 也就是将nginx封装在接口里, 实现nginx的7层调度.

image.png

不适用dns作为负载均衡器

无论是后期的ingress接口,还是service的迭代过程, 从来都没有说过要基于dns实现负载均衡. 我们是知道的, dns是可以实现负载均衡的, 如果有多台服务器, dns可以以轮巡的方式实现负载均衡. dns作为负载均衡被废弃的原因有很多,其中一个是dns作为负载均衡器的时候, 有大量的缓存存在, 甚至现在很多供应商会做dns劫持. 比如: 买了一个带宽, 这个带宽不是大的供应商, 移动,联通,电信等. 买的小带宽, 比如铁通, 鹏博士, 他怎么盈利呢? 他要挂广告. 也就是请求访问一个网址, 解析的结果可能不是站点的原站, 而是做了dns污染, 这样可能会有的问题是, 服务端做的dns解析记录和真实用户的dns解析记录是不一样的. 而有些dns还会有缓存, 这样就更加影响调度访问了. 基于以上两点, 我们从来都没有考虑过使用dns作为k8s内部的调度方式.