Deployment

Deployment资源是一种更为高阶的资源,它通过创建ReplicaSet的资源的方式,接管匹配标签的Pods。

通常我们使用Deployment来部署应用程序,从而方便通过声明的方式升级应用,即通过Deployment可以更容易地更新应用程序,通过声明Deployment资源需要到达的状态,Kubernetes会帮我们达到最终需要的状态。

创建Deployment

如其他资源一样,可以通过编写YAML配置文件的格式创建Deployment资源。

下面介绍一个具体的Deployment的YAML配置文件:

apiVersion: apps/v1    # 注意版本信息
kind: Deployment    # 资源类型为Deployment
metadata:
  name: httpd
  namespace: default    # Deployment所在命名空间,默认为default
  labels:    # Deployment的标签
    run: httpd
spec:
  progressDeadlineSeconds: 600 # 滚动升级超时时间,默认为600s,超时后,describe结果中的Conditions会显示ProgressDeadlineExceeded。当超过这个时间后,需要使用kubectl rollout undo来回滚升级
  revisionHistoryLimit: 10    # 增加回滚记录中可以保存的版本数(因为Deployment更新后,不会删除旧的RS,所以这里其实就是保存的最大RS数)
  replicas: 3    # 产生的副本个数
  minReadySeconds: 10    # 用来减慢滚动更新的速度(容器需要至少Ready10s后才能认定其为可用,在Pod可用前,滚动升级过程不会继续),配合Readiness探针,可以实现当滚动升级过程中发现Pod出错,可以立即停止滚动更新
  strategy:
    type: RollingUpdate    # 更新策略(这种是删一个旧的,加一个新的,还有一种是Recreate,即全部删除旧的后,再创建新的)
    rollingUpdate:    # 定制滚动更新中的策略(适用于RollingUpdate,type为Recreate,则该字段为空)
      maxSurge: 35%        # 滚动更新中副本总数可超过DESIRED的上限(向上取整)
      maxUnavailable: 35%    # 滚动更新中不可用的副本占DESIRED的最大比例(向下取整)
  selector:        # (必须)用于匹配Pod的labels
    matchLabels:
      run: httpd
  template:    # (必须)Pod的模板
    metadata:
      labels:
        run: httpd
    spec:    # Pod的规格
      containers:
      - name: httpd
        image: httpd:2.4.17
        ports:
        - containerPort: 80    # 容器暴露的Port,其实这里只是一个类似于声明的,这里即使不写,容器的应用可能也暴露该端口
        env:    # docker的ENV
        - name: MYNAME
          value: http
      nodeSelector:    # 根据Nodes的label选择合适的Node部署Pods
        disktype: ssd

然后可以使用kubectl apply -f生成该资源。

通过kubectl get deployments可以看到创建出来的Deployment资源的名字为httpd,再通过kubectl get rs可以看到创建出来的RS的名字为httpd-xxxxxx,再通过kubectl get pods可以看到创建的Pods的名字为httpd-xxxxxx-yyyy(xxxxxxx和yyyy为自动生成的值)。

通过Deployment更新

通过Deployment进行滚动升级是声明式的,即只需要通过修改Deployment中的Pod模板,它会自动将集群中的状态收敛至该目标状态。

Deployment有两种更新策略,具体配置可以看上面的Deployment的YAML配置文件详情:

  • RollingUpdate:默认策略,滚动升级,逐个删除旧Pod的同时创建新Pod;

  • Recreate:一次性删除所有旧Pod,然后创建新Pod;

更新过程

之前提到,Deployment首先创建ReplicaSet,再由ReplicaSet负责创建并接管Pod。

升级Deployment非常容易,只需要修改资源的配置文件即可,修改方式见修改资源

Deployment滚动升级流程

