背景
前不久公司领导跟我聊天,
K8S
是什么? 它能干什么?
二话不说,直接搬出概念,它的本质是工业级编排平台,负责容器的弹性、管理和编排。
我之前没有怎么接触
K8S
相关的概念,啥是容器?怎么弹性?如何管理和编排?
容器是利用了集装箱的思想,把可运行程序打包成可运行、自包含、标准化的镜像。通过K8S
能够管理和编排我们打的镜像,举例来说,如果你想运行两个副本,直接在编排文件中配置replicas
为2
即可,你也可以使用HPA
通过检测CPU
、内存使用率实现自动扩缩容。
又是镜像,又是编排,引入这么多新概念,能
hold
住?你就给我说说,它和SpringCloud
、dubbo
...等微服务框架有什么不同?
SpringCloud、dubbo
等框架和K8S
切入点不同,K8S
能够支撑所有框架和语言,并提供了平台级别的服务;而SpringCloud
仅仅是整合了Java
库以及各种运行时概念,是通过JVM
级别来管理的。
到此结束吧,说到底,还是没有讲清楚它的本质、不能用通俗易懂的语言说清楚
K8S
到底是什么!
对于一个没有接触到云原生概念的人,如何讲清楚云原生时代的操作系统K8S
到底是什么?和普通微服务框架有什么区别?如果问我K8S
中的核心组件的功能,又该如何解答?
后来仔细想了想, 可以把K8S
比喻成一栋精装修大楼,每间都是统一的标准,拎包入住即可;而其它的一些微服务框架则可以看作毛坯房,需要各种定制化,无法做到开箱即用,至于精装修是否适合自己,还要看自己房子的数量。
就本人而言是不喜欢拿IT
技术打比方的,因为IT
技术是一门严谨的科学,通过打比方的方式,虽然能够对一门技术有个大致的了解,但是不能从根本上搞明白核心技术点,从而不能起到关键性帮助,有时还会造成曲解。所以直接抠概念中核心关键点文档即可。
本文会用本人自己通俗的语言叙述K8S
中核心组件的概念,概念段落中黑体字会用浅显易懂的语言描述该概念,紧接着会进一步解释该组件的功能。适用于K8S
小白,如果你是高手,出门左转,不送!
Controller-控制器
- 宏观上来说
控制器本质上就是一个死循环,不断获取实际状态,然后跟期望状态做对比,通过对比决定下一步的操作;如果跟实际状态一致,维持现状,否则将实际状态调整为期望状态。
控制器基本架构
- 微观上来说
控制器的设计原理是用一种对象控制另一种对象的艺术。
从编排文件看控制器设计模式
另外我们在一些架构图中经常看到kube controller manager
和cloud ontroller manager
,其中kube controller manager
就是我们常见的有Pod
控制器、Deployment
控制器....的实现。cloud ontroller manager
是对route
控制器、Service
控制器,之所以会出现cloud mananger controller
是因为在不通的云环境中、控制器的实现会因为云厂商、环境的不同,存在一定的差别。
总结来说,控制器就是整个集群的大脑,有了控制器才能使集群更加智能。
Scheduler-调度器
从大体上来说,是一个择优而居的过程,调度器就是为Pod
选择一个合适Node
,让Pod
的定义的任务在这个node
上顺利完成。
整个过程如下图:
Informer Path
第一个控制循环我们称之为Informer Path
,它启动一系列的Informer
,用来监听etcd
中Pod、Node、Service
等资源对象的变化,并通过Informer Handler
把待调度Pod
加入的到优先级队列,Node
等信息缓存到Cache
中。
Informer
是Client-go
中的一个核心工具包。内部实现极其复杂,简单来说是一个依赖K8s List/watch API
,可以监听事件并触发回调函数的工具包。Priority Queue K8s
的调度队列,之所以在这里添加调度队列主要是出于对调度优先级和抢占的考虑,通过使用调度队列可以对调度中的内容做特殊操作。Scheduler cache
调度器缓存,最大程度上将集群信息缓存化,提高Predicte
调度算法的执行效率。
Scheduling Path
第二个控制循环是调度器负责Pod
调度的主循环,称之为Scheduling Path
,主要逻辑就是不断的从队列里拿出Pod
,然后调用Predictates
进行过滤,这一步的过滤是得到一组满足条件的Node
,当然这些Node
都是从cache
中直接拿到的,接下来再调用Priority
算法为上述列表中的Node
打分,分数从0-10
,得分最高的Node
将会被选中。调度算法完成后需要将Pod
和NodeName
进行绑定,这个过程就是最后一步Bind
,当然这个Bind
只是更新缓存中绑定信息,称之为乐观绑定。
Predicates
在调度过程中的作用,可以理解为filter
,它按照调度策略,从集群节点中过滤出一系列符合条件的节点。这些节点都是可以运行待调度Pod
的宿主机。Priorities
阶段的工作主要就是为这些节点大根,这个打分的范围是0-10
分,得分最高的节点就是Pod
绑定的最佳节点。
APIServer
对比Kubernetes
和单机操作系统,Kubernetes
相当于操作系统,控制着整个集群硬件资源管理,并提供统一的入口,用户可以通过这个入口使用集群、这个入口正是API Server
,通过这个入口,使我们才能进入K8S
内部操作其资源对象。
集群入口
举个例子,一个Pod
从提交到运行时序图,如下所示:
- 提交一个
yaml
编排文件到APIServer
APIServer
会把创建Pod
编排文件信息透传到etcd
数据库中- 调度器
Scheduler
通过listandwatch
观察到有新的Pod
需要调度,调度器会为这个Pod
寻找一个合适的节点并放置上去,并且把节点信息回传到APIServer
保存到etcd
中 Kubelet
发现有一个Pod
调度到自己所在节点,会进行docker run
操作启动服务,并且把Pod
状态信息回传给APIServer
,最终APIServer
把Pod
信息记录到etcd
中。
通过这幅图可以看出一个Pod
在创建过程,除了APIServer
之外,其它组件之间的通信都要经过APIServer
。但是你可能会产生一个疑问,控制器呢?请看下图,控制器正是保证和控制服务正常运行的大脑。
Kubernetes控制平面
etcd
etcd
etcd
是一个分布式,可靠的key value存储系统,它用于存储分布式系统中的关键数据。得益于etcd
自身的租约、历史数据版本控制等机制,Kubernetes
自身状态数据流转到etcd
中,Kubernetes
自身不在需要处理复杂的状态数据,从而简化Kubernetes
自身架构。
一个
etcd
集群,通常会由3
个或者5
个节点组成,多个节点之间,通过一个叫做Raft
一致性算法的方式完成分布式一致性协同,算法会选举出一个主节点作为leader
,由leader
负责数据的同步与数据的分发,当leader
出现故障后,系统会自动地选取另一个节点成为leader
,并重新完成数据的同步与分发。客户端在众多的leader
中,仅需要选择其中的一个就可以完成数据的读写。其内部机制非常复杂,采用B 树数据存储,但是对外提供接口非常简单,我们可以直接通过HTTP
协议进行访问。
ETCD
中主要使用使用场景有选主、并发控制进程执行、服务发现(租约检测节点存活}、版本机制控制历史数据
总结
本文主要是通过通俗易懂的语言描述了K8S中核心组件的功能以及用途,使其看起来简单,但内部执行流程及细节却是非常复杂,本人目前也正在阅读和实践client-go
的源码,后续会有输出,欢迎有兴趣的同学,关注公众号、加我微信一起讨论。