Kubernetes工作负载资源之Deployment

这里将介绍Kubernetes工作负载资源中的Deployment

abstract.png

创建Deployment

Deployment是一种更高阶的工作负载资源。其可以视作为对RS的再一次升级。其不仅可以部署应用还可以通过声明的方式升级应用。具体地,Deployment被创建后,其内部先创建相应的RS资源。再利用该RS资源创建相应的Pod。下面即是一个创建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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 创建Deployment资源

apiVersion: apps/v1
# 资源类型
kind: Deployment
metadata:
# Deployment名称
name: my-kubia-deployment
spec:
# Pod副本数量
replicas: 3
# 标签选择器
selector:
matchLabels:
app: my-kubia-app
# Pod模板
template:
metadata:
# 标签信息
labels:
app: my-kubia-app
spec:
# 容器信息
containers:
- name: my-kubia
image: luksa/kubia:v1
# 仅用于展示容器所使用的端口
ports:
- containerPort: 8080
protocol: TCP

---

# 创建Service资源

# API组、版本
apiVersion: v1
# 资源类型
kind: Service
metadata:
# 资源名称
name: my-kubia-svc
spec:
# Service类型
type: NodePort
selector:
app: my-kubia-app
ports:
- port: 80 # 服务监听端口
targetPort: 8080 # 服务将请求转发到Pod的目标端口
# 在集群各节点所打开的端口, 使得可以通过集群中任一节点IP、nodePort端口号访问该服务
nodePort: 30123

---

# 创建一个Pod用于访问、测试Service提供的服务

apiVersion: v1
kind: Pod
metadata:
name: my-bootcamp-pod
spec:
containers:
- name: my-bootcamp
image: jocatalin/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
protocol: TCP

效果如下所示。可以看到该Deployment会自行创建一个RS资源。同时再由该RS资源创建相应的Pod。同时这些Pod的名称前缀和RS名称完全一样。然后还可以通过Service进行访问

figure 1.jpeg

特别地,对于Deployment而言,还可以通过下述命令查看部署状态

1
2
3
4
5
# 查看指定名称的Deployment的部署结果
kubectl rollout status deployment <Deployment的名称>

# 查看名为my-kubia-deployment的Deployment的部署结果
kubectl rollout status deployment my-kubia-deployment

效果如下所示

figure 2.jpeg

基本实践

创建应用的V1版本

现在来演示下如何利用Deployment升级应用,先创建一个应用的V1版本

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
apiVersion: apps/v1
# 资源类型
kind: Deployment
metadata:
# Deployment名称
name: my-kubia-deployment-2
spec:
# Pod副本数量
replicas: 3
# Pod就绪后需要等待多长时间, 才会将该Pod视为可用
minReadySeconds: 10
# 升级策略
strategy:
# 默认策略类型为滚动升级
type: RollingUpdate
# 控制滚动升级速率
rollingUpdate:
# 升级期间, 相对于Deployment中指定的Pod期望副本数而言, 允许多出的Pod数量
maxSurge: 1
# 升级期间, 相对于Deployment中指定的Pod期望副本数而言, 允许有多少个Pod处于不可用状态
# 例如: 当replicas=3、maxUnavailable=1, 则此时要求可用的Pod数量至少为 replicas - maxUnavailable = 3-1 = 2
maxUnavailable: 0
# 标签选择器
selector:
matchLabels:
app: my-kubia-app-2
# Pod模板
template:
metadata:
# 标签信息
labels:
app: my-kubia-app-2
spec:
# 容器信息
containers:
- name: my-kubia-2
image: luksa/kubia:v1
# 仅用于展示容器所使用的端口
ports:
- containerPort: 8080
protocol: TCP
# 就绪探针
readinessProbe:
periodSeconds: 1
httpGet:
path: /
port: 8080

---

# 创建Service资源