Tips: pod-template-hash是Deployment创建RS时自动生成的,用来区分新旧Pod,这里与ReplicationController配合rolling-update进行滚动更新的方式有点像。但是这个标签对于Deployment和用户是无感的,因为用户直接对接的是Deployment,这也是为什么用Deployment更新应用的优势之一。

从上图中,可以将升级流程归纳为以下几步:

  1. Deployment创建一个新的RS,负责创建并接管新的Pod,其与旧RS具有不同值的pod-template-hash标签

  2. 逐步对旧RS缩容的同时,对新RS扩容,直至更新完毕。

  3. 在更新完毕后,会保存旧的RS,当使用Deployment进行回滚时,可以使用保存的旧的RS扩容旧的Pod的同时,使用新的RS缩容新的Pod。若Deployment接管的RS总数超过了spec.revisionHistoryLimit(默认为10),则删除保存时间最久的RS;

ReplicationController滚动更新对比,可以总结出以下优势:

  • 更新流程均由Deployment这个控制器完成,与kubectl客户端解耦;

  • 用户不用关心创建或删除RS,对用户无感,Deployment的标签无需修改;

  • 由于Deployment可以保存历史RS,所以可以方便应用回滚;

maxSurge和maxUnavailable

RollingUpdate这种滚动更新策略中,可以指定maxSurgemaxUnavailable两个属性。

  • maxSurge:定义除Deployment的spec.replicas个Pod外,最多能超过的Pod数量,默认值为25%,向上取整。例如,spec.replicas=4,则maxSurge=4*25%=1,也就是说当前的最多的Pod数不超过4+1=5个;

  • maxUnavailable:定义了相对于Deployment的spec.replicas允许有多少Pod实例处于不可用状态,默认值为25%,向下取整。例如,spec.replicas=4,则maxUnavailable=4*25%=1,也就是说在滚动更新过程中,原本4个可用的Pod中,可以有一个被替换(若maxSurge计算得1,也就是Pod数不超过5,那么还可以再部署一个新的Pod,也就是同一时间可能有2个Pod不可用,3个Pod可用)。

下面举一个例子,更直观的观察滚动更新的流程,Deployment的spec.replicas=4maxSurge=25%maxUnavailable=25%

滚动更新中新旧Pod变化流程

假设A=maxSurgeB=maxUnavailableX=spec.replicas,那么可以得到下面的公式:

  1. 更新过程中,最少可用Pod数 = X - B;

  2. 每轮更新过程中,新RS可创建最大Pod数 = 旧RS可删除最大Pod数 = A + B;

Tips: 说最大Pod数的原因是,需要考虑当前可用Pod数,如上图第一列,因为需要保证有3个可用Pod,所以旧RS在这里只能删除1个v1 Pod;倒数第二列,也是如此。

使用rollout控制更新流程

观察升级过程

可以通过rollout status观察Deployment资源对象的升级过程。例如,观察Deployment对象kubia的升级过程:

kubectl rollout status deployment kubia

查看滚动升级历史

可以通过rollout history查看Deployment资源对象的滚动升级历史。例如,观察Deployment对象kubia的滚动升级历史:

kubectl rollout history deployment kubia

Tips: 默认滚动升级历史为空,需要在使用kubectl create -fkubectl apply -f创建Deployment资源的同时加上--record标志,才会将该操作加入滚动历史中。

回滚升级

可以通过rollout undo进行回滚,可以加上--to-revision标志,指定回滚的确切版本。例如,针对Deployment对象进行回滚:

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

Tips: --to-revision后面的版本号是滚动升级历史中的版本号。

暂停和恢复升级流程

可以通过rollout pause暂停Deployment资源对象的滚动升级流程,从而方便用户验证新的版本行为是否符合预期,即金丝雀版本(灰度),一部分为新版本,一部分为旧版本。例如,将Deployment对象kubia的滚动更新流程暂停:

kubectl rollout pause deployment kubia

恢复流程可以通过rollout resume来实现。例如:

kubectl rollout resume deployment kubia

Last updated

Was this helpful?