K8S学习笔录 - Deployment的升级和回滚

3,339 阅读4分钟

原文链接

当集群中某个服务需要升级时,我们可能需要停止目前与该服务相关的所有Pod,然后下载新版本镜像并创建新的Pod。 然而这个升级/回滚方案在集群较大的时候代价是巨大的,会导致较长时间的服务不可用。K8S提供了滚动升级功能来解决这些问题。

不同的管理对象的更新配置和操作是不同的

对于Deployment来讲,更新的过程如下

  1. Deployment的ReplicaSet原本有3个Pod副本

  2. 在更新开始前,创建一个新的ReplicaSet对象,配置与旧的ReplicaSet一致

  3. 根据更新规则,逐渐扩容新的RS、缩容旧的RS,直到新的RS容量与旧的一致、旧的RS容量为0

  4. 根据存储历史版本配置决定是否删除超出存储数量的历史ReplicaSet

deployment-update.png

配置

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

有两种方案可以进行升级,效果一样

  1. 通过执行 kubectl edit (RESOURCE/NAME | -f FILENAME) [options]

    具体用法可以通过 kubectl edit --help 查看

  2. 通过执行 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

我们可以根据上面的信息看到

  1. Annotations: deployment.kubernetes.io/revision: 2

    当前Deployment的版本是2

  2. RollingUpdateStrategy: 25% max unavailable, 25% max surge

    此Deployment对象的滚动升级策略为最多25%不可用,最多同时升级25%的Pod,Events信息中的行为与配置要求行为完全一致

  3. Replicas: 3 desired | 2 updated | 4 total | 3 available | 1 unavailable

    当前的更新进度,也可以通过 kubectl rollout status deployments nginx-deployment 来监听

  4. Conditions:

    当前Deployment可用,正在进行ReplicaSet升级

  5. OldReplicaSets: ... NewReplicaSet: ... 存在的新旧ReplicaSets信息

  6. 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>

在回滚的时候有两种方案

  1. 回滚到上一版本 kubectl rollout undo (TYPE NAME | TYPE/NAME)
  2. 回滚到制定版本 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进行多次更新

  1. 暂停更新 kubectl rolout pause (TYPE NAME | TYPE/NAME)
  2. 修改Deployment
  3. 恢复更新 kubectl rolout resume (TYPE NAME | TYPE/NAME)