kubernetes-Deployment部署无状态服务的原理详解(七)

公众号:后端技术解忧铺

引言

  k8s部署无状态应用后,若需要更新应用时,可以通过使用ReplicationController或ReplicaSet实现升级,主要有两种方式:

  • 直接删除所有现有的pod,然后创建新的pod;
  • 先创建新的pod,再删除旧pod。这里面也有两种方式,一种是先等所有新pod都运行成功后,应用切换到新pod访问,一次性删除所有旧pod;另一种是滚动升级方式逐步新建pod代替旧pod。
      下面我们将先看一下常用的相关术语,然后看一下升级pod的演进方式。

其他相关术语

  Pod:每个Pod是一个或一组紧密相关的容器,每个Pod就像是一个独立的逻辑机器,拥有自己的IP、主机名、进程等,运行一个独立的应用程序,是K8S调度的基本单位。
  ReplicationController:简称RC,旨在创建和管理一个Pod的多个副本(replicas)。当Pod副本数少于指定数目,RC就会启动运行新的Pod副本;多于指定数目,RC就会杀死多余的Pod副本。
  ReplicaSet:是新一代的RC,其相比于RC,Pod选择器的表达能力更强,其选择器可匹配缺少某个标签或特定标签名的Pod。

删旧pod,建新pod

  假设ReplicationController管理一组v1版本的pod,直接通过将pod模板修改为v2版本的镜像,删除旧的pod实例,RC检测到当前没有pod匹配标签选择器,就会创建新的实例。
删除旧pod,创建新pod

  1. 阶段1:原v1版本的RC有3个副本pod-v1。
  2. 阶段2:pod模板发生修改,由初始的v1版本修改为v2版本。
  3. 阶段3:pod-v1被手动删除。
  4. 阶段4:RC检测到当前没有pod匹配标签选择器,根据模板创建新的pod-v2。在阶段3过渡到阶段4期间,服务会出现短暂的不可用。

建新pod,删旧pod

  如果客户不能接受升级更新期间出现短暂的不可用的服务,那就需要先创建新的pod,再删除旧pod,这需要更多的硬件资源来支撑新旧pod同时存在的场景。

创建所有新pod,删除所有旧pod

  pod一般是通过Service来暴露服务的,在运行新版本pod前,Service都是访问的旧版本pod,当新版本pod创建且正常运行后,修改服务标签选择器切换Service流量至新pod,切换完毕后,删除旧RC,就可以删除所有旧pod。这种方式就是所谓的蓝绿部署
蓝绿部署

  1. 阶段1:原v1版本的RC有3个副本pod-v1。
  2. 阶段2:新建v2版本的RC,并且RC-v2自动创建了新的v2版本的pod。
  3. 阶段3:Service的流量切换到pod-v2,正常运行起来。
  4. 阶段4:删除RC-v1,从而自动删除pod-v1。

滚动新建和删除pod

  除了一次性创建新pod再一次性删除旧pod,我们还可以逐步递进的对旧版本pod进行删除,对新版本pod进行创建。这个可以通过对旧版本RC逐步缩容,同时对新版本RC进行扩容来实现。
滚动升级RC

  1. 阶段1:v1版本的RC副本数为3,有3个pod-v1。
  2. 阶段2:RC-v1副本数降为2,自动删除一个pod-v1,此时,创建一个v2版本的RC,且pod副本数为1,会自动新建一个v2版本的pod。
  3. 阶段3:RC-v1副本数降为1,自动再删除一个pod-v1,RC-v2的副本数为2,再自动新建一个pod-v2。
  4. 阶段4:RC-v1副本数降为0,并且删掉RC-v1,RC-v2副本数升为3,从而创建第3个pod-v2,至此完成滚动升级。

引入Deployment

  ReplicationController和ReplicaSet这两种资源对象需要其他控制器进行配合才可以实现滚动升级,并且难度大,因此k8s提供了一种基于ReplicaSet的资源对象Deployment可以支持声明式地更新应用。

Deployment介绍

Deployment概述

  Deployment是K8s在1.2版本引入的,是一种更高阶的资源,用于部署应用程序并以声明的方式升级应用,从而更好地解决pod编排问题。

