29.Deployment

Deployment

DeploymentPodReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:

  • 定义Deployment来创建PodReplicaSet
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续Deployment

比如一个简单的nginx应用可以定义为:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
            - containerPort: 80

扩容:

kubectl scale deployment nginx-deployment --replicas 10

如果集群支持horizontal pod autoscaling的话,还可以为Deployment设置自动扩展:

kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80

更新镜像也比较简单:

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

回滚:

kubectl rollout undo deployment/nginx-deployment

Deployment结构示意图

kubernetes deployment cheatsheet
Kubernetes Deployment Cheatsheet

Deployment是什么?

DeploymentPodReplica Set(下一代Replication Controller)提供声明式更新。

您只需要在Deployment中描述您想要的目标状态是什么,Deployment controller就会帮您将PodReplicaSet的实际状态改变到您的目标状态。您可以定义一个全新的Deployment来创建ReplicaSet或者删除已有的Deployment并创建一个新的来替换。

注意:您不该手动管理由Deployment创建的ReplicaSet,否则您就篡越了Deployment controller的职责!下文罗列了Deployment对象中已经覆盖了所有的用例。如果未有覆盖您所有需要的用例,请直接在Kubernetes的代码库中提issue

典型的用例如下:

  • 使用Deployment来创建ReplicaSetReplicaSet在后台创建pod。检查启动状态,看它是成功还是失败。
  • 然后,通过更新DeploymentPodTemplateSpec字段来声明Pod的新状态。这会创建一个新的ReplicaSetDeployment会按照控制的速率将pod从旧的ReplicaSet移动到新的ReplicaSet中。
  • 如果当前状态不稳定,回滚到之前的Deployment revision。每次回滚都会更新Deploymentrevision
  • 扩容Deployment以满足更高的负载。
  • 暂停Deployment来应用PodTemplateSpec的多个修复,然后恢复上线。
  • 根据Deployment的状态判断上线是否hang住了。
  • 清除旧的不必要的ReplicaSet

创建Deployment

下面是一个Deployment示例,它创建了一个ReplicaSet来启动3nginx pod

下载示例文件并执行命令:

$ kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record
deployment "nginx-deployment" created

kubectl--recordflag设置为true 可以在annotation中记录当前命令创建或者升级了该资源。这在未来会很有用,例如,查看在每个Deployment revision中执行了哪些命令。

然后立即执行 get 将获得如下结果:

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         0         0            0           1s

输出结果表明我们希望的repalica数是3(根据deployment中的.spec.replicas配置)当前replica数(.status.replicas)是0,最新的replica数(.status.updatedReplicas)是0,可用的replica数(.status.availableReplicas)是0

过几秒后再执行 get 命令,将获得如下输出:

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           18s

