一文让你了解Kubernetes架构与核心概念

本篇文章我会探讨Kubernetes的整体架构与核心概念。

架构

与很多基础设施领域现有工程实践、后有方法论的发展路线不同,Kubernetes项目的理论基础则要比工程实践走得靠前许多,这要归功于Goole公司在2015年4月发布的Borg论文。Borg系统一直以来被誉为Google内部最强大的”秘密武器“。

一文让你了解Kubernetes架构与核心概念


本图源于Google Omega论文第一作者,马尔特施瓦茨科普夫的博士论文

从此图可以看出相比Dapper、BigTable等相对上层项目,Borg要承担的责任是承载Goole公司整个基础设施的核心依赖。所以Borg项目当仁不让居整个基础设施技术栈的最底层。

正犹豫这样的定位Borg可以说是Google最不可能开源的一个项目。而幸运的是,得益于Docker项目和容器技术的风靡,它以另一种方式与开源社区见面,这个方式就是Kubernetes。

一文让你了解Kubernetes架构与核心概念

Kubernetes项目的架构与它的原型项目Borg非常类似,都由Mater和Node两种节点组成,而这两种角色分别对应着控制节点和计算节点。

控制节点即Master节点,由三个紧密协作的独立组件组合而成,它们分别是负责API服务的kube-apiserver、负责调度的kube-scheduler,以及负责编排的kube-controller-manager。整个集群的持久化数据,则由kube-apiserver处理后保存在Etcd中。

计算节点上最核心的部分是叫做kubelet的组件。在Kubernetes项目中,kubelet主要负责与容器运行时打交道。而这个交互所以来的是一个称作CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的各项核心操作,比如:启动一个容器所需的所有参数。这也是为什么Kubernetes项目并不关心你部署的是什么容器。

kubelet另一个重要的功能是调用网络插件和存储插件,为容器配置网络和持久化存储。这两个插件与kubelet进行交互的接口,分别是CNI(Container Networking Interface)和CSI(Container Storage Interface)。

从这些设计来看,Kubernetes项目从一开始就没有想各种”容器云“项目那要把Docker作为整个架构的核心,而只是把它作为底层的一个容器运行时的实现。对于Kubernetes项目定位与重点要解决的问题,Borg的研究员在论文中也给出非常重要的观点:

运行在大规模集群中的各种任务之间,实际上存在着各种各样的关系。这些关系的处理,才是作业编排和管理系统最苦难的地方。

Pod

Kubernetes项目主要设计思想是从更宏观的角度,以统一的方式来定义任务之间的各种关系,而且为将来支持更多种类的关系留有余地,拥有更好的普适性。

所以有一些抽象的设计概念,在常规环境下,这些应用往往会被直接部署在统一机器上,通过Localhost通信,通过本地磁盘目录交换文件。而在Kubernetes项目中,这些容器则会被划分为一个”Pod“,Pod里的容器共享同一个Network Namespace、同一组数据卷,从而达到高效率交换信息的目的。

为什么设计出Pod

容器的本质是进程,容器的镜像就类似操作系统的安装包,那边Kubernetes就好比操作系统。又因为操作系统中的进程并不是独自运行的,而是以进程组的方式组织在一起。其实Kubernetes就是将”进程组“的概念映射到容器技术中,并使其成为云计算”操作系统“的原子调度单位。

容器的本质就是进程,Pod就类似进程组的概念,所以Pod是K8s的一等公民。

Pod的实现原理

关于Pod最重要的一个事实是:Pod只是一个逻辑概念。也就是Kubernetes真正处理的还是宿主机操作系统上的Linux容器Namespace和Cgroups,而不存在一个Pod的边界或者隔离环境。其实就是共享了某些资源的容器,Pod里的所有容器共享的是同一个Network Namespace,而且可以声明共享同一个Volume。

一文让你了解Kubernetes架构与核心概念

Pod的实现需要一个中间容器,这个容器叫做Infra容器,在Pod中,Infra容器永远是第一个被创建的容器,而其他用户定义的容器则通过Join Network Namespace 的方式,与Infra容器关联在一起。这个容器叫做:k8s.gcr.io/pause,永远处于”暂停“状态的容器,占用极少的资源解压后也只有100~200KB。

