容器化技术(十二):如何使用Kubernetes中Deployment实现滚动升级与版本回滚?

1,056 阅读10分钟

Deployment—无状态部署

在常规的应用部署到Kubernetes集群当中的时候,很少直接使用Pod来直接部署,而是使用了Deployment的逻辑分装的概念。Deployment是对一组Pod的封装,可以在Deployment中指定运行的Pod实例的数目,Deployment会在Kubernetes集群中的kube-controller-manager的监控下,保证集群中的Pod的实例数目维持在Deployment中设定的数目上。

Deployment,顾名思义是部署的意思,它对Pod的集合,可以通过在yaml文件中定义Pod的模板template来定义Pod。这其中定义的Pod可以定义各种我们在前一节中介绍的各种属性与特性。

一、认识Deployment

Kubernetes 集群中的 Pod 有确定的生命周期。 例如,一旦某 Pod 在你的集群中运行,Pod 运行所在的节点出现致命错误时, 所有该节点上的 Pods 都会失败。Kubernetes 将这类失败视为最终状态: 即使该节点后来恢复正常运行,也需要创建新的 Pod 来恢复应用。 不过,为了让用户的日子略微好过一些,Kubernetes并不需要直接管理每个 Pod。 相反,可以使用负载资源来替用户管理一组 Pods。 这些资源配置控制器来确保合适类型的、处于运行状态的 Pod 个数是正确的,与用户所指定的状态相一致。这其中 Deployment 很适合用来管理集群上的无状态应用,Deployment 中的所有 Pods 都是相互等价的,并且在需要的时候被换掉。

接下来,我们来创建一个Deployment,并进行基本的实践,来感知Deployment的方便与强大。在之前单独定义Pod时,我们对Pod的修改,都是需要先去删除Pod,然后重新修改Pod的定义,然后再创建Pod的方式,在Deployment中,内部会通过删除旧的Pod,建立新的Pod的方式来达到修改Pod定义的方式。

第一步,新建一个yaml文件,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels: # 定义Deployment关联的Pod的标签
      app: nginx
  replicas: 2 # 告诉Deployment运行两个Pod实例
  template: # Pod的模板
    metadata:
      labels:
        app: nginx # Pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

第二步,创建这个Deployment:

kubectl apply -f 1-deploy.yaml

第三步,查询Deployment的运行情况,如图所示,Deployment创建成功,其中的参数的具体意义如下:

(1)NAME:列出了集群中 Deployment 的名称。 (2)READY:显示应用程序的可用的副本数。显示的模式是”就绪个数/期望个数“。 (3)UP-TO-DATE:显示为了达到期望状态已经更新的副本数。 (4)AVAILABLE:显示应用可供用户使用的副本数。 (5)AGE:显示应用程序运行的时间。

[root@kubernetes-master01 deploy]# kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           5m7s

查看,对应的Pod运行情况,如图所示,已经如yaml中定义的,创建了两个Pod。Pod的名字是自己生成的。

[root@kubernetes-master01 deploy]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-6b474476c4-dx7b6   1/1     Running   0          6m5s
nginx-deployment-6b474476c4-xljrj   1/1     Running   0          6m5s

第四步,修改Deployment中Pod的数目,修改对应的参数replicas为数目3,其他内容不变。

replicas: 3 # 告诉Deployment运行三个Pod实例
  template: # Pod的模板
    metadata:
      labels:
        app: nginx # Pod的标签

第五步,此时,我们只需要重新应用这个yaml文件,不需要手动对运行中的Deployment做任何改动。

kubectl apply -f 1-deploy.yaml

第六步,查看Deployment的运行情况,如图所示,已经成功的按照yaml中的定义创建了3个Pod的实例。

[root@kubernetes-master01 deploy]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-6b474476c4-dx7b6   1/1     Running   0          10m
nginx-deployment-6b474476c4-glfzt   1/1     Running   0          28s
nginx-deployment-6b474476c4-xljrj   1/1     Running   0          10m

