//
//
Deployment是k8s中比较常用的控制器,它实现了k8s中一个重要的功能:Pod的水平扩展和水平收缩。
01
Deployment控制器和Pod的关系
在k8s中,控制器和Pod的关系我们可以用下面的图来表示:
其中Deployment控制器的yaml文件中包含了被控对象的定义,一旦这个被控制对象生成,就会在它自己元信息metadata中的ownerReference字段写入控制器对象的信息,如下:
apiVersion: v1 kind: Pod metadata: creationTimestamp: "2021-04-19T08:54:28Z" generateName: nginx-7d48c8fb8f- labels: app: nginx pod-template-hash: 7d48c8fb8f name: nginx-7d48c8fb8f-glxpr namespace: database ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: nginx-deployment-7d48c8fb8f uid: d9297a21-a0ec-11eb-82a0-246e96b7eb9c
上图中的ownerReferences字段下面的内容,就是Pod中看到的Deployment的相关信息。
细心的你可能发现了,ownerReferences中的kind字段,并不是Deployment,而是ReplicaSet,这怎么解释?
上篇k8s笔记中,我们提到过,deployment是k8s 1.2版本引入的新概念,这个控制器和RC控制器的相似程度达到了90%,它和RC的不同是它可以随时获取当前Pod的"部署进度",有了Deployment之后,使用RC的场景几乎都可以使用Deployment来替代。
ReplicaSet对象其实就是由副本数目的定义和一个Pod模板来组成的,它是Deployment的一个子集,Deployment实际操作的,其实就是ReplicaSet,而不是Pod对象,真正操作Pod对象的是ReplicaSet,这三者的关系,画成图来表示就是:
可以看出来,这是一个层层控制的关系。
其中:
1、ReplicaSet保证Pod的个数永远等于指定的个数;
2、Deployment保证ReplicaSet的个数和属性;
3、Deployment通过修改ReplicaSet中的Pod副本个数来对应用进行弹性'扩缩容',例如将replicas字段从2改成3,则Replicaset会自动创建一个Pod节点,反之则销毁一个Pod节点。
这也就是我们常说的Deployment控制器的"水平扩展"和"水平收缩".
02
Deployment控制器的"滚动更新"
要了解"滚动更新",查看deployment的输出结果有几个字段需要介绍一下:
[root ~]# kubectl get deployment -n database NAME READY UP-TO-DATE AVAILABLE AGE nginx / d
其中:
Ready:2/2表示需要的Pod个数,以及当前处于Running的Pod个数。旧版本中也使用Desired和Current来表示这2个字段。
UP-TO-DATE:表示当前的最新版本的Pod个数,所谓最新版本指的是 Pod 的 Spec 部分与 Deployment 里 Pod 模板里定义的完全一致
Available:当前可用的Pod个数,也就是running状态的最新版本Pod个数。这个字段表示了最终的可用节点个数,非常关键。
对比下ReplicaSet的结果:
[root@ ~]# kubectl get replicaset -n database NAME DESIRED CURRENT READY AGE nginx-57bdbc4f46 d6h
可以发现,Deployment和Replicaset的差别就在于Up-to-date这个字段,这个字段标注了当前的节点是否是最新版本。
当我们需要滚动更新应用的时候,只需要修改Deployment的控制对象模板,"滚动更新"就会被自动触发。我们可以使用kubectl edit的命令直接在线打开某个deployment对象,这个命令的作用是:
将API对象的内容下载到本地,修改之后再提交上去。
滚动更新过程:
1、k8s利用新的模板,创建一个新的Replicaset对象,这个新的RS对象的初始副本数是0;
2、Deployment将这个新的RS控制的副本数从0改为1,也就是"水平扩展"1个;
3、Deployment将旧的RS所控制的副本数减少一个,也就是"水平收缩"1个;
4、如此交替进行,直到达到满足的Pod副本数;这个过程就是滚动更新,如下图所示:
滚动更新的好处:
1、如果滚动初期,发现新版本存在问题,滚动过程会失败,而旧的版本不受影响,运维人员可以快速接入;
2、Deployment Controller还会保证,任意时间段内,有指定比例个Pod被创建出来,只有指定比例的旧pod离线,这两个值都可以配置,默认是desire的25%。假设我们有个3副本的应用,那么Deployment控制器在滚动更新中会至少保证有2个Pod处于可用状态,至多只有4个Pod同时处于集群中,这个策略,在yaml文件中,叫做RollingUpdateStrategy,相关字段如下:
spec: progressDeadlineSeconds: 600 replicas: 1 reVisionHistoryLimit: 10 selector: matchLabels: app: nginx-deployment strategy: rollingUpdate: maxSurge: maxUnavailable: type: RollingUpdate
其中:
maxSurge:表示除了desire数量之外,在一次滚动中,Deployment控制器还可以创建多少个新Pod;
maxUnavailable:表示在一次滚动中,Deployment可以删除多少个就的Pod
03
滚动更新如何停止和回滚
有时候,我们的新版本除了问题,滚动更新会失败,在滚动更新失败的时候,kubernetes为我们制定了特定的命令,来让滚动终止和回滚。
在上面的修改过程中,我们使用kubectl edit的命令来修改API对象,我们还可以使用set image的方法来修改API对象,而不用打开编辑器编辑它。做个类比,edit的命令就是编辑mysql的配置文件,而set image的方法就是在命令行中直接写入参数。如下:
kubectl set image deployment/nginx-deployment nginx=nginx:1.91
我们修改nginx的版本为1.91版本。
1、滚动升级失败了怎么回滚?
如果这个命令在回滚的过程中发生问题,失败了,我们就可以使用下面的命令来回滚这个滚动更新的操作:
kubectl rollout undo deployment/nginx-deployment
2、如何获取所有版本?
除此之外,还可以通过:
kubectl rollout history deployment/nginx-deployment
rollout history的命令来获取所有的Deployment变更的版本,需要注意,要想获取版本,在启动Deployment的时候,需要带上--record参数,形如下面这样:
kubectl create -f deployment.yaml --record
3、如果回滚到指定版本?
有了版本之后,我们可以通过版本号--to-version的方法,回滚到某个指定的版本:
kubectl rollout undo deployment/nginx-deployment --to-revision=
4、如何暂停滚动更新?
如果我们需要对Deployment对象进行多次多处变更,而在变更过程中,不希望滚动更新发生,可以使用下面的方法来暂停滚动更新:
# 停止滚动更新 kubectl rollout pause deployment/nginx-deployment # 恢复滚动更新 kubectl rollout resume deploy/nginx-deployment
5、如何控制历史版本的个数?
通过spec的revisionHistoryLimit字段来控制Deployment控制器的历史版本ReplicaSet个数。
spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: maxUnavailable: type: RollingUpdate
有帮助的话还希望点下再看哈
基于centos7.9二进制部署kubernetes1.25.4