如果 Pod 是通过 Deployment 创建的,则++用户可以在运行时修改 Deployment 的 Pod 定义(spec.template)或镜像名称,并应用到 Deployment 对象上,系统即可完成 Deployment 的 rollout 动作++,rollout 可被视为 Deployment 的自动更新或者自动部署动作。如果在更新过程中发生了错误,则还可以通过回滚操作恢复 Pod 的版本。
Deployment 的升级
以 Deployment nginx 为例,保存文件名为 nginx-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
已运行的 Pod 副本数量有 3 个:
现在Pod 镜像需要被更新为 Nginx:1.9.1,可以通过 kubectl set image
命令为 Deployment 设置新的 镜像名称:
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
另一种更新的方法是使用 kubectl edit
命令修改 Deployment 的配置,将 spec.template.spec.containers[0].image 从 Nginx:1.7.9 更改为 Nginx:1.9.1:
kubectl edit deployment/nginx-deployment
保存退出
镜像名(或 Pod 定义)一旦发送了修改,则将触发系统完成 Deployment 所有运行 Pod 的滚动升级操作。可以使用 kubectl rollout status
命令查看 Deployment 的更新过程:
查看当前运行的 Pod,名称已经更新了:
可以使用 kubectl describe deployments/nginx-deployment
命令观察 Deployment 的更新过程。
- 初始创建 Deployment 时,系统创建了一个 ReplicaSet (nginx-deployment-5d59d67564),并按用户的需求创建了3个 Pod 副本。
- 更新 Deployment 时,系统创建了一个新的 ReplicaSet (replica set nginx-deployment-69c44dfb78),并将其副本数量扩展到1,然后将旧的 ReplicaSet 缩减为 2。
- 之后,系统继续按照相同的更新策略对新旧两个 ReplicaSet 进行逐个调整。新的 ReplicaSet 副本数量扩展至2,旧的 ReplicaSet 数量缩减到1。
- 最后的 ReplicaSet 运行了3个新版的 Pod 副本,旧的 ReplicaSet 副本缩减为0。
运行 kubectl get rs 命令,查看两个 ReplicaSet 的最终状态:
在整个升级过程中,系统会保证至少有两个 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。
-
Recreate:设置 spec.strategy.type=Recreate,表示 Deployment 在更新 Pod 时,会先“杀掉”所有正在运行的 Pod,然后创建新的 Pod。
-
RollingUpdate:设置 spec.strategy.type=RollingUpdate,表示 Deployment 会以滚动更新的方式来逐个更新 Pod。同时,可以通过设置 spec.strategy.rollingUpdate 下的两个参数(maxUnavailable 和 maxSurge)来控制滚动更新的过程。
-
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%。
Deployment 的回滚
假设在更新 Deployment 镜像时,将容器镜像名错误设置成 Nginx:19.1
则这时 Deployment 的部署过程会卡住:
所以需要 ctrl + c 命令来终止这个查看命令。
查看 ReplicaSet,可以看到新建的 ReplicaSet(nginx-deployment-d645d84b6)
在查看创建的 Pod,会发现新的 ReplicaSet 创建的 1 个 Pod 被卡在镜像拉取的过程中。
为了解决上面的问题,需要回滚到之前稳定版本的 Deployment。
- 首选用 kubectl rollout history 命令检查这个 Deployment 部署的历史记录:
kubectl rollout history deployment/nginx-deployment
注意:如果想要在 history 里面看到历史记录,需要在执行的创建和升级的命令里加上–record=true 才能看到。
将 Deployment 回滚到之前的版本时,只有 Deployment 的 Pod 模板部分会被修改,在默认情况下,所有 Deployment 的发布历史记录都被保留在系统中(可以配置历史记录数量)以便进行回滚操作。
如果需要查看特定版本的详细信息,则可以加上 --revision=参数:
kubectl rollout history deployment/nginx-deployment --revision=3
- 撤回本次发布并回滚到上一个部署版本:
kubectl rollout undo deployment/nginx-deployment
也可以使用 --to-reversion 参数指定回滚到的部署版本号:
kubectl rollout undo deployment/nginx-deployment --to-revision=2
可以在 kubectl describe
Deployment 的事件信息中查看到回滚版本2 的操作过程:
kubectl describe deployments/nginx-deployment
暂停和恢复 Deployment 的部署操作
对于一次复杂的 Deployment 配置修改,为了避免频繁触发 Deployment 的更新操作,可以先粘贴 Deployment 的更新操作,然后进行配置修改,再恢复 Deployment,一次性触发完整的更新操作,就可以避免不必要的 Deployment 更新操作了。
以之前创建的 Nginx 为例:
kubectl create -f nginx-deployment.yaml --record=true
通过 kubectl rollout pause
命令暂停 Deployment 的更新操作:
kubectl rollout pause deployment/nginx-deployment
然后修改 Deployment 的镜像信息:
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1 --record=true
查看 Deployment 的历史记录,发现并没有触发新的 Deployment 部署操作
在暂停 Deployment 部署之后,可以根据需要进行任意次数的配置更新。例如,再次更新容器的资源限制:
kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi --record=true
最后恢复这个 Deployment 的部署操作:
kubectl rollout resume deployment nginx-deployment
注意,在恢复暂停的 Deployment 之前,无法回滚该 Deployment。
DaemonSet 的更新策略
目前DaemonSet 的升级策略(updateStrategy)包括两种:OnDelete 和 RollingUpdate。
- OnDelete:当使用 OnDelete作为升级策略时,在创建好新的 DaemonSet 配置之后,新的 Pod 并不会被创建,直到用户手动删除旧版本的 Pod,才出发新建操作,即只有手工删除了 DaemonSet 创建的 Pod 副本,新的 Pod 副本才会被创建出来。
- RollingUpdate:默认选项。当使用 RollingUpdate 作为升级策略对 DaemonSet 进行更新时,旧版本的 Pod 将被自动“杀掉”,然后自动创建新版本的 DaemonSet Pod。整个过程与普通 Deployment 的滚动升级一样是可控的。不过有两点不同于普通 Pod 的滚动升级:
- 目前 Kubernetes 还不支持查看和管理 DaemonSet 的更新历史记录;
- DaemonSet 的回滚(Rollback)并不能如同 Deployment 一样直接通过 kubectl rollback 命令来实现,必须通过再次提交旧版本配置的方式实现。
例子如下:
创建带有 RollingUpdate 更新策略的 DaemonSet
保存为daemonset_rollingUpdate.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
# tolerations:
# # this toleration is to have the daemonset runnable on master nodes
# # remove it if your masters can't run pods
# - key: node-role.kubernetes.io/master
# effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.17
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
执行 kubectl apply 创建这个 DaemonSet
kubectl apply -f daemonset_rollingUpdate.yaml
检查 DaemonSet 的滚动更新策略
kubectl get ds/fluentd-elasticsearch -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}' -n kube-system
运行这个 DaemonSet
更新 DaemonSet 模板,保存为daemonset_rollingUpdate_2.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
updateStrategy:
type: OnDelete
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
# tolerations:
# # this toleration is to have the daemonset runnable on master nodes
# # remove it if your masters can't run pods
# - key: node-role.kubernetes.io/master
# effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.19
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- 声明式命令
如果你使用 配置文件 来更新 DaemonSet,请使用 kubectl apply:
kubectl apply -f daemonset_rollingUpdate_2.yaml
- 指令式命令
如果你使用 指令式命令 来更新 DaemonSets,请使用kubectl edit:
kubectl edit ds/fluentd-elasticsearch -n kube-system
把
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.17
改为
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.19
保存退出
- 只更新容器镜像
如果只需要更新 DaemonSet 模板里的容器镜像,比如,.spec.template.spec.containers[*].image
, 请使用 kubectl set image:
kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.19 -n kube-system
- 监视滚动更新状态
最后,观察 DaemonSet 最新滚动更新的进度:
kubectl rollout status ds/fluentd-elasticsearch -n kube-system
当滚动更新完成时,输出结果如下:
daemonset “fluentd-elasticsearch” successfully rolled out
查看 DaemonSet 事件信息:
kubectl describe daemonsets -n kube-system fluentd-elasticsearch
符合 RollingUpdate 的升级规则,旧版本的 Pod 将被自动“杀掉”,然后自动创建新版本的 DaemonSet Pod。
创建带有 OnDelete 更新策略的 DaemonSet
保存文件名为:daemonset_onDelete.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
updateStrategy:
type: OnDelete
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
# tolerations:
# # this toleration is to have the daemonset runnable on master nodes
# # remove it if your masters can't run pods
# - key: node-role.kubernetes.io/master
# effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.17
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
执行 kubectl apply 创建这个 DaemonSet
kubectl apply -f daemonset_onDelete.yaml
- 指令式命令修改这个 DaemonSet:
kubectl edit daemonsets -n kube-system fluentd-elasticsearch
把
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.17
改为
image: registry.aliyuncs.com/google_containers/fluentd-elasticsearch:1.19
保存退出
- 声明式命令
如果使用配置文件来更新 DaemonSet,请使用 kubectl apply:
kubectl apply -f daemonset_onDelete_2.yaml
- 查看这个 DaemonSet 的配置:
kubectl describe daemonsets -n kube-system fluentd-elasticsearch
发现已经修改成1.19,然后查看下面两个 Pod 的版本信息:
○ 发现还是1.17版本,然后手动删除这两个 Pod:
kubectl delete pod -n kube-system fluentd-elasticsearch-cpp2w
kubectl delete pod -n kube-system fluentd-elasticsearch-9fkwx
执行 kubectl 查看这个 daemonset 的状态
○ 查看新创建 Pod 的版本信息:
发现已成功更新1.19版本。
StatefulSet 的更新策略
StatefulSet 的更新策略跟 DaemonSet 类似,也有RollingUpdate 和 OnDelete 的策略
参考:《Kubernetes 权威指南 第五版》、https://v1-19.docs.kubernetes.io/zh/docs/tasks/manage-daemon/update-daemon-set/