Deployment使用机制

使用Deployment机制
  Deployment在内部使用了ReplicaSet实现编排pod功能,当创建一个Deployment时,ReplicaSet资源会随之创建,ReplicaSet是新一代的ReplicationController,并推荐使用它替代ReplicationController来复制和管理Pod,在使用Deployment时,实际的Pod是由Deployment的ReplicaSet创建和管理的。

Deployment使用场景

  1. 创建Deployment对象生成对应的ReplicaSet并完成pod副本创建;
  2. 通过检查Deployment状态(查看pod副本数量是否达到预期值)检验应用部署是否完成;
  3. 更新Deployment从而创建新的pod;
  4. 当前Deployment不稳定或故障,回滚到之前某个版本的Deployment(历史版本revision)
  5. 暂停Deployment并修改多个pod的template spec配置项,再恢复Deployment进行新的发布部署;
  6. 扩展Deployment从而应对高负载场景;
  7. 清理不再需要使用的旧版本ReplicaSet;

Deployment使用

Deployment基本命令

  假设Deployment的服务名称为test-tomcat-deploy,yaml模板文件名为test-tomcat.yaml。使用命令时,deploy等价于deployment等价于deployments。若需要指定命名空间ns_name时,需要加上-n ns_name

创建deployment

  • 基于模板创建:

    kubectl create -f test-tomcat.yaml

删除deployment

  • 基于模板删除:

    kubectl delete -f test-tomcat.yaml
  • 基于名称删除:

    kubectl delete deployment test-tomcat-deploy

更新deployment

  • 基于模板更新:

    kubectl apply -f test-tomcat.yaml
  • 基于名称更新:

    kubectl edit deploy/test-tomcat-deploy

查看deployment

  • 基于模板查看:

    kubectl get deploy test-tomcat-deploy -o yaml
  • 基于名称查看:

    kubectl describe deployments test-tomcat-deploy
  • 查看列表:

    kubectl get deploy

资源对象信息

Deployment信息

[root@localhost ~]# kubectl get deploy -n kube-system
NAME             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
st-ui-wnunzeyg   1         1         1            1           1d
st-ui-x3w4xumy   1         1         1            1           1d
  • DESIRED:pod副本数量的期望值(Deployment中定义的Replica数)
  • CURRENT:当前Replica值(Deployment实际创建的ReplicaSet中Replica值),该值会一直增加到DESIRED值为止才算整个应用实例创建完毕,部署才算完成。
  • UP-TO-DATE:最新版本的pod副本数量,用于指示在滚动升级过程中,有多少pod副本已成功升级。(Deployment滚动升级过程中ReplicaSet的Replica成功数)
  • AVAILABLE:当前集群中可用pod副本数。(Deployment创建的ReplicaSet中Replica存活数)
  • AGE:表示距离最后一次操作的时长。

ReplicaSet信息

[root@localhost ~]# kubectl get rs -n kube-system
NAME                        DESIRED   CURRENT   READY     AGE
st-ui-wnunzeyg-391614280    1         1         1         1d
st-ui-x3w4xumy-1656786196   1         1         1         1d

  我们可以看到ReplicaSet的命名和Deployment是相关的,ReplicaSet命名是以Deployment名为前缀,在Deployment名字基础上又加了一串随机数。

Pods信息

[root@localhost ~]# kubectl get pods -n kube-system
NAME                              READY     STATUS    RESTARTS   AGE
st-ui-wnunzeyg-391614280-3brk8    1/1       Running   0          1d
st-ui-x3w4xumy-1656786196-f4w8z   1/1       Running   0          1d

  pod名称以Deployment中的ReplicaSet名称为前缀,在此基础上又加了随机字符串。

Deployment更新

更新策略

  在Deployment中,可以通过spec.strategy指定Pod更新的策略,目前支持:Recreate(重建)RollingUpdate(滚动更新),默认是RollingUpdate。
  Recreate:设置spec.strategy.type=Recreate,更新方式为:Deployment在更新Pod时,会先杀掉所有正在运行的Pod,然后创建新的Pod。
  RollingUpdate:设置spec.strategy.type=RollingUpdate,更新方式为:Deployment会以滚动的方式来渐变性的更新Pod,即Pod新版本的递增,旧版本的递减的一个过程。

