当前位置 博文首页 > RtxTitanV的博客:Kubernetes控制器之Deployment

    RtxTitanV的博客:Kubernetes控制器之Deployment

    作者:[db:作者] 时间:2021-07-07 10:08

    Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。只需要在Deployment中描述一个期望状态,Deployment控制器以受控速率更改实际状态以达到期望状态。

    本文主要Kubernetes的Deployment控制器进行简单总结。

    一、环境信息

    本文所使用的环境如下:

    • 操作系统:CentOS Linux release 8.2.2004
    • Docker:19.03.12
    • kubernetes:v1.18.5

    二、Deployment简介

    Deployment为Pod和ReplicaSet提供声明式的更新方式。只需要在Deployment中描述一个期望状态,Deployment控制器以受控速率更改实际状态以达到期望状态。可以定义Deployment以创建新的ReplicaSet,或删除现有的Deployment并通过新的Deployment使用其所有资源。注意不要手动管理Deployment创建的ReplicaSet,否则逾越了Deployment控制器职责。下面是关于Deployment的典型用例:

    • 创建Deployment以展开(rollout)ReplicaSet。ReplicaSet在后台创建Pod。检查ReplicaSet展开的状态,查看其是否成功。
    • 通过更新Deployment的PodTemplateSpec字段来声明Pod的新状态。这将创建一个新的ReplicaSet,并且Deployment管理器会以受控速率将Pod从旧ReplicaSet移动到新ReplicaSet。每个新的ReplicaSet都会更新Deployment的修订历史(revision)。
    • 如果Deployment的当前状态不稳定,支持回滚到较早的Deployment历史版本。每次回滚都会更新Deployment的修订历史(revision)。
    • 扩容Deployment以满足更高的负载。
    • 暂停Deployment对其PodTemplateSpec进行修改,然后恢复它以启动新的展开。
    • 根据Deployment的状态判断展开是否卡住。
    • 清理那些不再需要的旧的ReplicaSet。

    三、创建Deployment

    1.Deployment清单

    可以通过以下命令查看Deployment资源清单规则:

    kubectl explain deployment
    kubectl explain deployment.spec
    kubectl explain deployment.spec.template
    

    也可以通过官方Kubernetes API手册进行查找。这里主要总结一下资源清单中重要的字段:

    字段类型说明
    apiVersionstringapi版本定义
    kindstring资源类型定义
    metadataobject元数据定义
    specobjectDeployment的Spec定义
    spec.replicasintegerPod副本的期望数目,默认值为1。为可选字段
    spec.selectorobject标签选择器,定义匹配Pod的标签。spec.selector必须匹配spec.template.metadata.labels,否则请求会被API拒绝。为必要字段
    spec.selector.matchLabelsobject{key,value}对的映射
    spec.templateobjectPod模板定义,除了它是嵌套的并且没有apiVersionkind之外,与Pod资源清单的语法几乎完全一致。为必要字段
    spec.template.metadataobjectPod的元数据定义
    spec.template.metadata.namestring定义Pod的名称
    spec.template.metadata.labelsobject定义Pod的标签,必须与spec.selector匹配(可以多出其他标签),否则它将被API拒绝
    spec.template.specobjectPod的Spec定义
    spec.strategyobject指定可用于用新Pod替换旧Pod的策略
    spec.strategy.typestring指定Deployment的策略类型,可以是Recreate或RollingUpdate,RollingUpdate是默认值。当spec.strategy.type==Recreate时,在创建新Pod之前,所有现有的Pod都将被杀死。当spec.strategy.type==RollingUpdate时,Deployment会以滚动更新方式更新Pod,可以指定maxUnavailablemaxSurge来控制滚动更新过程
    spec.strategy.rollingUpdateobject滚动更新配置参数,仅在spec.strategy.type==RollingUpdate时生效
    spec.strategy.rollingUpdate.maxSurge指定在期望的Pod副本数的基础之上再创建的最大Pod数量。该值可以是绝对数字(例如,5)或所需Pod的百分比(例如,10%)。如果spec.strategy.rollingUpdate.maxUnavailabl为0,则该值不能为0。绝对数字通过四舍五入从百分比中得出的。默认值为25%。例如:当此值设置为30%时,滚动更新开始时会立即按比例扩展新的ReplicaSet,以使新旧Pod的总数不超过所需Pod的130%。一旦旧Pod被杀死,就可以进一步扩展新的ReplicaSet,以确保更新期间任何时间运行的Pod总数最多为所需Pod数的130%
    spec.strategy.rollingUpdate.maxUnavailable指定更新期间不可用的Pod的最大数量。该值可以是绝对数字(例如,5)或所需Pod的百分比(例如,10%)。绝对数字是通过四舍五入从百分比中得出的。 如果spec.strategy.rollingUpdate.maxSurge为0,则该值不能为0。默认为25%。例如:当此值设置为30%时,滚动更新开始时会立即将旧ReplicaSet向下缩减到期望Pod的70%。新Pod准备就绪后,可以进一步向下缩减旧ReplicaSet,然后向上扩展新的ReplicaSet,确保可用的Pod总数在更新期间的任何时候都至少为期望Pod数的70%
    spec.progressDeadlineSecondsinteger在Deployment失败之前,部署进行的最长时间,以秒为单位。Deployment制器将继续处理失败的部署,并且在部署状态中将显示带有ProgressDeadlineExceeded原因的条件。在部署暂停期间不会估计进度。默认为600s。如果指定,此字段需要大于spec.minReadySeconds。为可选字段
    spec.minReadySecondsinteger指定新创建的Pod在没有任何容器崩溃情况下的最小就绪时间,以便将其视为可用。默认值为0(Pod在准备就绪后将立即被视为可用)。为可选字段
    spec.revisionHistoryLimitinteger指定要保留的旧ReplicaSet的数量以允许回滚。这些旧ReplicaSet消耗etcd中的资源,并占用kubectl get rs的输出。每个Deployment修改版的配置都存储在其ReplicaSet中,一旦删除了旧的ReplicaSet,将失去回滚到旧的Deployment版本的能力。默认值为10。将此字段设置为0意味着将清理所有具有0个Pod副本的旧ReplicaSet,这种情况下,无法撤消新的Deployment展开,因为它的修改历史被清除了。为可选字段
    spec.pausedboolean用于暂停和恢复Deployment的可选布尔字段。暂停的Deployment和未暂停的Deployment唯一的区别就是,只要暂停Deployment处于暂停状态,PodTemplateSpec的任意修改都不会触发新的展开。默认Deployment在创建时是不会被暂停的

    注意:

    • 在APIapps/v1版本中,spec.selector.metadata.labels不会被默认设置为.spec.template.metadata.labels,如果没有设置需要明确进行设置。同时在 apps/v1版本中,Deployment创建后spec.selector是可变的。
    • 当Pod的标签和选择器匹配时,若此类Pod的模板和spec.template不同,或者此类Pod的总数超过spec.replicas, Deployment会终止这些Pod。如果Pod总数达不到期望值,会用spec.template创建新的Pod。
    • 不应直接通过创建另一个Deployment或创建另一个诸如ReplicaSet或ReplicationController的控制器来创建其标签与该选择器匹配的其他Pod。如果这样做,第一个Deployment会认为是它创建了这些其他的Pod。如果有多个具有重叠选择器的控制器,则控制器之间会因冲突而故障。

    2.Deployment示例

    创建Deployment会展开(rollout)ReplicaSet,ReplicaSet会在后台创建Pod。一个简单的Deployment示意图如下:
    1
    首先准备一个镜像,创建一个名为mynginx1Dockerfile文件:

    FROM nginx:alpine
    RUN echo 'mynginx:v1' > /usr/share/nginx/html/index.html
    

    构建mynginx:v1镜像:

    docker build -t mynginx:v1 -f mynginx1 .
    

    创建Deployment资源清单文件mynginx-deployment.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mynginx-deployment
      labels:
        app: mynginx
        env: test
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: mynginx
          env: test
      template:
        metadata:
          labels:
            app: mynginx
            env: test
        spec:
          containers:
          - name: nginx
            image: mynginx:v1
            imagePullPolicy: IfNotPresent
            ports:
            - name: http
              containerPort: 80        
    

    执行以下命令创建Deployment

    kubectl apply -f mynginx-deployment.yaml --record
    

    注意:可以指定--record选项来写入在资源注释(annotation)kubernetes.io/change-cause中执行的命令。它对以后的检查很有用。例如,查看在每个Deployment修订历史(revision)中执行的命令。

    查看Deployment展开状态,为成功状态:

    kubectl rollout status deployment.v1.apps/mynginx-deployment
    

    2
    查看Deployment,发现Deployment已创建了所有的三个最新且可用的副本:

    kubectl get deployment
    

    3
    Deployment的输出显示的字段解释如下:

    • NAME:列出名称空间中Deployment的名称。
    • READY:显示用户可以使用多少个应用程序副本。它遵循准备/期望的模式。
    • UP-TO-DATE:显示已更新以实现期望状态的副本数。
    • AVAILABLE:显示应用程序可供用户使用的副本数。
    • AGE:显示应用程序运行的时间。

    查看Deployment创建的ReplicaSet,发现ReplicaSet的名称格式为[DEPLOYMENT-NAME]-[RANDOM-STRING],其中随机字符串是以pod-template-hash为基础随机生成的:

    kubectl get rs
    

    4
    ReplicaSet的输出显示的字段的解释如下:

    • NAME:列出名称空间中ReplicaSet的名称。
    • DESIRED:显示应用程序的期望副本数,这些副本是在创建展开时定义的,这只是期望的状态。
    • CURRENT:显示当前正在运行的副本数。
    • READY:显示用户可以使用多少个应用程序副本。
    • AGE:显示应用程序运行的时间。

    查看每个Pod及其标签,发现创建的ReplicaSet确保总是有3个nginxPod存在,Pod的名字为ReplicaSet的名字加上5位随机字符:

    kubectl get pod -o wide --show-labels
    

    5
    注意有一个名为pod-template-hash的标签,不要更改。此标签将被Deployment控制器添加到Deployment创建或使用的每个ReplicaSet中,可确保Deployment的子ReplicaSet不重复。它是通过对ReplicaSet的PodTemplate进行哈希处理并使用生成的哈希值添加到ReplicaSet选择器、Pod模板标签以及ReplicaSet可能具有的任何现有Pod中的标签而生成的。最后执行以下命令清理之前创建的资源对象:

    kubectl delete all -l app=mynginx
    

    四、更新Deployment

    仅当Deployment的Pod模板即spec.template更改时,例如模板的标签或容器镜像已更新,才会触发Deployment的展开(rollout)。其他更新,如Deployment扩容,则不会触发Deployment的展开。首先准备一个mynginx:v2镜像用于更新,创建一个名为mynginx2Dockerfile文件:

    FROM nginx:alpine
    RUN echo 'mynginx:v2' > /usr/share/nginx/html/index.html
    

    构建mynginx:v2镜像:

    docker build -t mynginx:v2 -f mynginx2 .
    

    1.更新策略

    Deployment控制器支持两种更新策略:

    • 滚动更新(rollingUpdate):在删除一部分旧版本Pod的同时,补充创建一部分新版本的Pod对象进行升级,其优势是升级期间,容器中应用提供的服务不会中断,但更新期间,不同客户端得到的相应内容可能会来自不同版本的应用。为默认更新策略。
    • 重新创建(Recreate):在创建新Pod之前,所有现有的Pod都将被杀死。

    Deployment控制器的滚动更新并非在同一个ReplicaSet控制器对象下删除并创建Pod,会先创建一个新的ReplicaSet控制器,然后新控制器的Pod数量不断增加,旧控制器的Pod相应不断减少,直到旧控制器不再拥有Pod,而新控制器的Pod副本数量达到期望值为止。如下图所示:
    6
    滚动更新可以指定spec.strategy.rollingUpdate.maxSurgespec.strategy.rollingUpdate.maxUnavailable来控制滚动更新过程。其功能如下:

    • maxSurge:指定在期望的Pod副本数的基础之上再创建的最大Pod数量。该值可以是绝对数字(例如,5)或所需Pod的百分比(例如,10%)。如果spec.strategy.rollingUpdate.maxUnavailabl为0,则该值不能为 0。绝对数字通过四舍五入从百分比中得出的。默认值为25%。
    • maxUnavailable:指定更新期间不可用的Pod的最大数量。该值可以是绝对数字(例如,5)或所需Pod的百分比(例如,10%)。绝对数字是通过四舍五入从百分比中得出的。 如果spec.strategy.rollingUpdate.maxSurge为0,则该值不能为0。默认为25%。

    2.重新创建

    先创建资源清单mynginx-deploy-recreate.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mynginx-deploy-recreate
      labels:
        app: mynginx
        env: test
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: mynginx
          env: test
      strategy:
        type: Recreate  
      template:
        metadata:
          labels:
            app: mynginx
            env: test
        spec:
          containers:
          - name: nginx
            image: mynginx:v1
            imagePullPolicy: IfNotPresent
            ports:
            - name: http
              containerPort: 80        
    

    创建Deployment并查看DeploymentReplicaSetPod,然后访问其中一个Pod可知更新前使用的mynginx:v1镜像:
    7
    Deploymentspec.template.spec.containers[0].imagemynginx:v1改为mynginx:v2

    kubectl edit deployment.v1.apps/mynginx-deploy-recreate
    

    之后马上查看Pod的状态,由于删除得太快,这里只截到有两个旧Pod已经被删除,只剩一个旧的Pod处于正在终止状态,并且3个Pod都被删除后才开始创建新的Pod
    8
    同时新开三个终端查看DeploymentReplicaSetPod变化过程:

    kubectl get deployment mynginx-deploy-recreate -w
    kubectl get rs -w
    kubectl get pod -o wide -w
    

    9
    10
    11
    查看DeploymentReplicaSet
    12
    再次查看Pod,发现旧Pod已全部被新创建的Pod取代:
    13
    查看Deployment描述信息:
    14
    然后访问其中一个Pod,发现使用了mynginx:v2镜像,说明更新成功:
    15
    最后清理之前创建的资源对象。

    3.滚动更新

    先通过之前的Deployment示例的清单文件mynginx-deployment.yaml创建Deployment,然后在此基础上进行滚动更新操作。在更新之前先查看DeploymentReplicaSetPod,然后访问其中一个Pod可知更新前使用的mynginx:v1镜像:
    16
    下面更新nginxPod,可以执行以下命令更新:

    kubectl --record deployment.apps/mynginx-deployment set image deployment.v1.apps/mynginx-deployment nginx=mynginx:v2
    

    也可以使用editDeploymentspec.template.spec.containers[0].imagemynginx:v1改为mynginx:v2

    kubectl edit deployment.v1.apps/nginx-deployment
    

    之后马上查看Pod的状态,可以发现旧的pod正在被终止,而一个新的ReplicaSet也在创建新的pod
    17
    查看展开状态,新ReplicaSet已成功展开:
    18
    同时新开三个终端查看DeploymentReplicaSetPod变化过程:
    19
    20
    21
    查看DeploymentReplicaSet
    22
    再次查看Pod,发现旧Pod已全部被新创建的Pod取代:
    23
    查看Deployment描述信息:
    24
    访问其中一个Pod,发现使用了mynginx:v2镜像,说明更新成功:
    25
    最后清理之前创建的资源对象。

    3.Rollover

    每次Deployment控制器观察新Deployment时,都会创建一个ReplicaSet以启动所期望的Pod。如果更新了Deployment ,则已存在的 ReplicaSet控制其标签spec.selector匹配但其模板与spec.template不匹配的Pod缩容。最终,新的ReplicaSet将会扩容出spec.replicas指定数目的Pod,旧的ReplicaSet会缩容到0。

    如果更新了一个的已存在并正在进行中的Deployment,每次更新Deployment都会创建一个新的ReplicaSet并扩容它,同时回滚之前扩容的ReplicaSet——将它添加到旧的ReplicaSet列表中并开始缩容。例如,假设创建一个Deployment以创建5个nginx:1.7.9的副本,然后更新Deployment以创建5个 nginx:1.9.1 的副本,而此时只有3个nginx:1.7.9 的副本已创建。在这种情况下, Deployment会立即开始杀死3个nginx:1.7.9的Pod,并开始创建nginx:1.9.1的Pod。它不会等到5个nginx:1.7.9的副本都创建完成之后才改变任务。

    五、回滚Deployment

    默认情况下,所有Deployment历史记录都保留在系统中,以便可以随时回滚。

    1.查看Deployment历史记录

    首先通过资源清单文件mynginx-deployment.yaml创建Deployment,然后更新镜像为v2版。更新后的Pod信息如下:
    26
    查看Deployment修改历史:

    kubectl rollout history deployment.v1.apps/mynginx-deployment
    

    27
    查看修改历史的详细信息:

    kubectl rollout history deployment.v1.apps/mynginx-deployment --revision=2
    

    28

    2.回滚到上一版本

    回滚到上一版本:

    kubectl rollout undo deployment.v1.apps/mynginx-deployment
    

    然后立马查看Pod
    29
    查看DeploymentReplicaSet
    30
    查看Deployment描述信息:
    31
    访问其中一个Pod,发现使用了mynginx:v1镜像,说明回滚到上一版本成功:
    32

    3.回滚到指定历史版本

    回滚到版本2:

    kubectl rollout undo deployment.v1.apps/mynginx-deployment --to-revision=2
    

    然后立马查看Pod
    33
    查看DeploymentReplicaSet
    34
    查看Deployment描述信息:
    35
    访问其中一个Pod,发现使用了mynginx:v2镜像,说明回滚到版本2成功:
    36

    4.清理策略

    在Deployment中设置spec.revisionHistoryLimit,以指定此Deployment要保留的旧ReplicaSet的数量以允许回滚,多余的ReplicaSet将在后台进行垃圾回收,默认值为10。如果显式将此字段设置为0将会清理Deployment的所有历史记录,因此Deployment将无法回滚。

    六、缩放Deployment

    扩容到10个副本:

    kubectl scale deployment.v1.apps/mynginx-deployment --replicas=10
    

    查看DeploymentPod
    37
    缩容到3个副本:

    kubectl scale deployment.v1.apps/mynginx-deployment --replicas=3
    

    查看DeploymentPod
    38
    如果集群中启用了HPA,可以为Deployment设置autoscale,基于现有Pod的CPU利用率进行自动缩放,当CPU利用率超过80%,Pod最多不超过15个,当CPU利用率低于80%,Pod最低不少于10个:

    kubectl autoscale deployment.v1.apps/mynginx-deployment --min=10 --max=15 --cpu-percent=80
    

    最后清理之前创建的资源对象。

    七、暂停和恢复Deployment

    可以在触发一个或多个更新之前暂停Deployment,然后再恢复它。这允许在Deployment暂停和恢复之间修复应用多个程序,而不会触发不必要的展开(rollout)。首先通过资源清单文件mynginx-deployment.yaml创建Deployment,然后查看DeploymentReplicaSet信息:
    39
    执行以下命令暂停Deployment

    kubectl rollout pause deployment.v1.apps/mynginx-deployment
    

    然后更新DeploymentPod使用的镜像:

    kubectl set image deployment.v1.apps/mynginx-deployment nginx=mynginx:v2
    

    查看Deployment修改历史,发现没有新的展开:
    40
    可以进行任意多次更新,例如更新使用到的资源:

    kubectl set resources deployment.v1.apps/mynginx-deployment -c