Kubernetes中Pod的升级和回滚
本文说说 Pod 的升级和回滚问题。
当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有 Pod,然后下载新版本镜像并创建新的
Pod。如果集群规模比较大,则这个工作变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的
服务不可用。Kubernetes 提供了滚动升级功能来解决上述问题。
如果 Pod 是通过 Deployment 创建的,则用户可以在运行时修改 Deployment 的 Pod 定义(spec.template)或镜
像名称,并应用到 Deployment 对象上,系统即可完成 Deployment 的自动更新操作。如果在更新过程中发生了
错误,则还可以通过回滚操作恢复 Pod 的版本。
1、Deployment的升级
配置文件 034-nginx-deployment.yaml
的内容为:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
template:
metadata:
labels:
app: nginx-deployment
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
[root@master cha3]# kubectl create -f 034-nginx-deployment.yaml
deployment.apps/nginx-deployment created
[root@master cha3]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 14s
已运行的 Pod 副本数量有 3 个:
[root@master cha3]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-5c5f6c4496-2ctkg 1/1 Running 0 44s 10.244.140.66 slave2 <none> <none>
nginx-deployment-5c5f6c4496-tz9wr 1/1 Running 0 44s 10.244.140.193 slave1 <none> <none>
nginx-deployment-5c5f6c4496-vs2rk 1/1 Running 0 44s 10.244.140.67 slave2 <none> <none>
现在 Pod 镜像需要被更新为 Nginx:1.9.1 ,我们可以通过 kubectl set image
命令为 Deployment 设置新的镜
像名称:
[root@master cha3]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
另一种更新的方法是使用 kubectl edit 命令修改 Deployment 的配置,将
spec.template.spec.containers[0].image
从 Nginx:1.7.9
更改为 Nginx:1.9.1
:
[root@master cha3]# kubectl edit deployment/nginx-deployment
......
spec:
progressDeadlineSeconds: 600
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx-deployment
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deployment
spec:
containers:
- image: nginx:1.9.1
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
......
一旦镜像名(或 Pod 定义)发生了修改,则将触发系统完成 Deployment 所有运行 Pod 的滚动升级操作。可以使用
kubectl rollout status
命令查看 Deployment 的更新过程:
[root@master cha3]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
查看当前运行的 Pod,名称已经更新了:
[root@master cha3]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-76478869c8-tgmfp 1/1 Running 0 3m25s 10.244.140.69 slave2 <none> <none>
nginx-deployment-76478869c8-wrqnw 1/1 Running 0 3m29s 10.244.140.194 slave1 <none> <none>
nginx-deployment-76478869c8-xfw25 1/1 Running 0 3m27s 10.244.140.68 slave2 <none> <none>
查看 Pod 使用的镜像,已经更新为 Nginx:1.9.1
了:
[root@master cha3]# kubectl describe pod/nginx-deployment-76478869c8-xfw25
Name: nginx-deployment-76478869c8-xfw25
Namespace: default
Priority: 0
Node: slave2/192.168.226.202
Start Time: Mon, 10 Jul 2023 20:22:00 +0800
Labels: app=nginx-deployment
pod-template-hash=76478869c8
Annotations: <none>
Status: Running
IP: 10.244.140.68
IPs:
IP: 10.244.140.68
Controlled By: ReplicaSet/nginx-deployment-76478869c8
Containers:
nginx:
Container ID: docker://e02663da607b87a595ca02a250a6e7732f8fdb9778d37bdc30a6298927bab857
Image: nginx:1.9.1
Image ID: docker-pullable://nginx@sha256:2f68b99bc0d6d25d0c56876b924ec20418544ff28e1fb89a4c27679a40da811b
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 10 Jul 2023 20:22:01 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vj2v7 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-vj2v7:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m15s default-scheduler Successfully assigned default/nginx-deployment-76478869c8-xfw25 to slave2
Normal Pulled 4m15s kubelet Container image "nginx:1.9.1" already present on machine
Normal Created 4m15s kubelet Created container nginx
Normal Started 4m15s kubelet Started container nginx
那么,Deployment 是如何完成 Pod 更新的呢?
我们可以使用 kubectl describe deployments/nginx-deployment
命令仔细观察 Deployment 的更新过程。
初始创建 Deployment 时,系统创建了一个 ReplicaSet(nginx-deployment-5c5f6c4496),并按用户的需求创建
了 3 个 Pod 副本。当更新 Deployment 时,系统创建了一个新的 ReplicaSet(nginx-deployment-76478869c8),
并将其副本数量扩展到 1,然后将旧的 ReplicaSet 缩减为 2。之后,系统继续按照相同的更新策略对新旧两个
ReplicaSet 进行逐个调整。最后,新的 ReplicaSet 运行了 3 个新版本 Pod 副本,旧的 ReplicaSet 副本数量则缩
减为0。如图所示。
下面列出 Deployment nginx-deployment 的详细事件信息:
[root@master cha3]# kubectl describe deployments/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 10 Jul 2023 20:20:12 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=nginx-deployment
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx-deployment
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-76478869c8 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set nginx-deployment-5c5f6c4496 to 3
Normal ScalingReplicaSet 9m6s deployment-controller Scaled up replica set nginx-deployment-76478869c8 to 1
Normal ScalingReplicaSet 9m4s deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 2
Normal ScalingReplicaSet 9m4s deployment-controller Scaled up replica set nginx-deployment-76478869c8 to 2
Normal ScalingReplicaSet 9m2s deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 1
Normal ScalingReplicaSet 9m2s deployment-controller Scaled up replica set nginx-deployment-76478869c8 to 3
Normal ScalingReplicaSet 9m deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 0
运行 kubectl get rs
命令,查看两个 ReplicaSet
的最终状态:
[root@master cha3]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c5f6c4496 0 0 0 11m
nginx-deployment-76478869c8 3 3 3 9m42s
在整个升级的过程中,系统会保证至少有两个 Pod 可用,并且最多同时运行 4 个 Pod,这是 Deployment 通过复
杂的算法完成的。Deployment 需要确保在整个更新过程中只有一定数量的 Pod 可能处于不可用状态。在默认情
况下,Deployment 确保可用的 Pod 总数至少为所需的副本数量 DESIRED 减1,也就是最多1个不可用
maxUnavailable=1。Deployment 还需要确保在整个更新过程中 Pod 的总数量不会超过所需的副本数量太多。在
默认情况下,Deployment 确保 Pod 的总数最多比所需的 Pod 数多1个,也就是最多1个浪涌值 maxSurge=1。
Kubernetes 从 1.6 版本开始,maxUnavailable 和 maxSurge 的默认值将从1、1更新为所需副本数量的25%、
25%。这样,在升级过程中,Deployment 就能够保证服务不中断,并且副本数量始终维持为用户指定的数量
DESIRED。
对更新策略的说明如下。
在 Deployment 的定义中,可以通过 spec.strategy
指定 Pod 更新的策略,目前支持两种策略:
Recreate
(重建)和 RollingUpdate
(滚动更新),默认值为 RollingUpdate
。
在前面的例子中使用的就是 RollingUpdate 策略。
-
Recreate
:设置spec.strategy.type=Recreate,表示Deployment在更新Pod时,会先杀掉所有正在运行的Pod,然后创建新的Pod。
-
RollingUpdate
:设置spec.strategy.type=RollingUpdate,表示Deployment会以滚动更新的方式来逐个更新Pod。同时,可以通过设置spec.strategy.rollingUpdate下的两个参数(maxUnavailable和maxSurge)来
控制滚动更新的过程。
下面对滚动更新时两个主要参数的说明如下。
-
spec.strategy.rollingUpdate.maxUnavailable
:用于指定Deployment在更新过程中不可用状态的Pod数量的上限。该maxUnavailable的数值可以是绝对值(例如5)或Pod期望的副本数的百分比(例如10%),
如果被设置为百分比,那么系统会先以向下取整的方式计算出绝对值(整数)。而当另一个参数maxSurge被
设置为0时,maxUnavailable则必须被设置为绝对数值大于0(从Kubernetes 1.6开始,maxUnavailable的默
认值从1改为25%)。举例来说,当maxUnavailable被设置为30%时,旧的ReplicaSet可以在滚动更新开始时
立即将副本数缩小到所需副本总数的70%。一旦新的Pod创建并准备好,旧的ReplicaSet会进一步缩容,新的
ReplicaSet又继续扩容,整个过程中系统在任意时刻都可以确保可用状态的Pod总数至少占Pod期望副本总数
的70%。
-
spec.strategy.rollingUpdate.maxSurge
:用于指定在Deployment更新Pod的过程中Pod总数超过Pod期望副本数部分的最大值。该maxSurge的数值可以是绝对值(例如5)或Pod期望副本数的百分比(例如
10%)。如果设置为百分比,那么系统会先按照向上取整的方式计算出绝对数值(整数)。从Kubernetes 1.6
开始,maxSurge的默认值从1改为25%。举例来说,当maxSurge的值被设置为30%时,新的ReplicaSet可以
在滚动更新开始时立即进行副本数扩容,只需要保证新旧ReplicaSet的Pod副本数之和不超过期望副本数的
130%即可。一旦旧的Pod被杀掉,新的ReplicaSet就会进一步扩容。在整个过程中系统在任意时刻都能确保
新旧ReplicaSet的Pod副本总数之和不超过所需副本数的130%。
这里需要注意多重更新(Rollover)的情况。如果Deployment的上一次更新正在进行,此时用户再次发起
Deployment的更新操作,那么Deployment会为每一次更新都创建一个ReplicaSet,而每次在新的ReplicaSet创建
成功后,会逐个增加Pod副本数,同时将之前正在扩容的ReplicaSet停止扩容(更新),并将其加入旧版本
ReplicaSet列表中,然后开始缩容至0的操作。
例如,假设我们创建一个 Deployment,这个 Deployment 开始创建 5 个 Nginx:1.7.9 的 Pod 副本,在这个创建
Pod 动作尚未完成时,我们又将 Deployment 进行更新,在副本数不变的情况下将 Pod 模板中的镜像修改为
Nginx:1.9.1,又假设此时 Deployment 已经创建了 3 个 Nginx:1.7.9 的 Pod 副本,则 Deployment 会立即杀掉已
创建的 3 个 Nginx:1.7.9 Pod,并开始创建 Nginx:1.9.1 Pod。Deployment 不会在等待 Nginx:1.7.9 的 Pod 创建
到 5 个之后再进行更新操作。
还需要注意更新 Deployment 的标签选择器(Label Selector)的情况。通常来说,不鼓励更新 Deployment 的标
签选择器,因为这样会导致 Deployment 选择的 Pod 列表发生变化,也可能与其他控制器产生冲突。如果一定要
更新标签选择器,那么请务必谨慎,确保不会出现其他问题。
关于 Deployment 标签选择器的更新的注意事项如下。
(1)添加选择器标签时,必须同步修改 Deployment 配置的 Pod 的标签,为 Pod 添加新的标签,否则
Deployment 的更新会报验证错误而失败:
[root@master cha3]# kubectl edit deployment/nginx-deployment
将 spec.template.metadata.labels
的值 app=nginx-deployment
改为 app=nginx
。
......
spec:
progressDeadlineSeconds: 600
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx-deployment
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx # 修改nginx-deployment为nginx
......
会报错而退出修改:
# deployments.apps "nginx-deployment" was not valid:
# * spec.template.metadata.labels: Invalid value: map[string]string{"app":"nginx"}: `selector` does not match template `labels`
添加标签选择器是无法向后兼容的,这意味着新的标签选择器不会匹配和使用旧选择器创建的 ReplicaSets 和
Pod,因此添加选择器将会导致所有旧版本的 ReplicaSets 和由旧 ReplicaSets 创建的 Pod 处于孤立状态(不会被
系统自动删除,也不受新的 ReplicaSet 控制)。
为标签选择器和Pod模板添加新的标签(使用kubectl edit deployment
命令)。
[root@master cha3]# kubectl edit deployment/nginx-deployment
ReplicaSet 会创建 3 个新的 Pod。
[root@master cha3]# kubectl get rs
[root@master cha3]# kubectl get pod
(2)更新标签选择器,即更改选择器中标签的键或者值,也会产生与添加选择器标签类似的效果。
(3)删除标签选择器,即从Deployment的标签选择器中删除一个或者多个标签,该Deployment的ReplicaSet和
Pod不会受到任何影响。但需要注意的是,被删除的标签仍会存在于现有的Pod和ReplicaSets上。
Deployment 标签更改的情况很少,这里我们就不详细介绍了。
2、Deployment的回滚
有时(例如新的 Deployment 不稳定时)我们可能需要将 Deployment 回滚到旧版本。在默认情况下,所有
Deployment 的发布历史记录都被保留在系统中,以便于我们随时进行回滚(可以配置历史记录数量)。
# 现在的环境
[root@master cha3]# kubectl create -f 034-nginx-deployment.yaml
deployment.apps/nginx-deployment created
[root@master cha3]# kubectl get rs,deploy,pod
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-5c5f6c4496 3 3 3 22s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 22s
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-5c5f6c4496-22gfk 1/1 Running 0 22s
pod/nginx-deployment-5c5f6c4496-4ddxd 1/1 Running 0 22s
pod/nginx-deployment-5c5f6c4496-rkqzq 1/1 Running 0 22s
假设在更新 Deployment 镜像时,将容器镜像名误设置成 Nginx:1.91(一个不存在的镜像):
[root@master cha3]# kubectl set image deployment/nginx-deployment nginx=nginx:1.91
deployment.apps/nginx-deployment image updated
则这时 Deployment 的部署过程会卡住:
[root@master cha3]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
由于执行过程卡住,所以需要执行 Ctrl-C
命令来终止这个查看命令。
查看 ReplicaSet,可以看到新建的 ReplicaSet(nginx-deployment-85d8cdd6f7):
[root@master cha3]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c5f6c4496 3 3 3 70s
nginx-deployment-77f88687b6 1 1 0 31s
再查看创建的 Pod,会发现新的 ReplicaSet 创建的 1 个 Pod 被卡在镜像拉取过程中。
[root@master cha3]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5c5f6c4496-22gfk 1/1 Running 0 83s
nginx-deployment-5c5f6c4496-4ddxd 1/1 Running 0 83s
nginx-deployment-5c5f6c4496-rkqzq 1/1 Running 0 83s
nginx-deployment-77f88687b6-sqg6w 0/1 ImagePullBackOff 0 44s
为了解决上面这个问题,我们需要回滚到之前稳定版本的 Deployment。
首先,用kubectl rollout history
命令检查这个 Deployment 部署的历史记录:
[root@master cha3]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
注意,在创建 Deployment 时使用 --record 参数,就可以在 CHANGE-CAUSE 列看到每个版本使用的命令了。另
外,Deployment 的更新操作是在 Deployment 进行部署(Rollout)时被触发的,这意味着当且仅当Deployment的
Pod模板(即spec.template)被更改时才会创建新的修订版本,例如更新模板标签或容器镜像。其他更新操作
(如扩展副本数)将不会触发Deployment的更新操作,这也意味着我们将Deployment回滚到之前的版本时,只
有Deployment的Pod模板部分会被修改。
如果需要查看特定版本的详细信息,则可以加上--revision=<N>
参数:
[root@master cha3]# kubectl rollout history deployment/nginx-deployment --revision=0
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
[root@master cha3]# kubectl rollout history deployment/nginx-deployment --revision=1
deployment.apps/nginx-deployment with revision #1
Pod Template:
Labels: app=nginx-deployment
pod-template-hash=5c5f6c4496
Containers:
nginx:
Image: nginx:1.7.9
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
[root@master cha3]# kubectl rollout history deployment/nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
Labels: app=nginx-deployment
pod-template-hash=77f88687b6
Containers:
nginx:
Image: nginx:1.91
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
现在我们决定撤销本次发布并回滚到上一个部署版本:
[root@master cha3]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
当然,也可以使用 --to-revision
参数指定回滚到的部署版本号:
[root@master cha3]# kubectl rollout undo deployment/nginx-deployment --to-revision=1
这样,该Deployment就回滚到之前的稳定版本了,可以从Deployment的事件信息中查看到回滚到版本1的操作过
程:
[root@master cha3]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 10 Jul 2023 21:43:07 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 3
Selector: app=nginx-deployment
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx-deployment
Containers:
nginx:
Image: nginx:1.7.9
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-5c5f6c4496 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 5m24s deployment-controller Scaled up replica set nginx-deployment-5c5f6c4496 to 3
Normal ScalingReplicaSet 4m45s deployment-controller Scaled up replica set nginx-deployment-77f88687b6 to 1
Normal ScalingReplicaSet 73s deployment-controller Scaled down replica set nginx-deployment-77f88687b6 to 0
查看回滚历史:
[root@master cha3]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 <none>
3 <none>
3、暂停和恢复Deployment的部署操作以完成复杂的修改
对于一次复杂的Deployment配置修改,为了避免频繁触发Deployment的更新操作,可以先暂停Deployment的
更新操作,然后进行配置修改,再恢复Deployment,一次性触发完整的更新操作,就可以避免不必要的
Deployment更新操作了。
以之前创建的 Nginx 为例:
[root@master cha3]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 8m43s
[root@master cha3]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c5f6c4496 3 3 3 9m22s
nginx-deployment-77f88687b6 0 0 0 8m43s
[root@master cha3]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-5c5f6c4496-22gfk 1/1 Running 0 9m30s
nginx-deployment-5c5f6c4496-4ddxd 1/1 Running 0 9m30s
nginx-deployment-5c5f6c4496-rkqzq 1/1 Running 0 9m30s
通过 kubectl rollout pause
命令暂停 Deployment 的更新操作:
[root@master cha3]# kubectl rollout pause deployment/nginx-deployment
deployment.apps/nginx-deployment paused
然后修改Deployment的镜像信息:
[root@master cha3]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
查看Deployment的历史记录,发现并没有触发新的Deployment部署操作(停止和重启):
[root@master cha3]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 <none>
3 <none>
在暂停Deployment部署之后,可以根据需要进行任意次数的配置更新。例如,再次更新容器的资源限制:
[root@master cha3]# kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements update
最后,恢复这个Deployment的部署操作:
[root@master cha3]# kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed
可以看到一个新的ReplicaSet被创建出来了:
[root@master cha3]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c5f6c4496 0 0 0 11m
nginx-deployment-77f88687b6 0 0 0 11m
nginx-deployment-889d8b75d 3 3 3 13s
查看 Deployment 的事件信息,可以看到 Deployment 完成了更新:
[root@master cha3]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 10 Jul 2023 21:43:07 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 4
Selector: app=nginx-deployment
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx-deployment
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 200m
memory: 512Mi
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-889d8b75d (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-5c5f6c4496 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-77f88687b6 to 1
Normal ScalingReplicaSet 8m16s deployment-controller Scaled down replica set nginx-deployment-77f88687b6 to 0
Normal ScalingReplicaSet 60s deployment-controller Scaled up replica set nginx-deployment-889d8b75d to 1
Normal ScalingReplicaSet 59s deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 2
Normal ScalingReplicaSet 59s deployment-controller Scaled up replica set nginx-deployment-889d8b75d to 2
Normal ScalingReplicaSet 57s deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 1
Normal ScalingReplicaSet 57s deployment-controller Scaled up replica set nginx-deployment-889d8b75d to 3
Normal ScalingReplicaSet 55s deployment-controller Scaled down replica set nginx-deployment-5c5f6c4496 to 0
注意,在恢复暂停的 Deployment 之前,无法回滚该 Deployment。
4、使用kubectl rolling-update命令完成RC的滚动升级
高版本已经移除了该命令。
对于RC的滚动升级,Kubernetes还提供了一个kubectl rolling-update
命令进行实现。该命令创建了一个新的
RC,然后自动控制旧的RC中的Pod副本数量逐渐减少到0,同时新的RC中的Pod副本数量从0逐步增加到目标值,
来完成Pod的升级。需要注意的是,系统要求新的RC与旧的RC都在相同的命名空间内。
以redis-master为例,假设当前运行的redis-master Pod是1.0版本,现在需要升级到2.0版本。
配置文件 035-redis-master-controller.yaml
的内容为:
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 3
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
创建 036-redis-master-controller.yaml
的配置文件如下:
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master-v2
labels:
name: redis-master
version: v2
spec:
replicas: 3
selector:
name: redis-master
version: v2
template:
metadata:
labels:
name: redis-master
version: v2
spec:
containers:
- name: master
image: kubeguide/redis-master:2.0
ports:
- containerPort: 6379
在配置文件中需要注意以下两点。
-
RC 的名字不能与旧 RC 的名字相同。
-
在 selector 中应至少有一个 Label 与旧 RC 的 Label 不同,以标识其为新 RC。在本例中新增了一个名为
version 的 Label,以与旧 RC 进行区分。
首先,先创建v1版本的redis:
[root@master cha3]# kubectl create -f 035-redis-master-controller.yaml
replicationcontroller/redis-master created
[root@master cha3]# kubectl get rc,pod -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicationcontroller/redis-master 3 3 3 81s master kubeguide/redis-master name=redis-master
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/redis-master-tpnfr 1/1 Running 0 81s 10.244.140.84 slave2 <none> <none>
pod/redis-master-w8qdq 1/1 Running 0 81s 10.244.140.203 slave1 <none> <none>
pod/redis-master-ws7d5 1/1 Running 0 81s 10.244.140.83 slave2 <none> <none>
运行 kubectl rolling-update
命令完成 Pod 的滚动升级:
$ kubectl rolling-update redis-master -f 036-redis-master-controller.yaml
等所有新的 Pod 都启动完成后,旧的 Pod 也被全部销毁,这样就完成了容器集群的更新工作。
另一种方法是不使用配置文件,直接用 kubectl rolling-update
命令,加上--image
参数指定新版镜像名称来
完成Pod的滚动升级:
$ kubectl rolling-update redis-master --image=redis-master:2.0
与使用配置文件的方式不同,执行的结果是旧 RC 被删除,新 RC 仍将使用旧 RC 的名称。
kubectl 通过新建一个新版本 Pod,停掉一个旧版本 Pod,如此逐步迭代来完成整个 RC 的更新。
更新完成后,查看RC:
$ kubectl get rc
kubectl 给 RC 增加了一个key为 deployment 的Label(这个key的名字可通过 --deployment-label-
key
参数进行修改),Label 的值是 RC 的内容进行 Hash 计算后的值,相当于签名,这样就能很方便地比较RC里
的 Image 名字及其他信息是否发生了变化。
如果在更新过程中发现配置有误,则用户可以中断更新操作,并通过执行
kubectl rolling-update --rollback
完成 Pod 版本的回滚:
$ kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback
至此,Pod 恢复到更新前的版本了。
可以看出,RC 的滚动升级不具有 Deployment 在应用版本升级过程中的历史记录、新旧版本数量的精细控制等功
能,在 Kubernetes 的演进过程中,RC 将逐渐被 RS 和 Deployment 所取代,建议用户优先考虑使用
Deployment 完成 Pod 的部署和升级操作。
5、其他管理对象的更新策略
Kubernetes从 1.6 版本开始,对 DaemonSet 和 StatefulSet 的更新策略也引入类似于 Deployment 的滚动升
级,通过不同的策略自动完成应用的版本升级。
5.1 DaemonSet的更新策略
目前 DaemonSet 的升级策略包括两种:OnDelete
和 RollingUpdate
。
(1)OnDelete
:DaemonSet的默认升级策略,与1.5及以前版本的Kubernetes保持一致。当使用OnDelete作为
升级策略时,在创建好新的DaemonSet配置之后,新的Pod并不会被自动创建,直到用户手动删除旧版本的
Pod,才触发新建操作。
(2)RollingUpdate
:从Kubernetes 1.6版本开始引入。当使用RollingUpdate作为升级策略对DaemonSet进
行更新时,旧版本的Pod将被自动杀掉,然后自动创建新版本的DaemonSet Pod。整个过程与普通Deployment
的滚动升级一样是可控的。不过有两点不同于普通Pod的滚动升级:一是目前Kubernetes还不支持查看和管理
DaemonSet的更新历史记录;二是DaemonSet的回滚(Rollback)并不能如同Deployment一样直接通过kubectl
rollback命令来实现,必须通过再次提交旧版本配置的方式实现。
5.2 StatefulSet的更新策略
Kubernetes从1.6版本开始,针对StatefulSet的更新策略逐渐向Deployment和DaemonSet的更新策略看齐,也将
实现RollingUpdate、Paritioned和OnDelete这几种策略,以保证StatefulSet中各Pod有序地、逐个地更新,并且
能够保留更新历史,也能回滚到某个历史版本。