在同一个Pod中,也就可以理解:

  • Pod中的容器可以直接使用localhost进行通信;
  • 它们看到的网络设备跟Infra容器看到的完全一样;
  • 一个Pod只有一个IP地址,也就是这个Pod的Network Namespace对应的IP地址;
  • Pod的生命周期只跟Infra容器一致,而与容器A和B无关;

Sidecar设计模式

通过”组合“方式,来解决容器与容器间的耦合关系的问题,这种容器设计模式最常用的一种模式,名字就叫sidecar,就像摩托车旁边的边车一样,对摩托车没有任何侵入性。Pod除了可以共享Volume来完成日志收集的sidecar模式,还有一个重要的特性是共享同一个Network Namespace。这使得很多与Pod的网络相关配置与管理,也可以交给sidecar完成,而无需干涉用户容器,这里最典型的例子莫过于Istio这个微服务治理项目了。

Pod的重要字段含义

NodeSelector:是一个供用户将Pod和Node进行绑定的字段。

apiVersion: v1
kind: Pod
...
spec:
 nodeSelector:
  distype: ssd

这样配置意味着Pod永远只能运行在携带了“disktype:ssd”标签(Label)的节点上,否则它将调度失败。

NodeName:一旦Pod的这个字段被赋值,Kubernetes项目就会被认为这个Pod已经经过了调度,调度的结果就是赋值的节点名字。所以这个字段一般由调度器负责设置,但用户可以设置它来“骗过”调度器,这样做一般在测试时候才会用到。

HostAliases:定义了Pod的hosts文件(比如/etc/hosts)里的内容,比如:

apiVersion: v1
kind: Pod
spec: 
 hostAliases:
 - ip: "10.1.2.34"
  hostname:
   - "foo.remote"
   - "bar.remote"
...

会发现凡是和容器的Linux Namespace相关的属性,也一定是Pod级别的。这个原因也是很容易理解:Pod的设计,就是让它里面的容器尽可能多共享Linux Namespace,仅保留隔离和限制的能力。这样Pod模拟出的效果,就类似虚拟机里程序关系非常类似。

Pod在Kubernetes的生命周期

Pod生命周期的变化,主要体现在Pod API对象的Status部分,这是它除了Metadata和Spec之外第三个重要的字段。其中,pod.status.phase,就是Pod的当前状态,有以下几种可能的情况:

  1. Pending。这个状态意味着Pod的YAML文件已经提交给Kubernetes,API对象已经被创建并保存在Etcd中,但是这个Pod里有些容器因为某种原因不能顺利创建。比如:调度不成功。
  2. Running。这个状态下,Pod已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,而且至少一个正则运行中。
  3. Succeeded。这个状态意味着Pod里面所有容器都运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
  4. Failed。这个状态意味着,Pod里至少有一个容器以不正常状态退出。这个状态出现,意味着你得想办法debug这个容器,比如查看Pod的Events和日志。
  5. Unkown。这是一个异常状态,意味着Pod的状态不能持续被kebelet汇报给kube-apiserver。

Pod配置之容器健康检查和恢复机制

在Kubernetes中可以为Pod里的容器定义一个健康检查“探针”(Probe)。这样kubelet就会根据这个Probe的返回值决定这个容器的状态,而不是以容器运行状态作为依据。这种机制是生产环境中保证应用健康存活的重要手段。

当容器通过健康检查发现是不健康的,Pod并没有进入Failed状态,你注意到restarts字段从0到1发生了变化,原因就是异常的容器被Kubernetes重启了。

需要注意的是:Kubernetes中并没有Docker的Stop语义。所以虽然是Restart但实际却是重新创建了容器,这个功能就是Kubernetes里Pod的恢复机制,也叫restartPolicy。它是Pod的Spec部分的一个标准字段(pod.spec.restartPolicy),默认值是Always,即:任何时候这个容器发生异常,它一定会被重新创建。

还可以通过设置restartPolicy,改变Pod的恢复策略。除了Always还有OnFailure和Never两种情况:

  • Always:在任何情况下,只要容器不在运行状态,就自动重启重启;
  • OnFailure:只在容器异常时才自动重启容器;
  • Never:从来不重启容器。