通过以上的操作,我们可以很方便的手动对Pod实例进行扩容或者缩容,非常的方便,当然,后续的内容,我们会讲述如何根据Pod的运行情况,进行自动的扩容与缩容。

以下是 Deployments 的典型用例,本书不会一一的带领大家去实践,我们从中选择了最常使用的滚动升级以及版本回滚的案例来与大家一起学习。

(1)创建 Deployment 以将 ReplicaSet 上线。 ReplicaSet 在后台创建 Pods。 检查 ReplicaSet 的上线状态,查看其是否成功。 (2)通过更新 Deployment 的 PodTemplateSpec,声明 Pod 的新状态 。 新的 ReplicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的 ReplicaSet 都会更新 Deployment 的修订版本。 (3)如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。 每次回滚都会更新 Deployment 的修订版本。 (4)扩大 Deployment 规模以承担更多负载。 (5)暂停 Deployment 以应用对 PodTemplateSpec 所作的多项修改, 然后恢复其执行以启动新的上线版本。 (6)使用 Deployment 状态 来判定上线过程是否出现停滞。 (7)清理较旧的不再需要的 ReplicaSet 。

二、实现滚动升级

什么是滚动升级呢?当我们在对应用进行版本升级的时候,期望能够不影响应用的对外服务,不停止应用的对外服务,我们可以考虑将应用的实例一部分一部分的升级,这就是所谓的滚动升级,在传统应用中实现滚动升级相当的麻烦,但是在Kubernetes集群中,确是很方便的。

对于升级的策略,可以在定义Deployment的yaml文件中,加入以下这段内容:

strategy:
    rollingUpdate:
      maxSurge: number1%
      maxUnavailable: number2%
    type: RollingUpdate

其中的参数的含义如下:

(1)strategy:定义升级的策略。

(2)type:默认为RollingUpdate,也就是滚动升级的策略,还可以为Recreate,Recreate是需要将所有的老Pod都关闭后,开启所有的新Pod的升级策略,当应用的升级不兼容老版本时,需要使用Recreate这种升级策略。

(3)maxSurge:集群中可以使用的额外的用于升级的Pod的数目,举例Deployment中定义的Pod数目为4个,maxSurge如果定义为75%,也就是说,集群中最多可以额外创建4*75%=3个新的Pod,然后去替换老的Pod。

(3)maxUnavailable:集群中最多的不可用的Pod的数目,举例Deployment中定义的Pod数目为4个,maxUnavailable如果定义为25%,也就是集群中最多只能有4*25%=1个Pod不可用。

接下来,我们来实践一个滚动升级的例子。

第一步,我们创建一个yaml文件,内容如下,添加滚动升级的要求。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  strategy:
    rollingUpdate:
      maxSurge: 75%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels: # 定义Deployment关联的Pod的标签
      app: nginx
  replicas: 4 # 告诉Deployment运行四个Pod实例
  template: # Pod的模板
    metadata:
      labels:
        app: nginx # Pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

创建这个Deployment,注意带上record这个参数,可以记录下来升级的记录的情况。

kubectl apply -f 2-deploy-roll.yaml --record

第二步,查看Deployment运行的情况,如图所示,已经创建了四个Pod,并且运行的nginx的版本为1.14.2。

[root@kubernetes-master01 deploy]# kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES         
nginx-deployment   4/4     4            4           119s   nginx        nginx:1.14.2

第三步,我们修改Deployment中定义的Pod的nginx的版本,只修改nginx镜像的版本其他不动。

spec:
  containers:
  - name: nginx
    image: nginx:1.14.2 # 由1.14.2升级为1.16.1
    ports:
    - containerPort: 80

应用这个新的yaml:

kubectl apply -f 2-deploy-roll.yaml --record

第四步,查看Deployment中运行的情况,如图所示,nginx的版本已经变为1.16.1了。

[root@kubernetes-master01 deploy]# kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES         
nginx-deployment   4/4     4            4           9m2s   nginx        nginx:1.16.1   