# API组、版本
apiVersion: v1
# 资源类型
kind: Service
metadata:
# 资源名称
name: my-kubia-svc-2
spec:
# Service类型
type: NodePort
selector:
app: my-kubia-app-2
ports:
- port: 80 # 服务监听端口
targetPort: 8080 # 服务将请求转发到Pod的目标端口
# 在集群各节点所打开的端口, 使得可以通过集群中任一节点IP、nodePort端口号访问该服务
nodePort: 30123

---

# 创建一个Pod用于访问、测试Service提供的服务

apiVersion: v1
kind: Pod
metadata:
name: my-bootcamp-pod-2
spec:
containers:
- name: my-bootcamp
image: jocatalin/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
protocol: TCP

效果如下所示

figure 3.jpeg

在Deployment升级应用时,支持两种策略

  • RollingUpdate:其是Deployment的默认升级策略。其会渐进的删除旧版本的Pod,与此同时创建新版本的Pod。这样应用在整个升级过程中都处于可用的状态,即通过旧版本、新版本的Pod同时对外提供服务
  • Recreate:该策略下,其会一次性删除所有旧版本的Pod。再创建新版本的Pod。这样应用在整个升级过程中会有短暂的时间不可用。如果应用不支持同时使用多个不同版本对外提供服务,则可以选择该策略

升级应用到V2版本

对于Deployment升级应用来说,非常简单。只需设置该Deployment中容器的新镜像信息即可

1
2
3
4
5
# 对于指定名称的Deployment,设置其中指定名称容器的镜像信息
kubectl set image deployment <Deployment的名称> <容器的名称>=<镜像名称>:<镜像版本>

# 对于名为my-kubia-deployment-2的Deployment,设置名为my-kubia-2容器的镜像为luksa/kubia:v2
kubectl set image deployment my-kubia-deployment-2 my-kubia-2=luksa/kubia:v2

与此同时,通过my-bootcamp-pod-2这个Pod来访问my-kubia-svc-2服务,命令如下所示

1
2
3
4
5
# 进入名为my-bootcamp-pod-2的Pod
kubectl exec my-bootcamp-pod-2 -it -- bash

# 不停的访问my-kubia-svc-2的Service
while true; do curl 10.96.247.140:80 ; done

效果如下所示,右侧显示在RollingUpdate策略下V2版本的新Pod不断被创建,与此同时V1版本的旧Pod逐渐被删除

figure 4.jpeg

当升级完成后,可以看到Deployment实际上是先创建了一个新RS。然后对新RS不断扩容、对旧RS不断缩容。而且旧RS实际上依然保留在其中并未删除

figure 5.jpeg

此外每次利用kubectl edit、kubectl apply命令修改、应用Deployment中Pod模板相关字段值时,同样也会自动触发升级更新。为此可先通过kubectl rollout pause命令暂停该Deployment的升级更新,在完成所有对Deployment的更改后,再通过kubectl rollout resume命令恢复该Deployment的升级更新。对于回滚操作而言,不可以对处于暂停状态的Deployment执行 kubectl rollout undo命令,需要先恢复再回滚

1
2
3
4
5
# 暂停指定Deployment的升级更新
kubectl rollout pause deployment <Deployment的名称>

# 恢复指定Deployment的升级更新
kubectl rollout resume deployment <Deployment的名称>

应用回滚到指定版本

对于Deployment回滚应用也很简单,可以先通过下述命令查看某Deployment的滚动升级历史

1
2
3
4
5
# 查看指定名称的Deployment的滚动升级历史
kubectl rollout history deployment <Deployment的名称>

# 查看名为my-kubia-deployment-2的Deployment的滚动升级历史
kubectl rollout history deployment my-kubia-deployment-2

然后通过指定版本号查看该版本的具体信息

1
2
3
4
5
# 查看指定名称Deployment的指定版本的信息
kubectl rollout history deployment <Deployment的名称> --revision=<版本号>

# 查看名为my-kubia-deployment-2的Deployment的版本号为1的信息
kubectl rollout history deployment my-kubia-deployment-2 --revision=1

效果如下所示