我们可以看到Deployment已经创建了3replica,所有的replica都已经是最新的了(包含最新的pod template,可用的(根据Deployment中的.spec.minReadySeconds声明,处于已就绪状态的pod的最少个数。执行kubectl get rskubectl get pods会显示Replica Set(RS)和Pod已创建。

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-2035384211   3         3         0       18s

您可能会注意到ReplicaSet的名字总是<Deployment 的名字>-<pod template 的 hash 值>

$ kubectl get pods --show-labels
NAME                                READY     STATUS    RESTARTS   AGE       LABELS
nginx-deployment-2035384211-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=2035384211
nginx-deployment-2035384211-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=2035384211
nginx-deployment-2035384211-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=2035384211

刚创建的Replica Set将保证总是有3nginxpod存在。

注意: 您必须在Deployment中的selector指定正确的pod template label(在该示例中是 app = nginx,不要跟其他的controllerselector中指定的pod template label搞混了(包括Deployment、Replica Set、Replication ControllerKubernetes本身并不会阻止您任意指定pod template label,但是如果您真的这么做了,这些controller之间会相互打架,并可能导致不正确的行为。

Pod-template-hash label

注意:这个label不是用户指定的!

注意上面示例输出中的pod label里的pod-template-hash label。当Deployment创建或者接管ReplicaSet时,Deployment controller会自动为Pod添加pod-template-hash label。这样做的目的是防止Deployment的子ReplicaSetpod名字重复。通过将ReplicaSetPodTemplate进行哈希散列,使用生成的哈希值作为label的值,并添加到ReplicaSet selector里、 pod template labelReplicaSet管理中的Pod上。

更新Deployment

注意Deploymentrollout当且仅当Deploymentpod template(例如 .spec.template)中的label更新或者镜像更改时被触发。其他更新,例如扩容Deployment不会触发rollout

假如我们现在想要让nginx pod使用 nginx:1.9.1 的镜像来代替原来的 nginx:1.7.9 的镜像。

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment "nginx-deployment" image updated

我们可以使用edit命令来编辑Deployment,修改.spec.template.spec.containers [0].image,将nginx:1.7.9改写成nginx:1.9.1

$ kubectl edit deployment/nginx-deployment
deployment "nginx-deployment" edited

查看rollout的状态,只要执行:

$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out

Rollout成功后,getDeployment:

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           36s

UP-TO-DATEreplica的数目已经达到了配置中要求的数目。

CURRENTreplica数表示Deployment管理的replica数量,AVAILABLEreplica数是当前可用的replica数量。

我们通过执行 kubectl get rs 可以看到Deployment更新了Pod,通过创建一个新的ReplicaSet并扩容了3replica,同时将原来的ReplicaSet缩容到了0replica

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-1564180365   3         3         0       6s
nginx-deployment-2035384211   0         0         0       36s

执行get pods只会看到当前的新的pod

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1564180365-khku8   1/1       Running   0          14s
nginx-deployment-1564180365-nacti   1/1       Running   0          14s
nginx-deployment-1564180365-z9gth   1/1       Running   0          14s

下次更新这些pod的时候,只需要更新Deployment中的podtemplate即可。

Deployment可以保证在升级时只有一定数量的Poddown的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用

Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod。默认的,它会确保最多比期望的Pod数量多一个的Podup的(最多1surge

在未来的Kuberentes版本中,将从1-1变成25%-25%

例如,如果您自己看下上面的Deployment,您会发现,开始创建一个新的Pod,然后删除一些旧的Pod再创建一个新的。当新的Pod创建出来之前不会杀掉旧的Pod。这样能够确保可用的Pod数量至少有2个,Pod的总数最多4个。

$ kubectl describe deployments
Name:           nginx-deployment
Namespace:      default
CreationTimestamp:  Tue, 15 Mar 2016 12:01:06 -0700
Labels:         app=nginx
Selector:       app=nginx
Replicas:       3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
OldReplicaSets:     <none>
NewReplicaSet:      nginx-deployment-1564180365 (3/3 replicas created)
Events:
  FirstSeen LastSeen    Count   From                     SubobjectPath   Type        Reason              Message
  --------- --------    -----   ----                     -------------   --------    ------              -------
  36s       36s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
  23s       23s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
  23s       23s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
  23s       23s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
  21s       21s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
  21s       21s         1       {deployment-controller}                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3

我们可以看到当我们刚开始创建这个Deployment的时候,创建了一个ReplicaSet(nginx-deployment-2035384211,并直接扩容到了3replica

当我们更新这个Deployment的时候,它会创建一个新的ReplicaSet(nginx-deployment-1564180365,将它扩容到1replica,然后缩容原先的ReplicaSet2replica,此时满足至少2Pod是可用状态,同一时刻最多有4Pod处于创建的状态。

接着继续使用相同的rolling update策略扩容新的ReplicaSet和缩容旧的ReplicaSet。最终,将会在新的ReplicaSet中有3个可用的replica,旧的ReplicaSetreplica数目变成0

Rollover(多个rollout并行)

每当Deployment controller观测到有新的deployment被创建时,如果没有已存在的ReplicaSet来创建期望个数的Pod的话,就会创建出一个新的ReplicaSet来做这件事。已存在的ReplicaSet控制label.spec.selector 匹配但是template.spec.template 不匹配的Pod缩容。最终,新的ReplicaSet将会扩容出 .spec.replicas 指定数目的Pod,旧的ReplicaSet会缩容到0

如果您更新了一个的已存在并正在进行中的Deployment,每次更新Deployment都会创建一个新的ReplicaSet并扩容它,同时回滚之前扩容的ReplicaSet —— 将它添加到旧的ReplicaSet列表中,开始缩容。

例如,假如您创建了一个有5niginx:1.7.9replicaDeployment,但是当还只有3nginx:1.7.9replica创建出来的时候您就开始更新含有5nginx:1.9.1replicaDeployment。在这种情况下,Deployment会立即杀掉已创建的3nginx:1.7.9Pod,并开始创建 nginx:1.9.1Pod。它不会等到所有的5nginx:1.7.9Pod都创建完成后才开始改变航道。

Label selector更新

我们通常不鼓励更新label selector,我们建议事先规划好您的selector

任何情况下,只要您想要执行label selector的更新,请一定要谨慎并确认您已经预料到所有可能因此导致的后果。

  • 增添selector需要同时在Deploymentspec中更新新的label,否则将返回校验错误。此更改是不可覆盖的,这意味着新的selector不会选择使用旧selector创建的ReplicaSetPod,从而导致所有旧版本的ReplicaSet都被丢弃,并创建新的ReplicaSet
  • 更新selector,即更改selector key的当前值,将导致跟增添selector同样的后果。
  • 删除selector,即删除Deployment selector中的已有的key,不需要对Pod template label做任何更改,现有的ReplicaSet也不会成为孤儿,但是请注意,删除的label仍然存在于现有的PodReplicaSet中。

回退Deployment

有时候您可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping

默认情况下,kubernetes会在系统中保存前两次的Deploymentrollout历史记录,以便您可以随时回退(您可以修改 revision history limit 来更改保存的revision

注意:只要Deploymentrollout被触发就会创建一个revision。也就是说当且仅当DeploymentPod template(如 .spec.template)被更改,例如更新template中的label和容器镜像时,就会创建出一个新的revision

其他的更新,比如扩容Deployment不会创建revision—— 因此我们可以很方便的手动或者自动扩容。这意味着当您回退到历史revision时,只有Deployment中的Pod template部分才会回退。

假设我们在更新Deployment的时候犯了一个拼写错误,将镜像的名字写成了 nginx:1.91,而正确的名字应该是 nginx:1.9.1

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91
deployment "nginx-deployment" image updated

Rollout将会卡住。

$ kubectl rollout status deployments nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...

按住Ctrl-C停止上面的rollout状态监控。

您会看到旧的replicanginx-deployment-1564180365nginx-deployment-2035384211)和新的replica (nginx-deployment-3066724191)数目都是2个。

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-1564180365   2         2         0       25s
nginx-deployment-2035384211   0         0         0       36s
nginx-deployment-3066724191   2         2         2       6s

看下创建Pod,您会看到有两个新的ReplicaSet创建的Pod处于ImagePullBackOff状态,循环拉取镜像。

$ kubectl get pods
NAME                                READY     STATUS             RESTARTS   AGE
nginx-deployment-1564180365-70iae   1/1       Running            0          25s
nginx-deployment-1564180365-jbqqo   1/1       Running            0          25s
nginx-deployment-3066724191-08mng   0/1       ImagePullBackOff   0          6s
nginx-deployment-3066724191-eocby   0/1       ImagePullBackOff   0          6s

注意,Deployment controller会自动停止坏的rollout,并停止扩容新的ReplicaSet

$ kubectl describe deployment
Name:           nginx-deployment
Namespace:      default
CreationTimestamp:  Tue, 15 Mar 2016 14:48:04 -0700
Labels:         app=nginx
Selector:       app=nginx
Replicas:       2 updated | 3 total | 2 available | 2 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
OldReplicaSets:     nginx-deployment-1564180365 (2/2 replicas created)
NewReplicaSet:      nginx-deployment-3066724191 (2/2 replicas created)
Events:
  FirstSeen LastSeen    Count   From                    SubobjectPath   Type        Reason              Message
  --------- --------    -----   ----                    -------------   --------    ------              -------
  1m        1m          1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
  22s       22s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
  22s       22s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
  22s       22s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
  21s       21s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
  21s       21s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3
  13s       13s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 1
  13s       13s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-1564180365 to 2
  13s       13s         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 2

为了修复这个问题,我们需要回退到稳定的Deployment revision

检查Deployment升级的历史记录

首先,检查下Deploymentrevision

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment":
REVISION    CHANGE-CAUSE
1           kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml--record
2           kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
3           kubectl set image deployment/nginx-deployment nginx=nginx:1.91

因为我们创建Deployment的时候使用了--record 参数可以记录命令,我们可以很方便的查看每次revision的变化。

查看单个revision的详细信息:

$ kubectl rollout history deployment/nginx-deployment --revision=2
deployments "nginx-deployment" revision 2
  Labels:       app=nginx
          pod-template-hash=1159050644
  Annotations:  kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
  Containers:
   nginx:
    Image:      nginx:1.9.1
    Port:       80/TCP
     QoS Tier:
        cpu:      BestEffort
        memory:   BestEffort
    Environment Variables:      <none>
  No volumes.

回退到历史版本

现在,我们可以决定回退当前的rollout到之前的版本:

$ kubectl rollout undo deployment/nginx-deployment
deployment "nginx-deployment" rolled back

也可以使用--revision参数指定某个历史版本:

$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment "nginx-deployment" rolled back

Deployment现在已经回退到了先前的稳定版本。如您所见,Deployment controller产生了一个回退到revison 2DeploymentRollbackevent

$ kubectl get deployment
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           30m

$ kubectl describe deployment
Name:           nginx-deployment
Namespace:      default
CreationTimestamp:  Tue, 15 Mar 2016 14:48:04 -0700
Labels:         app=nginx
Selector:       app=nginx
Replicas:       3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
OldReplicaSets:     <none>
NewReplicaSet:      nginx-deployment-1564180365 (3/3 replicas created)
Events:
  FirstSeen LastSeen    Count   From                    SubobjectPath   Type        Reason              Message
  --------- --------    -----   ----                    -------------   --------    ------              -------
  30m       30m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 2
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 1
  29m       29m         1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-1564180365 to 2
  2m        2m          1       {deployment-controller}                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-3066724191 to 0
  2m        2m          1       {deployment-controller}                Normal      DeploymentRollback  Rolled back deployment "nginx-deployment" to revision 2
  29m       2m          2       {deployment-controller}                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3

清理Policy

您可以通过设置 .spec.revisonHistoryLimit 项来指定deployment最多保留多少revision历史记录。默认的会保留所有的revision;如果将该项设置为0Deployment就不允许回退了。

Deployment扩容

您可以使用以下命令扩容Deployment

$ kubectl scale deployment nginx-deployment --replicas 10
deployment "nginx-deployment" scaled

假设您的集群中启用了 horizontal pod autoscaling,您可以给Deployment设置一个autoscaler,基于当前PodCPU利用率选择最少和最多的Pod数。

$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
deployment "nginx-deployment" autoscaled

比例扩容

RollingUpdate Deployment支持同时运行一个应用的多个版本。或者autoscaler扩 容RollingUpdate Deployment的时候,正在中途的rollout(进行中或者已经暂停的,为了降低风险,Deployment controller将会平衡已存在的活动中的ReplicaSet(有PodReplicaSet)和新加入的replica。这被称为比例扩容。

例如,您正在运行中含有10replicaDeployment。maxSurge=3,maxUnavailable=2。

$ kubectl get deploy
NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment     10        10        10           10          50s

您更新了一个镜像,而在集群内部无法解析。

$ kubectl set image deploy/nginx-deployment nginx=nginx:sometag
deployment "nginx-deployment" image updated

镜像更新启动了一个包含ReplicaSet nginx-deployment-1989198191的新的rollout,但是它被阻塞了,因为我们上面提到的maxUnavailable

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-1989198191   5         5         0         9s
nginx-deployment-618515232    8         8         8         1m

然后发起了一个新的Deployment扩容请求。autoscalerDeploymentrepllica数目增加到了15个。Deployment controller需要判断在哪里增加这5个新的replica。如果我们没有谁用比例扩容,所有的5replica都会加到一个新的ReplicaSet中。如果使用比例扩容,新添加的replica将传播到所有的ReplicaSet中。大的部分加入replica数最多的ReplicaSet中,小的部分加入到replica数少的ReplciaSet中。0replicaReplicaSet不会被扩容。

在我们上面的例子中,3replica将添加到旧的ReplicaSet中,2replica将添加到新的ReplicaSet中。rollout进程最终会将所有的replica移动到新的ReplicaSet中,假设新的replica成为健康状态。

$ kubectl get deploy
NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment     15        18        7            8           7m
$ kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-1989198191   7         7         0         7m
nginx-deployment-618515232    11        11        11        7m

删除autoscale

kubectl get hpa
kubectl delete hpa ${name of hpa}

暂停和恢复Deployment

您可以在发出一次或多次更新前暂停一个Deployment,然后再恢复它。这样您就能在Deployment暂停期间进行多次修复工作,而不会发出不必要的rollout

例如使用刚刚创建Deployment

$ kubectl get deploy
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     3         3         3            3           1m
[mkargaki@dhcp129-211 kubernetes]$ kubectl get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-2142116321   3         3         3         1m

使用以下命令暂停Deployment

$ kubectl rollout pause deployment/nginx-deployment
deployment "nginx-deployment" paused

然后更新Deplyment中的镜像:

$ kubectl set image deploy/nginx nginx=nginx:1.9.1
deployment "nginx-deployment" image updated

注意新的rollout启动了:

$ kubectl rollout history deploy/nginx
deployments "nginx"
REVISION  CHANGE-CAUSE
1   <none>

$ kubectl get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-2142116321   3         3         3         2m

您可以进行任意多次更新,例如更新使用的资源:

$ kubectl set resources deployment nginx -c=nginx --limits=cpu=200m,memory=512Mi
deployment "nginx" resource requirements updated

Deployment暂停前的初始状态将继续它的功能,而不会对Deployment的更新产生任何影响,只要Deployment是暂停的。

最后,恢复这个Deployment,观察完成更新的ReplicaSet已经创建出来了:

$ kubectl rollout resume deploy nginx
deployment "nginx" resumed
$ KUBECTL get rs -w
NAME               DESIRED   CURRENT   READY     AGE
nginx-2142116321   2         2         2         2m
nginx-3926361531   2         2         0         6s
nginx-3926361531   2         2         1         18s
nginx-2142116321   1         2         2         2m
nginx-2142116321   1         2         2         2m
nginx-3926361531   3         2         1         18s
nginx-3926361531   3         2         1         18s
nginx-2142116321   1         1         1         2m
nginx-3926361531   3         3         1         18s
nginx-3926361531   3         3         2         19s
nginx-2142116321   0         1         1         2m
nginx-2142116321   0         1         1         2m
nginx-2142116321   0         0         0         2m
nginx-3926361531   3         3         3         20s
^C
$ KUBECTL get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-2142116321   0         0         0         2m
nginx-3926361531   3         3         3         28s

注意:在恢复Deployment之前您无法回退一个已经暂停的Deployment

Deployment状态

Deployment在生命周期中有多种状态。在创建一个新的ReplicaSet的时候它可以是 progressing 状态, complete 状态,或者 fail to progress 状态。

进行中的Deployment

Kubernetes将执行过下列任务之一的Deployment标记为progressing状态:

  • Deployment正在创建新的ReplicaSet过程中。
  • Deployment正在扩容一个已有的ReplicaSet
  • Deployment正在缩容一个已有的ReplicaSet
  • 有新的可用的pod出现。

您可以使用 kubectl rollout status 命令监控Deployment的进度。

完成的Deployment

Kubernetes将包括以下特性的Deployment标记为complete状态:

  • Deployment最小可用。最小可用意味着Deployment的可用replica个数等于或者超过Deployment策略中的期望个数。
  • 所有与该Deployment相关的replica都被更新到了您指定版本,也就说更新完成。
  • Deployment中没有旧的Pod存在。

您可以用 kubectl rollout status 命令查看Deployment是否完成。如果rollout成功完成,kubectl rollout status 将返回一个0值的Exit Code

$ kubectl rollout status deploy/nginx
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx" successfully rolled out
$ echo $?
0

失败的Deployment

您的Deployment在尝试部署新的ReplicaSet的时候可能卡住,永远也不会完成。这可能是因为以下几个因素引起的:

  • 无效的引用
  • 不可读的probe failure
  • 镜像拉取错误
  • 权限不够
  • 范围限制
  • 程序运行时配置错误

探测这种情况的一种方式是,在您的Deployment spec中指定 spec.progressDeadlineSecondsspec.progressDeadlineSeconds 表示Deployment controller等待多少秒才能确定(通过Deployment statusDeployment进程是卡住的。

下面的 kubectl 命令设置 progressDeadlineSeconds 使controllerDeployment在进度卡住10分钟后报告:

$ kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
"nginx-deployment" patched

当超过截止时间后,Deployment controller会在Deploymentstatus.conditions 中增加一条DeploymentCondition,它包括如下属性:

  • Type=Progressing
  • Status=False
  • Reason=ProgressDeadlineExceeded

注意kubernetes除了报告 Reason=ProgressDeadlineExceeded 状态信息外不会对卡住的Deployment做任何操作。更高层次的协调器可以利用它并采取相应行动,例如,回滚Deployment到之前的版本。

注意:如果您暂停了一个Deployment,在暂停的这段时间内kubernetnes不会检查您指定的deadline。您可以在Deploymentrollout途中安全的暂停它,然后再恢复它,这不会触发超过deadline的状态。

您可能在使用Deployment的时候遇到一些短暂的错误,这些可能是由于您设置了太短的timeout,也有可能是因为各种其他错误导致的短暂错误。例如,假设您使用了无效的引用。当您Describe Deployment的时候可能会注意到如下信息:

$ kubectl describe deployment nginx-deployment
<...>
Conditions:
  Type            Status  Reason
----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     True    ReplicaSetUpdated
  ReplicaFailure  True    FailedCreate
<...>

执行kubectl get deployment nginx-deployment -o yamlDeployement的状态可能看起来像这个样子:

status:
  availableReplicas: 2
  conditions:
    - lastTransitionTime: 2016-10-04T12:25:39Z
      lastUpdateTime: 2016-10-04T12:25:39Z
      message: Replica set "nginx-deployment-4262182780" is progressing.
      reason: ReplicaSetUpdated
      status: "True"
      type: Progressing
    - lastTransitionTime: 2016-10-04T12:25:42Z
      lastUpdateTime: 2016-10-04T12:25:42Z
      message: Deployment has minimum availability.
      reason: MinimumReplicasAvailable
      status: "True"
      type: Available
    - lastTransitionTime: 2016-10-04T12:25:39Z
      lastUpdateTime: 2016-10-04T12:25:39Z
      message:
        'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
        object-counts, requested: pods=1, used: pods=3, limited: pods=2'
      reason: FailedCreate
      status: "True"
      type: ReplicaFailure
      observedGeneration: 3
      replicas: 2
      unavailableReplicas: 2

最终,一旦超过Deployment进程的deadlinekubernetes会更新状态和导致Progressing状态的原因:

Conditions:
    Type            Status  Reason
----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     False   ProgressDeadlineExceeded
  ReplicaFailure  True    FailedCreate

您可以通过缩容Deployment的方式解决配额不足的问题,或者增加您的namespace的配额。如果您满足了配额条件后,Deployment controller就会完成您的Deployment rollout,您将看到Deployment的状态更新为成功状态(Status=True并且Reason=NewReplicaSetAvailable

Conditions:
  Type          Status  Reason
----          ------  ------
  Available     True    MinimumReplicasAvailable
  Progressing   True    NewReplicaSetAvailable

Type=AvailableStatus=True 意味着您的Deployment有最小可用性。最小可用性是在Deployment策略中指定的参数。Type=ProgressingStatus=True 意味着您的Deployment或者在部署过程中,或者已经成功部署,达到了期望的最少的可用replica数量(查看特定状态的Reason—— 在我们的例子中 Reason=NewReplicaSetAvailable 意味着Deployment已经完成

您可以使用 kubectl rollout status 命令查看Deployment进程是否失败。当Deployment过程超过了deadlinekubectl rollout status 将返回非0exit code

$ kubectl rollout status deploy/nginx
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1

操作失败的Deployment

所有对完成的Deployment的操作都适用于失败的Deployment。您可以对它扩/缩容,回退到历史版本,您甚至可以多次暂停它来应用Deployment pod template

清理Policy

您可以设置Deployment中的 .spec.revisionHistoryLimit 项来指定保留多少旧的ReplicaSet。余下的将在后台被当作垃圾收集。默认的,所有的revision历史就都会被保留。在未来的版本中,将会更改为2

注意:将该值设置为0,将导致所有的Deployment历史记录都会被清除,该Deployment就无法再回退了。

用例

金丝雀Deployment

如果您想要使用Deployment对部分用户或服务器发布release,您可以创建多个Deployment,每个Deployment对应一个release,参照 managing resources 中对金丝雀模式的描述。

编写Deployment Spec

在所有的Kubernetes配置中,Deployment也需要 apiVersionkindmetadata 这些配置项。配置文件的通用使用说明查看 部署应用,配置容器,和使用kubectl管理资源文档。

Pod Template

.spec.template.spec 中唯一要求的字段。

.spec.templatepod template.它跟 Pod 有一模一样的schema,除了它是嵌套的并且不需要 apiVersionkind 字段。

另外为了划分Pod的范围,Deployment中的pod template必须指定适当的label(不要跟其他controller重复了,参考 selector)和适当的重启策略。

.spec.template.spec.restartPolicy 可以设置为Always,如果不指定的话这就是默认配置。

Replicas

.spec.replicas 是可以选字段,指定期望的pod数量,默认是1

Selector

.spec.selector 是可选字段,用来指定 label selector ,圈定Deployment管理的pod范围。

如果被指定, .spec.selector 必须匹配 .spec.template.metadata.labels,否则它将被API拒绝。如果 .spec.selector 没有被指定, .spec.selector.matchLabels 默认是 .spec.template.metadata.labels

Podtemplate.spec.template 不同或者数量超过了 .spec.replicas 规定的数量的情况下,Deployment会杀掉labelselector不同的Pod

注意:您不应该再创建其他label跟这个selector匹配的pod,或者通过其他Deployment,或者通过其他Controller,例如ReplicaSetReplicationController。否则该Deployment会被把它们当成都是自己创建的。Kubernetes不会阻止您这么做。

如果您有多个controller使用了重复的selectorcontroller们就会互相打架并导致不正确的行为。

策略

.spec.strategy 指定新的Pod替换旧的Pod的策略。.spec.strategy.type 可以是 “Recreate” 或者是 “RollingUpdate”“RollingUpdate” 是默认值。

Recreate Deployment

.spec.strategy.type==Recreate 时,在创建出新的Pod之前会先杀掉所有已存在的Pod

Rolling Update Deployment

.spec.strategy.type==RollingUpdate 时,Deployment使用Rolling Update的方式更新Pod 。您可以指定 maxUnavailablemaxSurge 来控制rolling update进程。

Max Unavailable

.spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指定在升级过程中不可用Pod的最大数量。该值可以是一个绝对值(例如5,也可以是期望Pod数量的百分比(例如10%。通过计算百分比的绝对值向下取整。如果 .spec.strategy.rollingUpdate.maxSurge0时,这个值不可以为0。默认值是1

例如,该值设置成30%,启动rolling update后旧的ReplicatSet将会立即缩容到期望的Pod数量的70%。新的Pod ready后,随着新的ReplicaSet的扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻可以用的Pod数量至少是期望Pod数量的70%

Max Surge

.spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期望的Pod数量的最大个数。该值可以是一个绝对值(例如5)或者是期望的Pod数量的百分比(例如10%。当 MaxUnavailable0时该值不可以为0。通过百分比计算的绝对值向上取整。默认值是1

例如,该值设置成30%,启动rolling update后新的ReplicatSet将会立即扩容,新老Pod的总数不能超过期望的Pod数量的130%。旧的Pod被杀掉后,新的ReplicaSet将继续扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻所有的Pod数量和不会超过期望Pod数量的130%

Progress Deadline Seconds

.spec.progressDeadlineSeconds 是可选配置项,用来指定在系统报告Deploymentfailed progressing —— 表现为resource的状态中 type=ProgressingStatus=FalseReason=ProgressDeadlineExceeded 前可以等待的Deployment进行的秒数。Deployment controller会继续重试该Deployment。未来,在实现了自动回滚后, deployment controller在观察到这种状态时就会自动回滚。

如果设置该参数,该值必须大于 .spec.minReadySeconds

Min Ready Seconds

.spec.minReadySeconds 是一个可选配置项,用来指定没有任何容器crashPod并被认为是可用状态的最小秒数。默认是0Podready后就会被认为是可用状态。进一步了解什么什么后Pod会被认为是ready状态,参阅 Container Probes

Rollback To

.spec.rollbackTo 是一个可以选配置项,用来配置Deployment回退的配置。设置该参数将触发回退操作,每次回退完成后,该值就会被清除。

Revision

.spec.rollbackTo.revision 是一个可选配置项,用来指定回退到的revision。默认是0,意味着回退到上一个revision

Revision History Limit

Deployment revision history存储在它控制的ReplicaSets中。

.spec.revisionHistoryLimit 是一个可选配置项,用来指定可以保留的旧的ReplicaSet数量。该理想值取决于心Deployment的频率和稳定性。如果该值没有设置的话,默认所有旧的Replicaset或会被保留,将资源存储在etcd中,是用 kubectl get rs 查看输出。每个Deployment的该配置都保存在ReplicaSet中,然而,一旦您删除的旧的RepelicaSet,您的Deployment就无法再回退到那个revison了。

如果您将该值设置为0,所有具有0replicaReplicaSet都会被删除。在这种情况下,新的Deployment rollout无法撤销,因为revision history都被清理掉了。

Paused

.spec.paused 是可以可选配置项,boolean值。用来指定暂停和恢复DeploymentPaused和没有pausedDeployment之间的唯一区别就是,所有对paused deployment中的PodTemplateSpec的修改都不会触发新的rolloutDeployment被创建之后默认是非paused

下一页