第五步,尝试分析版本升级的过程,每个Deployment内部会封装rs,在我们进行版本升级后Deployment下面的rs变成了两个,如图所示,c4结尾的rs运行了12分钟,49结尾的rs运行了5分钟多,也就是说:

(1)nginx-deployment-6b474476c4:是版本升级前Deployment关联的rs。

(2)nginx-deployment-7b45d69949:是版本升级后Deployment关联的rs。

[root@kubernetes-master01 deploy]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-6b474476c4   0         0         0       12m
nginx-deployment-7b45d69949   4         4         4       5m7s

查看版本升级的过程,如图所示旧的rs由4变为3,新的rs直接扩到了3,然后新的rs扩到了4,老的rs变为2、1、0,是与我们定义的预期一致的。也就是先额外创建了3个新版本的Pod待用,老的版本先下掉了一个,然后又创建了一个新的Pod,达到了新版本为4个的目标后,老版本中的Pod就逐渐都下掉了。

[root@kubernetes-master01 deploy]# kubectl describe deployment nginx-deployment
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  26m   deployment-controller  Scaled up replica set nginx-deployment-6b474476c4 to 4
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled up replica set nginx-deployment-7b45d69949 to 3
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled down replica set nginx-deployment-6b474476c4 to 3
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled up replica set nginx-deployment-7b45d69949 to 4
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled down replica set nginx-deployment-6b474476c4 to 2
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled down replica set nginx-deployment-6b474476c4 to 1
  Normal  ScalingReplicaSet  18m   deployment-controller  Scaled down replica set nginx-deployment-6b474476c4 to 0

总结一下,RollingUpdate,也就是滚动升级的流程为,可以使用额外的maxSurge个Pod的资源去支持滚动升级,本例子中也就是4个老Pod加上3个新Pod的资源,同时整个Deployment的服务状态最多只能有maxUnavailable个Pod是不可用的。

三、版本回滚案例

当我们发现升级后的应用有问题的时候,可以将Deployment进行回滚操作。

在上面版本升级的基础上,查看目前Deployment的升级历史,如图所示。

[root@kubernetes-master01 deploy]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=2-deploy-roll.yaml --record=true
2         kubectl apply --filename=2-deploy-roll.yaml --record=true

目前,集群中的Deployment中的nginx镜像的版本,如图所示,为1.16.1。

[root@kubernetes-master01 deploy]# kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deployment   4/4     4            4           58m   nginx        nginx:1.16.1   app=nginx

执行以下命令,将Deployment回滚到版本1:

kubectl rollout undo deployment nginx-deployment --to-revision=1

查看目前Deployment中的nginx的版本,如图所示,已经恢复到1.14.2了。

[root@kubernetes-master01 deploy]# kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deployment   4/4     4            4           61m   nginx        nginx:1.14.2   app=nginx

查看Deployment所对应的rs,也就是副本集的情况,如图所示,并没有增加新的副本集rs,只是恢复了之前的副本集中对应的Pod的数目。

[root@kubernetes-master01 deploy]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-6b474476c4   4         4         4       62m
nginx-deployment-7b45d69949   0         0         0       54m

通过Deployment中nginx的image的版本的变化,我们进行了版本升级与版本回滚的案例,从中我们验证了以下的结论:

(1)Deployment通过副本集ReplicaSet来管理Pod的定义与Pod的数目。

(2)Deployment中的Pod的定义修改操作是通过定义新的副本集ReplicaSet来实现的。

(3)Deployment根据回滚历史的版本,可以将Deployment的状态回滚为历史上的某一版本。

(4)对于Deployment中的除了Pod定义之外其他属性的更新,并不会创建新的副本集ReplicaSet,但是会在回滚历史中添加一条新的REVISION记录,例如对于Pod的数量的更新。

四、猜你喜欢

如果你对容器化技术的相关知识感兴趣,可以阅读:秀丽的容器化技术Kubernetes专栏

本专栏特点:

  • 理论结合实战
  • 讲解深入浅出