figure 6.jpeg

故如果我们想将应用回滚到V1版本,只需使用kubectl rollout undo子命令即可。如果使用—to-revision选项指定版本号则会回滚到指定版本,如果不使用—to-revision选项则会直接回滚到上一个版本

1
2
3
4
5
6
7
8
# 将指定名称的Deployment回滚到上一个版本
kubectl rollout undo deployment <Deployment的名称>

# 将指定名称的Deployment回滚到指定版本
kubectl rollout undo deployment <Deployment的名称> --to-revision=<版本号>

# 将名为 my-kubia-deployment-2的Deployment 回滚到1号版本
kubectl rollout undo deployment my-kubia-deployment-2 --to-revision=1

效果如下所示。通过curl命令的结果不难看出Deployment已经回滚到V1版本了。由于此前升级后V1版本所对应的旧RS并没有被删除。所以可以直接利用旧RS进行回滚。而一旦将旧RS删除掉,就无法进行回滚了

figure 7.jpeg

应用重启

对于Deployment、DaemonSet、StatefulSet而言,可以通过kubectl rollout restart命令对应用进行重启

1
2
3
4
5
# 重启指定资源
kubectl rollout restart <工作负载资源类型> <相应工作负载资源的名称>

# 重启名为my-kubia-deployment的deployment
kubectl rollout restart deployment my-kubia-deployment

效果如下所示

figure 9.jpeg

控制升级速率

在RollingUpdate策略下,可以通过maxSurge、maxUnavailable参数控制滚动升级的速率。具体地:

maxSurge参数

升级期间, 相对于Deployment中指定的Pod期望副本数而言, 允许多出的Pod数量。同时该值可以是绝对数字也可以是一个百分比。例如: 当Deployment中指定的Pod期望副本数replicas为4时,如果maxSurge值为2,则表明不会运行超过4+2=6个Pod实例;如果maxSurge值为25%,则表明不会运行超过4+4*25% = 4+1 =5 个Pod实例

maxUnavailable参数

升级期间, 相对于Deployment中指定的Pod期望副本数而言, 允许有多少个Pod处于不可用状态。同时该值可以是绝对数字也可以是一个百分比。当Deployment中指定的Pod期望副本数replicas为4时,如果maxUnavailable值为1。则表明此时要求可用的Pod数量至少为 replicas - maxUnavailable = 4-1 = 3个;如果maxUnavailable值为50%。则表明此时要求可用的Pod数量至少为 replicas - maxUnavailable = 4-4*50% = 4-2 =2个。换言之,该参数不是限制不可用Pod的数量,而是通过replicas值计算出可用Pod的最少数量

此外,还可以使用minReadySeconds参数来避免升级缺陷版本的应用时,造成大范围的影响。在RollingUpdate滚动升级策略条件下,可以实现自动阻止升级过程。 具体地:

minReadySeconds参数

该参数指定Pod就绪后需要等待多少秒, 才会将该Pod视为可用。由于maxUnavailable参数的存在,会导致Pod可用之前,滚动升级过程不会再继续。minReadySeconds参数通过搭配就绪探针共同使用,可以实现将只有少量Pod升级到缺陷版本。由于滚动升级过程自动被阻止,故可以避免将所有Pod全部升级到缺陷版本。默认值为0意为Pod一旦就绪后,会立即将该Pod视为可用状态

在之前的Deployment中我们定义minReadySeconds参数为10秒,同时还定义了一个就绪探针。现在我们将应用升级到V3版本,该版本有一个缺陷。即其只能正确处理前四个请求,后续所有HTTP请求都将会失败。效果如下所示,可以看到由于V3版本的Pod处于未就绪,自然其也是不可用的状态。现在滚动升级已经被自动阻止了,避免了更大范围的影响。我们只需将Deployment回滚到历史版本即可

figure 8.jpeg

参考文献

  1. Kubernetes in Action中文版 Marko Luksa著
  2. 深入剖析Kubernetes 张磊著
0%