当集群中某个服务需要升级时,我们可能需要停止目前与该服务相关的所有Pod,然后下载新版本镜像并创建新的Pod。 然而这个升级/回滚方案在集群较大的时候代价是巨大的,会导致较长时间的服务不可用。K8S提供了滚动升级功能来解决这些问题。
不同的管理对象的更新配置和操作是不同的
对于Deployment来讲,更新的过程如下
-
Deployment的ReplicaSet原本有3个Pod副本
-
在更新开始前,创建一个新的ReplicaSet对象,配置与旧的ReplicaSet一致
-
根据更新规则,逐渐扩容新的RS、缩容旧的RS,直到新的RS容量与旧的一致、旧的RS容量为0
-
根据存储历史版本配置决定是否删除超出存储数量的历史ReplicaSet

配置
type DeploymentSpec struct {
// Deployment对于已经存在的Pod的替换策略
Strategy DeploymentStrategy `json:"strategy,omitempty"`
// 存储的历史版本数量,用于回滚,默认是10
RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"`
}
type DeploymentStrategy struct {
// 替换策略,值为Recreate或RollingUpdate,默认为RollingUpate
// Recreate会先停止所有的旧Pod,然后创建新的
Type DeploymentStrategyType `json:"type,omitempty"`
// 更新回滚配置参数,只在RollingUpdate下生效
RollingUpdate *RollingUpdateDeployment `json:"rollingUpdate,omitempty"`
}
type RollingUpdateDeployment struct {
// 滚动升级过程中,允许不可用的Pod数量或比例
// 默认为25%,此时升级过程中可用的Pod数量始终为75%
// 每成功升级一个,则允许开始升级下一个
// MaxUnavailable为0时,MaxSurge不能为0
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
// 滚动升级过程中,允许最多同时创建Pod的数量或比例
// 默认为25%,此时升级过程中新旧Pod数量总和最多为正常值的125%
// 每删除一个旧的Pod则允许创建一个新的
// MaxSurge为0时,MaxUnavailable不能为0
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty"`
}
升级
当前拥有一个名为nginx-deployment的Deployment对象
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.13.0
ports:
- containerPort: 80
假如要将其nginx版本从1.13.0升级到最新的1.14.0
有两种方案可以进行升级,效果一样
-
通过执行
kubectl edit (RESOURCE/NAME | -f FILENAME) [options]具体用法可以通过
kubectl edit --help查看 -
通过执行
kubectl set SUBCOMMAND [options]具体用法可以通过
kubectl set --help查看
我们使用第二种方案进行升级
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.14.0
deployment.apps/nginx-deployment image updated
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-58cdcbb467 3 3 3 8m32s
nginx-deployment-7f555c9b4b 1 1 0 9s
$ kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sat, 28 Dec 2019 21:58:02 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 2
kubernetes.io/change-cause: kubectl create --filename=nginx-old.yaml --record=true
Selector: app=nginx
Replicas: 3 desired | 2 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.14.0
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-58cdcbb467 (2/2 replicas created)
NewReplicaSet: nginx-deployment-7f555c9b4b (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 8m53s deployment-controller Scaled up replica set nginx-deployment-58cdcbb467 to 3
Normal ScalingReplicaSet 30s deployment-controller Scaled up replica set nginx-deployment-7f555c9b4b to 1
Normal ScalingReplicaSet 17s deployment-controller Scaled down replica set nginx-deployment-58cdcbb467 to 2
Normal ScalingReplicaSet 17s deployment-controller Scaled up replica set nginx-deployment-7f555c9b4b to 2
我们可以根据上面的信息看到
-
Annotations: deployment.kubernetes.io/revision: 2
当前Deployment的版本是2
-
RollingUpdateStrategy: 25% max unavailable, 25% max surge
此Deployment对象的滚动升级策略为最多25%不可用,最多同时升级25%的Pod,Events信息中的行为与配置要求行为完全一致
-
Replicas: 3 desired | 2 updated | 4 total | 3 available | 1 unavailable
当前的更新进度,也可以通过
kubectl rollout status deployments nginx-deployment来监听 -
Conditions:
当前Deployment可用,正在进行ReplicaSet升级
-
OldReplicaSets: ... NewReplicaSet: ... 存在的新旧ReplicaSets信息
-
Events: ...
当前Deployment对象发生的事件
最终状态下,原来的 nginx-deployment-7f555c9b4b 中Pod的数量将会变成0,而新的 nginx-deployment-58cdcbb467 中的Pod数量将会变为3
由于Deployment的配置中保留历史版本数使用了默认的10,所以旧的RS会与新的同时存在,用于回滚
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-58cdcbb467 0 0 0 15m
nginx-deployment-7f555c9b4b 3 3 3 6m43s
回滚
可以使用 kubectl rollout 命令来对Deployment进行回滚,通过 kubectl rollout --help 查看具体用法
在回滚版本前,可以通过 kubectl rollout history 来查看当前存在的版本
如果在创建Deployment的时候,使用了 --record 参数,每次Deployment被修改的时候,还会记录下来修改的命令
$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=nginx-old.yaml --record=true
2 kubectl create --filename=nginx-old.yaml --record=true
此处可以看到当前有两个版本,可以在后面加参数 --revision=<REVISION> 来查看指定版本的PotTemplate
$ kubectl rollout history deployment/nginx-deployment --revision=1
deployment.apps/nginx-deployment with revision #1
Pod Template:
Labels: app=nginx
pod-template-hash=58cdcbb467
Annotations: kubernetes.io/change-cause: kubectl create --filename=nginx-old.yaml --record=true
Containers:
nginx:
Image: nginx:1.13.0
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
在回滚的时候有两种方案
- 回滚到上一版本
kubectl rollout undo (TYPE NAME | TYPE/NAME) - 回滚到制定版本
kubectl rollout undo (TYPE NAME | TYPE/NAME) --to-revision=<REVISION>
使用第2中方法进行回滚,回滚到1个版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1
deployment.apps/nginx-deployment rolled back
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-58cdcbb467 3 3 3 30m
nginx-deployment-7f555c9b4b 0 0 0 22m
$ kubectl describe deployment nginx-deployment
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-58cdcbb467 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 22m deployment-controller Scaled up replica set nginx-deployment-7f555c9b4b to 1
Normal ScalingReplicaSet 22m deployment-controller Scaled down replica set nginx-deployment-58cdcbb467 to 2
Normal ScalingReplicaSet 22m deployment-controller Scaled up replica set nginx-deployment-7f555c9b4b to 2
Normal ScalingReplicaSet 22m deployment-controller Scaled down replica set nginx-deployment-58cdcbb467 to 1
Normal ScalingReplicaSet 22m deployment-controller Scaled up replica set nginx-deployment-7f555c9b4b to 3
Normal ScalingReplicaSet 21m deployment-controller Scaled down replica set nginx-deployment-58cdcbb467 to 0
Normal ScalingReplicaSet 14s deployment-controller Scaled up replica set nginx-deployment-58cdcbb467 to 1
Normal ScalingReplicaSet 10s deployment-controller Scaled down replica set nginx-deployment-7f555c9b4b to 2
Normal ScalingReplicaSet 10s deployment-controller Scaled up replica set nginx-deployment-58cdcbb467 to 2
Normal ScalingReplicaSet 7s (x2 over 30m) deployment-controller Scaled up replica set nginx-deployment-58cdcbb467 to 3
Normal ScalingReplicaSet 7s deployment-controller Scaled down replica set nginx-deployment-7f555c9b4b to 1
Normal ScalingReplicaSet 3s deployment-controller Scaled down replica set nginx-deployment-7f555c9b4b to 0
信息上可以看到,通过缩容和扩容的操作,已经逐步切换到旧版本 nginx-deployment-58cdcbb467 上了
并且没有更旧的版本了 OldReplicaSets: <none>
暂停
当有比较复杂的修改需求的时候,可以先暂停Deployment的更新能力,在对Deployment进行修改完成之后,重新启用更新,从而避免Deployment进行多次更新
- 暂停更新
kubectl rolout pause (TYPE NAME | TYPE/NAME) - 修改Deployment
- 恢复更新
kubectl rolout resume (TYPE NAME | TYPE/NAME)