在实际使用时,我们需要根据应用运行的特性,合理设置这三种恢复策略。

StatefulSet

Deployment实际上并不足以覆盖所有的应用编排问题,造成这个问题根本原因在于Deployment对应用做了一个简单化假设。它认为一个应用的所有Pod是完全一样的。所以它们互相之间没有顺序,也无所谓运行在哪台宿主机上。需要的时候,Deployment就可以通过Pod模板创建新的Pod,不需要的时候Deployment就可以“杀掉”任意一个Pod。

但在实际场景中,并不是所有的应用都可以满足这样的要求。尤其是分布式应用,它的多个实例之间,往往有依赖关系。比如:主从关系、主备关系。所以,这种实例之间有不对等关系以及实例对外部数据有依赖关系的应用,就被称为“有状态应用”(Stateful Application)。

得益于“控制器模式”的设计思想,Kubernetes项目很早就在Deployment的基础上,扩展出了对“有状态应用”的初步支持。这个编排功能就是:StatefulSet。StatefulSet的设计其实非常容易理解。它把真实世界里的应用状态,抽象为两种情况:

  1. 拓扑状态。这种情况意味着,应用的多实例之间不是完全对等的关系,这些实例必须按照某些顺序启动。
  2. 存储状态。这种情况意味着,应用的多个实例分布绑定了不同的存储数据,对于这些应用实例来说,Pod A第一次读取到的数据,和隔了10分钟之后再读取到的数据应该是同一份数据,最简单的例子就是数据库应用多实例部署。

所以,StatefulSet的核心功能,就是通过某种方式记录这些状态,然后在Pod被重新创建的时候,能够为新的Pod恢复这些状态。

Headless Service概念

所谓Headless Service,其实仍然是一个标准的Service YAML文件,只不过它的clusterIP字段的值是:None,即这个Service 没有一个VIP作为“头”,这也就是Headless的含义,所以这个Service被创建并不会分配一个VIP,而是以DNS记录的方式暴露出它所代理的Pod。在创建StatefulSet时,和普通deployment唯一的区别除了kind不一致以外,唯一区别就是多了个serviceName=nginx字段。

这个字段作用就是告诉StatefulSet控制器,在执行控制循环(Control Loop)的时候,请使用nginx这个Headless Service来保证Pod的”可解析身份”。当我们把StatefulSet的两个Pod删除后,Kubernetes会按照原先编号的顺序,创建出了两个新的Pod。并且Kubernetes依然为它们分配了与原来相同的“网络身份”。

通过这种严格的对应规则,StatefulSet就保证了Pod网络标识的稳定性。通过这种方法,Kubernetes就成功地将Pod的拓扑状态(比如:哪个节点先启动,哪个节点后启动),按照Pod的“名称+编号”的方式固定了下来。此外,Kubernetes还为每一个Pod提供了一个固定而且唯一的访问入口,即:这个Pod对应的DNS记录。这些状态在StatefulSet的整个生命周期里都会保持不变,绝不会因为对应Pod的删除或者重新创建而失效。

所以,StatefulSet其实可以认为是对Deployment的改良。

DeamonSet

DaemonSet的主要作用,是让你在Kubernetes集群里,运行一个Daemon Pod,所以这个Pod有如下三个特征:

  1. 这个Pod运行在Kubernetes集群里的每一个节点(Node)上;
  2. 每个节点上只有一个这样的Pod实例;
  3. 当有新的节点加入Kubernetes集群后,该Pod会自动地在新节点上被创建出来;而旧的节点被删除后,它上面的Pod也相应地会被回收掉;

DaemonSet其实是一个非常简单的控制器,在它的控制循环中,只需遍历所有节点,然后根据节点是否有被管理Pod的情况,来觉得是否创建或者删除Pod。只不过在创建Pod的时候,DaemonSet会自动给这个Pod加上nodeAffinity,从而保证这个Pod只会在指定节点上启动。同时它还会自动给这个Pod加上一个Toleration,从而忽略节点的”污点”,从而实现自己的目的。


参考

https://juejin.cn/post/6844903959052681223 http://jartto.wang/2020/07/15/start-k8s/


原文始发于微信公众号(程序猿阿南):一文让你了解Kubernetes架构与核心概念

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/22337.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!