1. Deployment 无状态控制器
1.1 概述
Deployment 主要用于部署公司的无状态服务。无状态服务的特点是实例之间没有差异,请求发到任意实例都能处理,不需要保留会话或本地数据。
在学习Department的时候,要先简单认识一下Replication Controller(RC)和 ReplicaSet(RS)。
- ReplicationController(简称RC)可确保Pod副本数达到期望值,也就是RC定义的数量。换句话说,ReplicationController可确保一个Pod或一组同类Pod总是可用。(现在已经被废弃了)
- ReplicaSet是支持基于集合的标签选择器的下一代ReplicationController,它主要用作Deployment协调创建、删除和更新Pod,和ReplicationController唯一的区别是,ReplicaSet支持标签选择器。
为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过管理ReplicaSet来简介管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。

Deployment主要功能有下面几个:
-
支持ReplicaSet的所有功能
-
支持发布的停止、继续
-
支持滚动更新和回滚版本
1.2 创建和查看 Deployment
生成一个 Deployment 资源清单
bash
[root@master 1.2]# kubectl create deployment nginx --replicas=3 --image=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v1 --dry-run=client -o yaml > 1.nginx_v1_deploy.yaml
[root@master 1.2]# cat 1.nginx_v1_deploy.yaml
apiVersion: apps/v1 # API版本号
kind: Deployment # 资源类型
metadata:
creationTimestamp: null
labels: # 资源标签
app: nginx
name: nginx # 资源名称
spec:
replicas: 3 # 创建Pod的副本数量
selector: # 标签选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx # 该标签必须能匹配到以下pod的标签,否则会报错
strategy: {}
template: # Pod模板,会根据下面的模板创建pod副本
metadata:
creationTimestamp: null
labels:
app: nginx # 定义pod的标签
spec:
containers:
- image: crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v1
name: nginx
resources: {}
status: {}
[root@master 1.2]# kubectl apply -f 1.nginx_v1_deploy.yaml
使用kubectl get deploy命令可以查看到以下字段信息:
- NAME:Deployment 的名称,是你创建时指定的标识。
- READY:当前就绪的 Pod 副本数 / 期望的总副本数,比如 3/3 表示两个副本都正常运行。
- UP-TO-DATE:已更新到最新版本的 Pod 副本数,确保和期望版本一致。
- AVAILABLE:当前可用的 Pod 副本数,即能正常提供服务的数量。
- AGE:Deployment 从创建到现在的运行时间。
使用kubectl get rs命令可以查看到以下字段信息:
- NAME:RS 的名称(Deployment 创建的 RS 会带 "Deployment 名 + 随机哈希" 后缀,用于区分版本);
- DESIRED :期望运行的 Pod 副本数,与关联 Deployment 的
spec.replicas值一致; - CURRENT:集群中实际存在的 Pod 副本数(只要 Pod 创建成功即计数,不区分是否就绪);
- READY:已就绪、能正常提供服务的 Pod 副本数;
- AGE:RS 从创建到当前的运行时长。

1.3 扩缩容 Deployment
当应用访问量变大,或者有预期内的活动时(不在预期内可以使用HPA来自动扩缩容),三个 Pod 可能已无法支撑业务时,可以提前对其进行扩展。
扩缩容是使用kubectl scale deployment nginx --replicas=<副本数>命令
以下是扩容的示例,缩容同理

1.4 Deployment 更新策略
!IMPORTANT
- 仅当 Deployment 的 Pod 模板(即
.spec.template)更改时,才会触发 Deployment 更新,例如更改内存、CPU 配置或者容器的 image。- 当触发一个更新后,会有新的 ReplicaSet 产生,旧的 ReplicaSet 会被保存(用于后续版本回滚),查看此时 ReplicaSet,可以从 AGE 或 READY 看出来新旧 ReplicaSet
Deployment 目前只支持两种更新策略:重建更新 和 滚动更新(默认策略) ,可以通过 .spec.strategy.type指定策略类型。

1.4.1 滚动更新
滚动更新策略就是先启动新的 Pod 副本,再停止删除旧的,逐步替换完成更新。
使用kubectl get deploy nginx -o yaml查看默认的策略(生成环境中默认的策略已经足够用了)

使用kubectl set子命令来更新deploy副本的镜像为nginx:v2版本,也可以使用kubectl edit deploy nginx来更新副本,总之只要修改了.spec.template字段下的内容,就会触发更新动作。
bash
[root@master 1.2]# kubectl set image deploy nginx nginx=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v2
在滚动更新的时候新 Pod 先创建几个和我们定义的deployment.spec.strategy.rollingUpdate.maxSurge有关,这里是默认的25%(生产环境建议使用百分比),这里的副本数是3,3的25%向上取整就是1(也就是说副本数最大可以存在3+1=4个),所以是先创建一个然后删除一个。

使用kubectl rollout status deploy nginx命令来查看 Deployment 滚动更新过程的实时状态日志,该命令要在更新操作后立即执行,否则会看不到过程。

当然也可以使用kubectl describe deployments.apps nginx命令来查看deployment更新的详细过程

