当我们认识的k8s的时候,我们第一个认识的是pod,那么我觉得第二个认识的应该就是Deployment了。作为k8s中一个非常常见的对象,今天我们来看看它的实现原理和设计思想。

PS: 本文需要你对pod的定义和理解有一定的基础

定义

在k8s中,对象常常都是以一个yaml格式的文件来定义的,deployment也不例外。如果你对k8s还不是特别了解,你大可以将一个文件看做是一个对象的所有属性,每个属性都有对应的值,其实也并不复杂。deployment的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 定义版本
apiVersion: apps/v1
# 定义类型
kind: Deployment
# 定义名称和标签
metadata:
name: nginx-deployment
labels:
app: nginx
# 定义规格
spec:
replicas: 2
selector:
matchLabels:
app: nginx
# 定义模板
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

我也不知道网上为什么都用nginx来写这个例子,总之我拿来加上了一些注释,你就可以很清楚的看到它到底在定义些什么东西了。(其实整个deployment也并不复杂)

除了名字和标签类型是对于deployment的定义外,下面的规格就是deployment长得样子。而这里的模板是一个pod的模板,定义了pod的样子。

要点1:从定义上我们可以明显的看出 deployment 并不是直接控制的 pod ,其中在规格中的定义是 replicas ,所以控制其实是 ReplicaSet,由 ReplicaSet 去控制 pod

使用

  • 通过 kubectl create -f deploy-nginx.yml 命令可以创建这个 Deployment
  • 通过 kubectl get rs 命令查看 ReplicaSet 的情况
  • 通过 kubectl get pods 命令查看 Pod 的情况
1
2
3
4
5
6
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54f57cf6bf 2 2 2 75s

NAME READY STATUS RESTARTS AGE
nginx-deployment-54f57cf6bf-mjqw9 1/1 Running 0 4s
nginx-deployment-54f57cf6bf-pvtkq 1/1 Running 0 4s

特点

看完了定义和使用,我们再来看看它有什么特点

删除pod

我们可以通过 kubectl delete pod nginx-deployment-54f57cf6bf-mjqw9 命令删除一个 pod

然后我们再去查看当前 pod 的情况

1
2
3
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-54f57cf6bf-4scrb 1/1 Running 0 43s
nginx-deployment-54f57cf6bf-pvtkq 1/1 Running 0 5m

我们会惊奇的发现,它又重新创建了一个pod

要点2:Deployment 会维护pod的数量,一旦不满足数量的定义需求,就会进行创建

删除rs

我们可以通过 kubectl delete rs nginx-deployment-54f57cf6bf 命令删除一个 rs

然后我们去看 rs 和 pod,你就会发现它又重新帮你创建了

要点3:Deployment 会维护 ReplicaSet

扩容

说完了删除,那我们想要扩容怎么办呢?我现在要把pod变成3个

  • 方式1 修改yml文件,将2改为3;然后使用 kubectl apply -f deploy-nginx.yml
  • 方式2 直接使用命令 kubectl scale deploy nginx-deployment --replicas=3
  • 方式3 直接使用命令 kubectl edit deploy nginx-deployment 修改 replicas: 3

要点4:这些方式都可以完成扩容缩容的效果,同时还可以修改别的属性,如nginx版本等

设计模式

说完了定义和特点,来说说deployment的设计

控制器模式

这个设计模式其实在k8s中很常见,由A控制B,由B控制C,k8s没有让我们直接去控制pod,而是通过 deployment 去控制,而 deployment 其实也不是实际干活的,其实实际干活的是 ReplicaSet,有这样的控制链路组成的控制器模式。

1
2
3
4
graph LR;
Deployment-->ReplicaSet;
ReplicaSet-->Pod1;
ReplicaSet-->Pod2;

这样一层层的控制能让我们更清晰的去控制我们的最终要的结果,同时让最终结果的控制变得简单。

滚动更新模式

在使用中我们觉得非常好用的原因是,我们只要修改参数,就能获得水平扩容缩容的效果,非常简单,而这对于需要水平扩展的服务来说这无疑是非常重要的。

如果在以前,你需要水平扩展你的应用,你就需要复制一个你应用,或者说复制一个tomcat,然后修改各种配置避免冲突,如果服务挂了你需要手动去重新启动….

而k8s设计在于,你只需要描述目标状态是什么,就能帮你维护目标状态的样子,不对了我会自动帮你进行调整。你的任何更新都会及时被反映到状态中去。

1
2
3
4
5
6
7
8
9
for {
实际状态 := 获取集群中对象 X 的实际状态(Actual State)
期望状态 := 获取集群中对象 X 的期望状态(Expectation State)
if 实际状态 == 期望状态{
什么都不做
} else {
执行编排动作,将实际状态调整为期望状态
}
}

原理

https://draveness.me/kubernetes-deployment