开发者学堂课程【ALPD 云架构师系列:云原生 DevOps 36计-阿里云云效出品:环境管理3阶段:从说明书到命令到声明式】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/772/detail/13502
环境管理3阶段:从说明书到命令到声明式
内容介绍:
一. 说明书(文档)
二. 命令(脚本
三. 声明(配置)
一、说明书(文档)
不可执行,编辑文档的人和执行操作的人不是同一个人。
而且文档是不可执行的,不可验证的,说明这个软件是最新状态的。但是写软件的人并不应一定会去及时的去更新文档。同时,写软件的人即便更新了文档,这个文档是不是工作了,其实他没有办法得到及时的验证呢,因为他用不到。
二. 命令(脚本)
基础设施管理都有运维负责,Dev 和 Ops 是上下游的关系,界限分明
通过命令的方式,写各种脚本,然后把所有的命令组合在一起,作为一个批处理文件。
因为每次布置一个新环境都非常麻烦,需要花费大量时间在改参数,然后配各种各样的 ip 等。这种情况下效率太低,所以就可以写一个脚本去做这件事,这时脚本那就起着一个部署的作用。
但是这个脚本可能慢慢就会变的很多,因为要应对各种各样的环境。
比如说,有的环境可能是三个节点,但另外环境可能是十二个节点,这时就要改。很难做到很好的适配,可能还有网络差异,任何差异都会存在这个问题。所以我们就会写一系列的脚本,然后为各种情况去做控制。
如果要操作这个脚本,写脚本或者维护脚本一般都是慢慢开始的,需要有专人负责。然后这个技术设施就开始变成运维的一个工作,这个工作同时包括了怎么去做自动化运行脚本,甚至做一个平台。
开发是在前面,而运维在后面,这就是个上下游的关系,并且互相之间很分明。开发的时候 给的是一个镜像包或者是代码,而剩下的工作,比如怎么把它带上去,有哪些安全策略 这些东西全部都是运维的事情。
通过命令式的方式,我们会发现维护的成本是特别高的。而且相对来说,它是偏命令式的,就是说所有的东西,在不同的场景里,可能要写的命令是不一样的。这种组合或者场景,它的复杂度就会非常高,所有就需要做很多检查。这个检查是否符合预期,然后根据不同的反馈,做不同的判断,随着环境的种类越来越多,复杂度也越来越上升。
三. 声明(配置)
Dev 和 Ops 的界限变得模糊,很多基础设施的定义向左移,基础设施的的维护工作由K8S(或其他工具)标准化
1. 声明式与命令式最大的差别是什么?
命令式定义做什么。比如说,要配个ip地址,或者要把内存设为512G。
那么第三个阶段就是定义要什么,或者是什么。比如说,这个服务有两个副本,每个副本需要两个 CPU,然后可能其中一个对于内存还有网络有一些要求,那么这个是我给他定义的,所以我在这个第三个阶段所有的声明,其实声明的是个终态是什么样子的。
如果定义说需要三个节点,并且三个节点成本是最低的,那么这个声明就很明确了,这个就是声明的优势。
总之,命令式是把环境当做一个被怎么样的东西,是被操纵的。而声明式的更多是站在环境,或者站在应用服务本身来说需要什么,运行时是什么样的状态,去把这个东西给定义声明。
2. 声明式的描述
提供了环境的确定性表达
这里其实是两种不同的思维方式,声明式的描述提供了环境的确定性表达。就是描述是什么,那么环境就是什么。这是一个非常大的一个跨越。
声明式其实都是通过 k8s 来做,前面的练习也都通过 k8s来做。K8s 整个体系是怎么做这个事情的呢?
左上角的master 有好几个组件。它有一个 etcd 存储,各种各样的配置信息,其实都是在 k8s 里面的。下面的 node,就是真正的物理机或者虚拟机,跟他们通信是通过 API 去通信的。在每一个 node 上表示物理机,物理机上其实会引起很多个 Pod,然后 Pod 上面会运行很多的容器。这就是它的一个最简单的架构的样子
k8s 的那个最小单元是一个 Pod,Pod 里面会有容器,也会有各种像网络或者存储这样的东西。
Controller
#调用 APl server 的 list、watch 接口监听资源配置变化
for{
实际状态:=获取集群中对象
X
的实际状态
期望状态:=获取集群中对象X的期望状态
If
{
实际状态==期望状态
}
{
啥也不做}
else
{执行编排动作,将实际状态调整为期望状态}
}
这个其实就监听一个变化,比如说 API 里面,我有一个变化, 对于这个变化,就是告诉它我期望的一个状态。
那么controller那边就会去看我现在是什么状态,比如我现在的那个节点是一个,但是我希望有三个,那么我就会想我是不是要去再扩两个,他就会去逐步的去逼近这个目标状态,那么等他达到目标状态的时候就不做了。
所以,整个过程其实是一个逐步逼近的过程。我给他下发了一个声明,然后他把这个声明慢慢的逼近声明的条件和状态。所以说,其实环境的定义是面向终态的一个定义,这个是非常主要的一个特点,就跟我们之前的各种运维的手段,特点是很鲜明的,就是面向终态去设计的。
1.通过 sidecar 分离关注点
一般在一个应用开发的时候,关注点是什么?
如果写一个应用,然后把应用发到一个容器里,容器就跑起来。但是我们做开发,大家都知道在这个应用里面,大量的代码其实不是应应用业务代码。其实我们写了很多的,比如说服务的相关的东西,比如日志,模拟监控,熔断,各种各样的代码是占了很大的比重的。无论是用 sidecar 这样的框架,其实也会有这样的问题,就是有很多这样的代码,而这些代码的维护者和升级节奏跟应用开发者其实不是一波人。 通常情况下,像阿里肯定会去做这些事情,然后可能有些公司,可能是自己有专门的团队会去做这个事情,那么他们有不同的节奏和关注点。
传统情况下,其实我们如果要遇到这样的问题,就需要整个升级应用本身,才能达到这个效果。但是,在云原生时代,我们通常把它分离掉,就是把这个应用容器分离掉。我们应用开发者关心的就是应用业务代码,但这些服务相关的是放到其他容器里的,它会编排在同一个报道里面。但容器的管理,开发,发布都跟开发者没关系。这些就是属于 sidecar 容器,是我们可以通过注入的方式,或者在营业的行内来去配置的方式,放到我们的 Pod 里面跑起来,这样就实现了一个关注点的分离,就是说我作为应用的开发者和我的中间件的开发者,以及一些业务运维相关的一些开发者,那我可以有自己的关注点,而不需要互相之间有偶合性。
如果你是一个业务的开发者的话,你关注的是这个应用的容器。所以说你的发布的节奏,你的所有中心,你的关注点都在发布容器这一块的应用容器。
如果你是一个运维同学的话,无论是应用运维或者是基础设施运维,那你的关注点基本上会在这一块。你在这个 Pod 里头相应的会提供哪些服,比如你对 Log Colletor 这样的一些东西有你自己的节奏,这样的话大家的关注点就分离开了。
而且分离开来还有一个好处,就是我们中间下沉之后,都会这种方式来去管理。这样一旦遇到相应的一些中间件需要升级的时候,这时你的业务代码是不需要做任何改变和任何发布的,而只需要去做一个 sidecar 的发布就好了。
通过这样可以去分离关注点。前面我们提到了几点,就是一致的环境需要有三个部分,一个是相同的制品,一个是相同的运行上下文,还另外相同的编排规则。其相同的运行上下文,其本质就是这里有很多相应的一些配置。
那刚才了解到传统的,我们从以前的文档式的告诉我们应该怎么把环境弄起来,到按脚本的这种方式。然后我们发现其实声明式不是特别完美的,它也有一些问题,就是每一个新技术的引入都会带来好的地方之后,同时带来一些成本问题。举一个很具体的例子,就是声明式的话,可能针对应用运行的时候,声明式需要相应的一些配置。