图片分析如下:
第一步:启动新 RS 的 1 个副本
Scaled up replica set nginx-65444d9946 to 1
表示新 RS(nginx-65444d9946)先扩到 1 个 Pod。
第二步:缩旧 RS 到 2 个,同时扩新 RS 到 2 个
Scaled down replica set nginx-fb8b758b5 to 2 from 3(旧 RS 从 3 缩到 2)
Scaled up replica set nginx-65444d9946 to 2 from 1(新 RS 从 1 扩到 2)
第三步:缩旧 RS 到 1,同时扩新 RS 到 3(目标副本数)
Scaled down replica set nginx-fb8b758b5 to 1 from 2(旧 RS 从 2 缩到 1)
Scaled up replica set nginx-65444d9946 to 3 from 2(新 RS 扩到 3,达到期望副本数)
第四步:旧 RS 缩容到 0(完成替换)
Scaled down replica set nginx-fb8b758b5 to 0 from 1
旧 RS 的 Pod 全部终止,更新完成。
最后结果
- 新 RS(nginx-65444d9946) :
DESIRED=3、READY=3→ 已完全就绪,是当前生效的 RS。 - 旧 RS(nginx-fb8b758b5) :
DESIRED=0→ 副本数被置 0,保留下来用于后续回滚
查看deployment的pod副本已经为nginx:v2版本了
bash
[root@master ~]# kubectl get deploy nginx -owide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 3/3 3 3 140m nginx crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v2 app=nginx
1.4.2 重建更新
该策略是先删掉所有旧的 Pod 再创建新的 Pod(不推荐使用)
修改deployment的策略为重建更新
bash
[root@master 1.2]# cat 2.nginx_v1_deploy_recreate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx_recreate
spec:
replicas: 3
selector:
matchLabels:
app: nginx_recreate
strategy:
type: Recreate
template:
metadata:
creationTimestamp: null
labels:
app: nginx_recreate
spec:
containers:
- image: crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v1
name: nginx
resources: {}
status: {}
[root@master 1.2]# kubectl apply -f 2.nginx_v1_deploy_recreate.yaml
更新副本的镜像为nginx:v2
bash
[root@master 1.2]# kubectl set image deploy nginx-recreate nginx=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v2 --record
使用kubectl describe deploy nginx-recreate命令可以看到控制器是先把旧的副本 Pod 全部停止删除后,再创建的新的副本 Pod。

1.5 Deployment 版本管理
当我们进行 Deployment 版本更新时,因为它是操作 ReplicaSet 控制器的,可以查看一下rs的变化。
bash
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-recreate-57cc7cd58f 3 3 3 2m24s
nginx-recreate-8556f8cd96 0 0 0 3h3m
nginx-recreate-d4976b64c 0 0 0 3h5m
可以看到我以上更新了 Deployment 后,旧的rs依然存在,这就是 Deployment 的特殊的功能,它管控这 ReplicaSet 来进行版本回退的操作。那么以下就是版本管理的命令概述:
kubectl rollout命令: 版本升级相关功能,目前仅支持以下选项:
-
status : 显示当前升级状态
-
history: 显示升级历史记录
-
pause: 暂停版本升级过程
-
resume: 继续已经暂停的版本升级过程
-
restart : 重启版本升级过程
-
undo: 回滚到上一级版本(可以使用 --to-revision 回滚到指定版本)
1.6 Deployment 版本回滚
当更新了版本不稳定或配置不合理时,可以对其进行回滚操作,假设我们又进行了几次更新 (此处以更新镜像版本触发更新,更改配置效果类似):
bash
[root@master ~]# kubectl set image deploy nginx-recreate nginx=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v1 --record
[root@master ~]# kubectl set image deploy nginx-recreate nginx=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v2 --record
[root@master ~]# kubectl set image deploy nginx-recreate nginx=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v3 --record
使用kubectl rollout history deployment nginx-recreate 查看历史版本,也可以后面添加--revision=<版本号>查看详细的版本信息,然后再查看rs,每个历史版本就对应一个rs

当然也可以使用 kubectl annotate deployment nginx-recreate kubernetes.io/change-cause="version=v3"给当前版本添加注释,方便后续在回滚的时候知道该版本的具体信息

如果只需要回滚到上一个稳定版本,使用 kubectl rollout undo即可:

那么我想回到我的nginx:v1版本怎么回滚过去呢?使用kubectl rollout undo命令回滚的话,它就又回到了v3版本了,就掉进死循环了。
这个时候可以使用kubectl rollout undo命令,然后后面加个--to-revision参数即可回到指定的版本。

1.7 暂停和恢复 Deploy 更新
上述演示的均为更改某一处的配置,更改后立即触发更新,大多数情况下可能需要针对一个 资源文件更改多处地方,而并不需要多次触发更新,此时可以使用 Deployment 暂停功能,临时禁用更新操作,对 Deployment 进行多次修改后在进行更新。
使用kubectl rollout pause命令即可暂停 Deployment 更新
bash
# 先创建一个名为nginx的3副本的deployment
[root@master ~]# kubectl create deployment nginx --replicas=3 --image=crpi-j2guy08w46nav7rf.cn-hongkong.personal.cr.aliyuncs.com/xiao_he/nginx:v1
[root@master 1.2]# kubectl rollout pause deployment nginx
然后对 Deployment 进行相关更新操作,比如先更新镜像,然后对其资源进行限制(如果使用的是 kubectl edit 命令,可以直接进行多次修改,无需暂停更新,kubectl set 命令一般会集成在 CICD 流水线中)

查看有没有被更新,通过查看历史版本可以看到是没有更新的,rs也是一个。

这个时候我们通过kubectl edit deploy nginx命令可以看到镜像和资源限制确实是改变了的

进行完最后一处配置更改后,使用 kubectl rollout resume 恢复 Deployment 更新
bash
[root@master 1.2]# kubectl rollout resume deployment nginx
恢复更新后,查看是否正常更新

1.8 历史版本管理
在默认情况下,revision 保留 10 个旧的 ReplicaSet,其余的将在后台进行垃圾回收,可以在.spec.revisionHistoryLimit 设置保留 ReplicaSet 的个数。当设置为 0 时,不保留历史记录。实际应用中根据需求来调整。
