[Kubernetes]编排其实很简单
什么是编排 |
Kubernetes中,我们总是在说一个概念:编排.
在[Kubernetes]谈谈Kubernetes的本质这篇文章中,关于"编排"的概念介绍了一下:过去很多集群管理项目所擅长的都是把一个容器,按照某种规则,放置在某个最佳节点上运行起来,这种功能我们称为"调度".但Kubernetes项目所擅长的,是按照用户的意愿和整个系统的规则,完全自动化处理好容器之间的各种关系,这种功能,叫做编排.
这篇文章就尝试来讲一下,编排.
编排是如何实现的 |
不知道你对kube-controller-manager这个组件还有没有印象.这个组件实际上就是一系列控制器的集合.而Deployment,正是一系列控制器集合中的一种.
咱们来举个例子,来解释一下Deployment的作用.现在定义一个nginx的YAML文件,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
我们可以看到,这个Deployment定义的编排动作非常简单,要做的就是:确保携带了app=nginx标签的Pod的个数,永远等于spec.replicas指定的个数,即2个.
这意味着,如果在这个集群中,携带app=nginx标签的个数大于2的时候,就会有旧的Pod被删除;反之,则会有新的Pod被创建.
在这里,我们需要提到一个概念:控制循环.我先上一段伪代码,来描述一下控制循环概念:
for {
实际状态 = 获取集群中对象 X 的实际状态(Actual State)
期望状态 = 获取集群中对象 X 的期望状态(Desired State)
if 实际状态 == 期望状态{
什么都不做
} else {
执行编排动作,将实际状态调整为期望状态
}
}
应该能够看出,实际状态往往来自Kubernetes集群本身.而期望状态,一般来自于用户提交的YAML文件.基于上面的伪代码,来讲讲,Deployment是如何实现控制循环的.
- 1,Deployment控制器从Etcd中获取到所有携带了"app:nginx"标签的Pod,然后统计它们的数量,这就是实际状态;
- 2,Deployment对象的Replicas字段的值就是期望状态;
- 3,Deployment控制器将两个状态作比较,然后根据比较结果,确定是创建Pod,还是删除已有的Pod
通过以上,我们可以看到,主要编排逻辑,实际上是在第三步"对比"阶段完成的.这个操作,就是指:控制循环.
控制循环的结果就是,对被控制对象的某种写操作.比如,增加Pod,删除Pod,都是对对象的一些操作.也算是Kubernetes项目"面向API对象编排"的一个直观体现.
控制器的完整实现 |
上面只是一个概述.这一部分详细讲讲控制器的完整实现:Deployment.
Deployment看似简单,但实际上,它实现了Kubernetes项目中一个非常重要的功能:Pod的"水平扩展/收缩".
比较难以理解?没关系,咱们来举个例子.假设更新了Deployment的Pod模板(比如,修改了容器的镜像),那么Deployment就需要遵循一种叫做"滚动更新"的方式,来升级现有的容器,而这个能力的实现,依赖的是Kubernetes中一个非常重要的API对象:ReplicaSet.它的组成也很简单:副本数目的定义和一个Pod模板.
我们可以发现,所谓的ReplicaSet对象,其实是Deployment的一个子集.而实际上,Deployment控制器实际操纵的,正是这样的ReplicaSet对象,而不是Pod对象.
在这个基础上,咱们一起来分析一下下面的这个Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
从上面我们可以看到,这就是一个nginx-deployment,它定义的Pod副本个数是3(spec.replicas=3).具体实现是这样的:
这样我们就能很清楚的看到了,Deployment,ReplicaSet,Pod之间,是一种"层层控制"的关系.ReplicaSet负责通过"控制器模式",保证系统中Pod的个数永远等于指定的个数.这也是在Deployment中,为什么只允许容器的restartPolicy=Always的原因:只有在容器能保证自己始终是Running状态的前提下,ReplicaSet调整Pod的个数才有意义.
在此基础上,Deployment同样通过"控制器模式",来操作ReplicaSet的个数和属性,进而实现"水平扩展/收缩"和"滚动更新"这两个编排动作."水平扩展/收缩"非常容易实现,Deployment Controller只需要修改它所控制的ReplicaSet的Pod副本个数就可以了.而在"滚动更新"这个动作中,它有一个状态转换的过程:
- DESIRED:用户期望的Pod副本数(spec.replicas的值);
- CURRENT:当前处于Running状态的Pod的个数;
- UP-TO-DATE:当前处于最新版本的Pod的个数,就是说,Pod的Spec部分与Deployment中Pod模板里定义的完全一致;
- AVAILABLE:当前已经可用的Pod的个数,即:既是Running状态,又是最新版本,并且已经处于Ready(健康检查正确)状态的Pod的个数
我们可以看到,只有AVAILABLE字段,描述的才是用户所期望的最终状态.
在ReplicaSet的DESIRED,CURRENT和READY字段的含义,和Deployment中是一致的.相比Deployment和ReplicaSet,Deployment只是添加了UP-TO-DATE这个跟版本有关的状态字段.
也就是说,如果我们修改了Deployment的Pod模板,"滚动更新"就会被自动触发.
修改Deployment有很多方法,在这里就不说了.我想详细讲述一下"滚动更新"的过程.
滚动更新的详细过程 |
在这一部分,我详细讲述一下"滚动更新"这个过程.这样,会对"滚动更新"的好处,有一个比较好的理解.
来个小前提:假设我需要"滚动更新"3个Pod.
当我修改了Deployment里的Pod定义之后,Deployment Controller会使用这个修改后的Pod模板,创建一个新的ReplicaSet,此时这个ReplicaSet的初始Pod副本数是:0;
然后,Deployment Controller开始将这个新的ReplicaSet所控制的Pod副本数从0个变成1个,即:"水平扩展"出一个副本;
紧接着,Deployment Controller又将旧的ReplicaSet所控制的旧Pod副本数减少一个,即:“水平收缩"成两个副本.
如此交替进行,新ReplicaSet管理的Pod副本数,从0个变成1个,再变成2个,最后变成3个.与此同时,旧的ReplicaSet管理的Pod副本数则从3个变成2个,再变成1个,最后变成0个.
像这样,将一个集群中正在运行的多个Pod版本,交替地逐一升级过程,就是"滚动更新”
在你详细了解"滚动更新"的过程之后,你就会对它所带来的好处,有一个好的了解.
比如,在升级刚开始的时候,集群里只有1个新版本的Pod,如果这个时候,新版本Pod有问题启动不起来,那么"滚动更新"就会停止,允许开发和运维人员介入解决问题,而这个应用本身还有两个旧版本的Pod在线,所以服务不会受到太大的影响.
想和大家分享的内容,讲的差不多了
以上内容来自我学习<深入剖析Kubernetes>专栏文章之后的一些见解,有偏颇之处,还望指出.
感谢您的阅读~
[Kubernetes]编排其实很简单的更多相关文章
- Unity3D入门其实很简单
在上次发布拙作后,有不少童鞋询问本人如何学习Unity3D.本人自知作为一名刚入门的菜鸟,实在没有资格谈论这么高大上的话题,生怕误导了各位.不过思来想去,决定还是写一些自己的经验,如果能给想要入门U3 ...
- [.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office
打造一个很简单的文档转换器 - 使用组件 Spire.Office [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6024827.html 序 之前,& ...
- MVC其实很简单(Django框架)
Django框架MVC其实很简单 让我们来研究一个简单的例子,通过该实例,你可以分辨出,通过Web框架来实现的功能与之前的方式有何不同. 下面就是通过使用Django来完成以上功能的例子: 首先,我们 ...
- 【结果很简单,过程很艰辛】记阿里云Ons消息队列服务.NET接口填坑过程
Maybe 这个问题很简单,因为解决方法是非常简单,但填坑过程会把人逼疯,在阿里云ONS工作人员.同事和朋友的协助下,经过一天的调试和瞎捣鼓,终于解决了这个坑,把问题记下来,也许更多人在碰到类似问题的 ...
- 自定义View其实很简单系列1-12
作者: AigeStudio http://blog.csdn.net/aigestudio 说明:文中的1/12表示12篇中的第1篇, 1/6=2/12表示12篇中的第2篇,其它类似. 自定义控件 ...
- 踢爆IT劣书出版黑幕——由清华大学出版社之《C语言入门很简单》想到的(1)
1.前言与作者 首先声明,我是由于非常偶然的机会获得<C语言入门很简单>这本书的,绝对不是买的.买这种书实在丢不起那人. 去年这书刚出版时,在CU论坛举行试读推广,我当时随口说了几句(没说 ...
- java 调用 C# 类库搞定,三步即可,可以调用任何类及方法,很简单,非常爽啊
java 调用 C# 类库搞定,三步即可,可以调用任何类及方法,很简单,非常爽啊 java 调用 C# 类库搞定,可以调用任何类及方法,很简单,非常爽啊 总体分三步走: 一.准备一个 C# 类库 (d ...
- Crumpet – 使用很简单的响应式前端开发框架
Crumpet 是一个简单的响应式的基于 SASS/SCSS 的响应式前端框架,保持你的 HTML 代码简洁.内置尽量使用占位符选择器,以减少你的 HTML 标记的大小,没有凌乱的 HTML 代码.快 ...
- 其实Unix很简单
很多编程的朋友都在网上问我这样的几个问题,Unix怎么学?Unix怎么这么难?如何才能学好?并且让我给他们一些学好Unix的经验.在绝大多数时候,我发现问这些问题的朋友都有两个特点: 1)对Unix有 ...
随机推荐
- MySql数据库在NodeJS中简单的基本操作
阅读目录 一:连接数据库 二:数据的增删改查操作 2.1 数据库新增和查询数据 2.2 获取该数据的主键值 2.3 多语句查询 回到顶部 一:连接数据库 const mysql = require(' ...
- 一位月薪1.2w的北漂程序员真实生活!
“ 每个人都有一条生活道路.千万人,千万条,各不相同,各有特点.但是并不是好人都有一条好路,坏人都有一坏路.有的时候却恰恰相反.这虽然不是历史的必然,但却是客观社会存在的.今天咱们说的这部书是发生在当 ...
- Sqlserver查询死锁及杀死死锁的方法
-- 查询死锁 select request_session_id spid, OBJECT_NAME(resource_associated_entity_id) tableName from sy ...
- Vs2010项目升级到Vs2015时的一些修改
之前的C++/cli项目, Civil 3D版本为2014, 现在需要升级到2018版, 在升级的过程中遇到了一些问题: 为了备忘, 记录如下: Vcproj文件中进行了一些修改, 为了跟多版本项目的 ...
- MySQL——修改一个表的自增值
语句 alter table <table name> auto_increment=<value>; 示例 mysql; Query OK, rows affected (0 ...
- meta标签补充属性(viewport)
我们在开发移动设备的网站时,最常见的的一个动作就是把下面这个东西复制到我们的head标签中: <meta name="viewport" content="widt ...
- 【POJ 1740】A New Stone Game
这真是一道博弈论的好题啊 还是采用OI届的惯用套路,从简单想起 如果只有一堆石子,那么一定先手必胜 如果有两堆石子,那么我们考虑如下两种情况 2.1 两堆石子数量相同,那么无论先手怎么拿,后手都有一种 ...
- 洛谷 P3455&BZOJ1101 【[POI2007]ZAP-Queries】
这应该是入坑莫比乌斯反演的第一道题了吧 其实题目让我们求的东西很简单,就是 \[ ans=\sum_{i=1}^{a}\sum_{j=1}^{b}\left [ gcd(i,j)=k \right ] ...
- 使pre的内容自动换行(转)
<pre> 元素可定义预格式化的文本.被包围在 pre 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre> 标签的一个常见应用就是用来表示计算机的源代码 ...
- 用不用lambda,这是一个问题
用不用lambda,这是一个问题 mp.weixin.qq.com Sun在2009年开启了代号为“dolphin”的工程,计划在JDK1.7中加入lambda表达式.虚拟机模块化支持.动态语言支持 ...