滚动更新

概念

  “滚动”,给人的是一种“圆”的印象,持续,不中断的意思,类似于“持续交付”的理念。RollingUpdate策略指一次仅更新一个Pod,并且逐个更新,而不是一次性将所有的服务都关闭,避免业务中断。

原理

滚动更新流程

  1. 初始创建Deployment,系统创建了一个ReplicaSet,并按照用户的需求创建了3个Pod副本;
  2. 当更新Deployment时,系统创建一个新的ReplicaSet,并将其副本数量扩展到1,然后将旧的ReplicaSet缩减为2;
  3. 系统继续按照相同的更新策略对新旧两个ReplicaSet进行逐个调整。
  4. 最后,新的ReplicaSet运行了3个新版本的Pod副本,旧的ReplicaSet副本数量则缩减为0。

Deployment回滚

概念

  回滚:通过滚动升级的策略可以平滑的升级Deployment,若升级出现问题,需要最快且最好的方式回退到上一次能够提供正常工作的版本。为此K8S提供了回滚机制。
  revision:更新应用时,K8S都会记录当前的版次,即为revision,当升级出现问题时,可通过回滚到某个特定的revision,默认配置下,K8S只会保留最近的几个revision,可以通过Deployment配置文件中的spec.revisionHistoryLimit属性增加revision数量。
  更新或回滚:每次更新或回滚时,revision都会自增1,回滚可以看作是一次更新,是一次更新为原版本的操作。

kubectl命令使用

查看修订版本记录

kubectl rollout history deployment deployment_name

查看某个历史记录的详细信息

kubectl rollout history deployment deployment_name --revision=2
其中--revision表示指定修订版本;

回滚到上一个版本

kubectl rollout undo deployment deployment_name

回滚到指定版本

kubectl rollout undo deployment deployment_name --to-revision=2
其中,--to-revision表示回滚到指定的修订版本。

API接口使用

POST

/apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
如:
curl -k -H 'Authorization: Bearer token_xxxx' -H 'Content-Type:application/json' -X POST -d '{
    "kind": "DeploymentRollback",
    "apiVersion": "extensions/v1beta1",
    "name": "deployment_name",
    "rollbackTo": {
        "revision": 2
    }
}' https://localhost:6443/apis/extensions/v1beta1/namespaces/default/deployments/deployment_name/rollback

  其中:name和rollbackTo.revision为必须字段,name为资源名称,rollbackTo.revision为回退的版本,若要回退上一个版本,即为0。

Q&A

什么是声明式?和其他方式有什么区别?

  除了声明式,我们一般还有指令式,也就是命令式。我们看看这两者定义和区别。
指令式

  1. 定义:使用计算机某种语言的指令(命令)来完成程序的运行,比如我们通过编写shell脚本、python脚本运行程序应用。
  2. 编写:编写复杂,强依赖开发人员的经验,需要考虑目标环境以及流程细节,处理各种异常情况和边缘情况等。
  3. 事务性:较难保持事务性,强依赖脚本流程,若脚本在执行过程中出现异常,程序应用会处于一个中间状态,所以多次运行,可能会达到不同的状态和结果。
  4. 维护性:开发后,需要有对应的运维文档来协助运维人员维护同一个脚本,不便于维护。

声明式

  1. 定义:使用配置文件直接描述最终状态,比如k8s中的yaml文件,描述最终要启动多少副本,要多少cpu之类的状态和结果。
  2. 编写:易于编写,只要会写配置文件,告诉应用达到什么样的结果和状态即可,不需要考虑流程和目标环境的细节,
  3. 事务性:天然的事务性,要么执行成功,要么失败,不会出现多种中间状态,重复执行保持一致的状态和结果。
  4. 维护性:配置文件中直接描述了最终状态和结果,无需过多的运维文档来描述信息。

参考
《Kubernetes in Action》
《Kubernetes权威指南》
k8s官网

posted @ 2023-03-27 15:26  Andya_net  阅读(190)  评论(0编辑  收藏  举报  来源