部署

Deployment 管理一组 Pod,以运行应用程序工作负载,通常是不需要维护状态的工作负载。

Deployment 为 PodReplicaSet 提供声明式更新。

你在 Deployment 中描述一个**期望状态**,Deployment 控制器 以受控速率将实际状态更改为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或移除现有 Deployment 并使用新的 Deployment 采用所有其资源。

用例

以下是 Deployment 的典型用例:

创建 Deployment

下面是一个 Deployment 示例。它创建了一个 ReplicaSet 来启动三个 `nginx` Pod。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

在此示例中:

  • 创建了一个名为 `nginx-deployment` 的 Deployment,由 `.metadata.name` 字段指示。此名称将成为稍后创建的 ReplicaSet 和 Pod 的基础。有关更多详细信息,请参阅编写 Deployment Spec

  • Deployment 创建了一个 ReplicaSet,该 ReplicaSet 创建三个复制的 Pod,由 `.spec.replicas` 字段指示。

  • `.spec.selector` 字段定义了创建的 ReplicaSet 如何找到要管理的 Pod。在本例中,你选择 Pod 模板(`app: nginx`)中定义的标签。但是,只要 Pod 模板本身满足规则,就可以使用更复杂的选择规则。

  • `.spec.template` 字段包含以下子字段:

    • 使用 `.metadata.labels` 字段将 Pod 标记为 `app: nginx`。
    • Pod 模板的规约,即 `.spec` 字段,指示 Pod 运行一个容器,名为 `nginx`,它运行 1.14.2 版本的 `nginx` Docker Hub 镜像。
    • 使用 `.spec.containers[0].name` 字段创建并命名一个容器为 `nginx`。

在开始之前,请确保你的 Kubernetes 集群已启动并正在运行。按照以下步骤创建上述 Deployment:

  1. 通过运行以下命令创建 Deployment:

    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
    
  2. 运行 `kubectl get deployments` 以检查 Deployment 是否已创建。

    如果 Deployment 仍在创建中,则输出类似于以下内容:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   0/3     0            0           1s
    

    当你在集群中检查 Deployment 时,会显示以下字段:

    • `NAME` 列出了命名空间中 Deployment 的名称。
    • `READY` 显示了应用程序有多少副本可供用户使用。它遵循 ready/desired 模式。
    • `UP-TO-DATE` 显示已更新到期望状态的副本数量。
    • `AVAILABLE` 显示了应用程序有多少副本可供用户使用。
    • `AGE` 显示应用程序已运行的时间。

    请注意,根据 `.spec.replicas` 字段,期望的副本数量是 3。

  3. 要查看 Deployment 的推出状态,请运行 `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
    
  4. 几秒钟后再次运行 `kubectl get deployments`。输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           18s
    

    请注意,Deployment 已创建所有三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板)并且可用。

  5. 要查看 Deployment 创建的 ReplicaSet (`rs`),请运行 `kubectl get rs`。输出类似于:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-75675f5897   3         3         3       18s
    

    ReplicaSet 输出显示以下字段:

    • `NAME` 列出命名空间中 ReplicaSet 的名称。
    • `DESIRED` 显示应用程序期望的**副本**数量,这是你在创建 Deployment 时定义的。这是**期望状态**。
    • `CURRENT` 显示当前正在运行的副本数量。
    • `READY` 显示应用程序有多少副本可供用户使用。
    • `AGE` 显示应用程序已运行的时间。

    请注意,ReplicaSet 的名称总是格式化为 `[DEPLOYMENT-NAME]-[HASH]`。此名称将成为创建 Pod 的基础。

    `HASH` 字符串与 ReplicaSet 上的 `pod-template-hash` 标签相同。

  6. 要查看为每个 Pod 自动生成的标签,请运行 `kubectl get pods --show-labels`。输出类似于:

    NAME                                READY     STATUS    RESTARTS   AGE       LABELS
    nginx-deployment-75675f5897-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    

    创建的 ReplicaSet 确保有三个 `nginx` Pod。

Pod 模板哈希标签

`pod-template-hash` 标签由 Deployment 控制器添加到 Deployment 创建或采用的每个 ReplicaSet 中。

此标签确保 Deployment 的子 ReplicaSet 不会重叠。它是通过对 ReplicaSet 的 `PodTemplate` 进行哈希计算,并将生成的哈希用作添加到 ReplicaSet 选择器、Pod 模板标签以及 ReplicaSet 可能具有的任何现有 Pod 中的标签值来生成的。

更新 Deployment

按照以下步骤更新你的 Deployment:

  1. 让我们将 nginx Pod 更新为使用 `nginx:1.16.1` 镜像而不是 `nginx:1.14.2` 镜像。

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

    或者使用以下命令:

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

    其中 `deployment/nginx-deployment` 表示 Deployment,`nginx` 表示将进行更新的容器,`nginx:1.16.1` 表示新镜像及其标签。

    输出类似于:

    deployment.apps/nginx-deployment image updated
    

    或者,你可以 `edit` Deployment 并将 `.spec.template.spec.containers[0].image` 从 `nginx:1.14.2` 更改为 `nginx:1.16.1`。

    kubectl edit deployment/nginx-deployment
    

    输出类似于:

    deployment.apps/nginx-deployment edited
    
  2. 要查看推出状态,请运行:

    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
    

获取关于更新后的 Deployment 的更多详细信息。

  • 推出成功后,你可以通过运行 `kubectl get deployments` 查看 Deployment。输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           36s
    
  • 运行 `kubectl get rs` 查看 Deployment 如何通过创建新的 ReplicaSet 并将其扩容到 3 个副本,以及将旧的 ReplicaSet 缩减到 0 个副本,来更新 Pod。

    kubectl get rs
    

    输出类似于:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       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 的 Pod 模板。

    Deployment 确保在更新期间只有一定数量的 Pod 下线。默认情况下,它确保至少 75% 的所需 Pod 处于活动状态(最多 25% 不可用)。

    Deployment 还确保只创建一定数量的 Pod,超出所需 Pod 的数量。默认情况下,它确保最多 125% 的所需 Pod 处于活动状态(最多 25% 突增)。

    例如,如果你仔细查看上面的 Deployment,你会发现它首先创建一个新的 Pod,然后删除一个旧的 Pod,再创建另一个新的 Pod。它不会杀死旧的 Pod,直到足够数量的新 Pod 出现,也不会创建新的 Pod,直到足够数量的旧 Pod 被杀死。它确保至少 3 个 Pod 可用,并且总共有最多 4 个 Pod 可用。在具有 4 个副本的 Deployment 中,Pod 的数量将在 3 到 5 之间。

  • 获取你的 Deployment 的详细信息。

    kubectl describe deployments
    

    输出类似于:

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 30 Nov 2017 10:56:25 +0000
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=2
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
       Containers:
        nginx:
          Image:        nginx:1.16.1
          Port:         80/TCP
          Environment:  <none>
          Mounts:       <none>
        Volumes:        <none>
      Conditions:
        Type           Status  Reason
        ----           ------  ------
        Available      True    MinimumReplicasAvailable
        Progressing    True    NewReplicaSetAvailable
      OldReplicaSets:  <none>
      NewReplicaSet:   nginx-deployment-1564180365 (3/3 replicas created)
      Events:
        Type    Reason             Age   From                   Message
        ----    ------             ----  ----                   -------
        Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3
        Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
        Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0
    

    在这里,你看到当你第一次创建 Deployment 时,它创建了一个 ReplicaSet (nginx-deployment-2035384211) 并直接将其扩容到 3 个副本。当你更新 Deployment 时,它创建了一个新的 ReplicaSet (nginx-deployment-1564180365) 并将其扩容到 1 个,然后等待它启动。然后它将旧的 ReplicaSet 缩减到 2,并将新的 ReplicaSet 扩容到 2,以便始终至少有 3 个 Pod 可用,并且最多创建 4 个 Pod。然后它继续以相同的滚动更新策略对新旧 ReplicaSet 进行扩缩。最后,你将在新的 ReplicaSet 中拥有 3 个可用副本,并且旧的 ReplicaSet 将缩减到 0。

滚动(即飞行中的多次更新)

每当 Deployment 控制器观察到新的 Deployment 时,就会创建一个 ReplicaSet 来启动所需的 Pod。如果 Deployment 被更新,则控制 Pod 的现有 ReplicaSet(其标签与 `.spec.selector` 匹配但其模板与 `.spec.template` 不匹配)将缩减。最终,新的 ReplicaSet 将扩容到 `.spec.replicas`,所有旧的 ReplicaSet 将缩减到 0。

如果你在现有推出正在进行时更新 Deployment,Deployment 会根据更新创建一个新的 ReplicaSet 并开始扩容,然后将之前正在扩容的 ReplicaSet 滚动更新——它会将其添加到旧 ReplicaSet 列表中并开始缩减。

例如,假设你创建了一个 Deployment 以创建 5 个 `nginx:1.14.2` 副本,但在只创建了 3 个 `nginx:1.14.2` 副本时更新了 Deployment 以创建 5 个 `nginx:1.16.1` 副本。在这种情况下,Deployment 立即开始杀死它已创建的 3 个 `nginx:1.14.2` Pod,并开始创建 `nginx:1.16.1` Pod。它不会等待 5 个 `nginx:1.14.2` 副本创建完毕再改变方向。

标签选择器更新

通常不鼓励进行标签选择器更新,建议你预先规划好选择器。在任何情况下,如果你需要执行标签选择器更新,请务必谨慎并确保你已完全理解所有影响。

  • 选择器添加需要 Deployment 规约中的 Pod 模板标签也更新新标签,否则将返回验证错误。此更改是非重叠的,这意味着新选择器不选择使用旧选择器创建的 ReplicaSet 和 Pod,导致所有旧 ReplicaSet 孤立并创建新的 ReplicaSet。
  • 选择器更新更改选择器键中的现有值——导致与添加相同的行为。
  • 选择器删除会从 Deployment 选择器中移除现有键——不需要对 Pod 模板标签进行任何更改。现有的 ReplicaSet 不会被孤立,也不会创建新的 ReplicaSet,但请注意,已移除的标签仍然存在于任何现有 Pod 和 ReplicaSet 中。

回滚 Deployment

有时,你可能希望回滚 Deployment;例如,当 Deployment 不稳定(例如,崩溃循环)时。默认情况下,Deployment 的所有推出历史记录都保留在系统中,因此你可以随时回滚(你可以通过修改修订历史限制来更改此设置)。

  • 假设你在更新 Deployment 时打错了字,将镜像名称写成 `nginx:1.161` 而不是 `nginx:1.16.1`。

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

    输出类似于:

    deployment.apps/nginx-deployment image updated
    
  • 推出卡住了。你可以通过检查推出状态来验证这一点:

    kubectl rollout status deployment/nginx-deployment
    

    输出类似于:

    Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
    
  • 按 Ctrl-C 停止上述推出状态监视。有关推出卡顿的更多信息,请在此处阅读

  • 你看到旧副本(`nginx-deployment-1564180365` 和 `nginx-deployment-2035384211` 的副本计数之和)的数量是 3,而新副本(来自 `nginx-deployment-3066724191`)的数量是 1。

    kubectl get rs
    

    输出类似于:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       25s
    nginx-deployment-2035384211   0         0         0       36s
    nginx-deployment-3066724191   1         1         0       6s
    
  • 查看创建的 Pod,你看到由新的 ReplicaSet 创建的 1 个 Pod 停留在镜像拉取循环中。

    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-1564180365-hysrc   1/1       Running            0          25s
    nginx-deployment-3066724191-08mng   0/1       ImagePullBackOff   0          6s
    
  • 获取 Deployment 的描述。

    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 desired | 1 updated | 4 total | 3 available | 1 unavailable
    StrategyType:       RollingUpdate
    MinReadySeconds:    0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.161
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    ReplicaSetUpdated
    OldReplicaSets:     nginx-deployment-1564180365 (3/3 replicas created)
    NewReplicaSet:      nginx-deployment-3066724191 (1/1 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 1
      21s       21s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 1
    

    要解决此问题,你需要回滚到稳定的 Deployment 的先前修订版本。

检查 Deployment 的推出历史

按照以下步骤检查推出历史:

  1. 首先,检查此 Deployment 的修订版本:

    kubectl rollout history deployment/nginx-deployment
    

    输出类似于:

    deployments "nginx-deployment"
    REVISION    CHANGE-CAUSE
    1           kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
    2           kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    3           kubectl set image deployment/nginx-deployment nginx=nginx:1.161
    

    `CHANGE-CAUSE` 在创建时从 Deployment 注解 `kubernetes.io/change-cause` 复制到其修订版本。你可以通过以下方式指定 `CHANGE-CAUSE` 消息:

    • 使用 `kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"` 为 Deployment 添加注解。
    • 手动编辑资源的清单。
  2. 要查看每个修订版本的详细信息,请运行:

    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.16.1
      Containers:
       nginx:
        Image:      nginx:1.16.1
        Port:       80/TCP
         QoS Tier:
            cpu:      BestEffort
            memory:   BestEffort
        Environment Variables:      <none>
      No volumes.
    

回滚到先前修订版本

按照以下步骤将 Deployment 从当前版本回滚到上一个版本,即版本 2。

  1. 现在你已决定撤销当前的推出并回滚到上一个修订版本。

    kubectl rollout undo deployment/nginx-deployment
    

    输出类似于:

    deployment.apps/nginx-deployment rolled back
    

    或者,你可以通过使用 `--to-revision` 指定特定修订版本来回滚。

    kubectl rollout undo deployment/nginx-deployment --to-revision=2
    

    输出类似于:

    deployment.apps/nginx-deployment rolled back
    

    有关推出相关命令的更多详细信息,请参阅 `kubectl rollout`

    Deployment 现在已回滚到以前的稳定修订版本。如你所见,Deployment 控制器生成了一个 `DeploymentRollback` 事件,用于回滚到修订版本 2。

  2. 检查回滚是否成功以及 Deployment 是否按预期运行,运行:

    kubectl get deployment nginx-deployment
    

    输出类似于:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           30m
    
  3. 获取 Deployment 的描述。

    kubectl describe deployment nginx-deployment
    

    输出类似于:

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Sun, 02 Sep 2018 18:17:55 -0500
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=4
                            kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.16.1
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   nginx-deployment-c4747d96c (3/3 replicas created)
    Events:
      Type    Reason              Age   From                   Message
      ----    ------              ----  ----                   -------
      Normal  ScalingReplicaSet   12m   deployment-controller  Scaled up replica set nginx-deployment-75675f5897 to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 0
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-595696685f to 1
      Normal  DeploymentRollback  15s   deployment-controller  Rolled back deployment "nginx-deployment" to revision 2
      Normal  ScalingReplicaSet   15s   deployment-controller  Scaled down replica set nginx-deployment-595696685f to 0
    

扩展 Deployment

你可以使用以下命令扩展 Deployment:

kubectl scale deployment/nginx-deployment --replicas=10

输出类似于:

deployment.apps/nginx-deployment scaled

假设你的集群中启用了水平 Pod 自动扩缩,你可以为你的 Deployment 设置一个自动扩缩器,并根据现有 Pod 的 CPU 利用率选择你想要运行的最小和最大 Pod 数量。

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

输出类似于:

deployment.apps/nginx-deployment scaled

按比例扩缩

滚动更新型 Deployment 支持同时运行应用程序的多个版本。当你或自动扩缩器扩缩一个处于推出中(正在进行或已暂停)的滚动更新型 Deployment 时,Deployment 控制器会在现有的活动 ReplicaSet(带有 Pod 的 ReplicaSet)中平衡额外的副本,以减轻风险。这称为**按比例扩缩**。

例如,你正在运行一个包含 10 个副本的 Deployment,maxSurge=3,maxUnavailable=2。

  • 确保你的 Deployment 中的 10 个副本正在运行。

    kubectl get deploy
    

    输出类似于:

    NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment     10        10        10           10          50s
    
  • 你更新到新镜像,但该镜像无法从集群内部解析。

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

    输出类似于:

    deployment.apps/nginx-deployment image updated
    
  • 镜像更新启动了一个新的推出,ReplicaSet nginx-deployment-1989198191,但由于你上面提到的 `maxUnavailable` 要求,它被阻塞了。查看推出状态:

    kubectl get rs
    

    输出类似于:

    NAME                          DESIRED   CURRENT   READY     AGE
    nginx-deployment-1989198191   5         5         0         9s
    nginx-deployment-618515232    8         8         8         1m
    
  • 然后,一个新的 Deployment 扩缩请求到来。自动扩缩器将 Deployment 副本增加到 15。Deployment 控制器需要决定将这 5 个新副本添加到哪里。如果你不使用按比例扩缩,所有 5 个副本都将添加到新的 ReplicaSet 中。通过按比例扩缩,你将额外的副本分散到所有 ReplicaSet 中。较大比例分配给副本数量最多的 ReplicaSet,较小比例分配给副本数量较少的 ReplicaSet。任何剩余的副本将添加到副本数量最多的 ReplicaSet 中。副本数量为零的 ReplicaSet 不会被扩容。

在上面的示例中,3 个副本被添加到旧的 ReplicaSet,2 个副本被添加到新的 ReplicaSet。推出过程最终应该将所有副本移动到新的 ReplicaSet,假设新的副本变得健康。要确认这一点,请运行:

kubectl get deploy

输出类似于:

NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment     15        18        7            8           7m

推出状态确认了副本是如何添加到每个 ReplicaSet 的。

kubectl get rs

输出类似于:

NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-1989198191   7         7         0         7m
nginx-deployment-618515232    11        11        11        7m

暂停和恢复 Deployment 的推出

当你更新 Deployment 或计划更新时,可以在触发一次或多次更新之前暂停该 Deployment 的推出。当你准备好应用这些更改时,你将恢复 Deployment 的推出。这种方法允许你在暂停和恢复之间应用多个修复,而无需触发不必要的推出。

  • 例如,对于已创建的 Deployment:

    获取 Deployment 详细信息。

    kubectl get deploy
    

    输出类似于:

    NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx     3         3         3            3           1m
    

    获取推出状态。

    kubectl get rs
    

    输出类似于:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         1m
    
  • 通过运行以下命令暂停:

    kubectl rollout pause deployment/nginx-deployment
    

    输出类似于:

    deployment.apps/nginx-deployment paused
    
  • 然后更新 Deployment 的镜像:

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

    输出类似于:

    deployment.apps/nginx-deployment image updated
    
  • 请注意,没有新的推出启动。

    kubectl rollout history deployment/nginx-deployment
    

    输出类似于:

    deployments "nginx"
    REVISION  CHANGE-CAUSE
    1   <none>
    
  • 获取推出状态以验证现有 ReplicaSet 未更改:

    kubectl get rs
    

    输出类似于:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         2m
    
  • 你可以进行任意多次更新,例如,更新将使用的资源:

    kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
    

    输出类似于:

    deployment.apps/nginx-deployment resource requirements updated
    

    Deployment 在暂停推出之前的初始状态将继续其功能,但只要 Deployment 推出处于暂停状态,对 Deployment 的新更新将不会产生任何影响。

  • 最终,恢复 Deployment 推出并观察到新的 ReplicaSet 出现,其中包含所有新更新。

    kubectl rollout resume deployment/nginx-deployment
    

    输出类似于:

    deployment.apps/nginx-deployment resumed
    
  • 监视推出状态,直到完成。

    kubectl get rs --watch
    

    输出类似于:

    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
    
  • 获取最新推出的状态。

    kubectl get rs
    

    输出类似于:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         28s
    

Deployment 状态

Deployment 在其生命周期中会进入各种状态。它可能在推出新的 ReplicaSet 时处于进行中,可能处于完成状态,也可能未能取得进展

正在进行的 Deployment

当执行以下任务之一时,Kubernetes 将 Deployment 标记为**进行中**:

  • Deployment 创建了一个新的 ReplicaSet。
  • Deployment 正在扩容其最新的 ReplicaSet。
  • Deployment 正在缩减其旧的 ReplicaSet。
  • 新的 Pod 变得就绪或可用(至少在 MinReadySeconds 期间就绪)。

当推出变为“进行中”时,Deployment 控制器会在 Deployment 的 `.status.conditions` 中添加一个具有以下属性的条件:

  • type: Progressing
  • status: "True"
  • `reason: NewReplicaSetCreated` | `reason: FoundNewReplicaSet` | `reason: ReplicaSetUpdated`

你可以使用 `kubectl rollout status` 监视 Deployment 的进度。

完成的 Deployment

当 Deployment 具有以下特征时,Kubernetes 会将其标记为**完成**:

  • 与 Deployment 相关联的所有副本都已更新到你指定的最新版本,这意味着你请求的任何更新都已完成。
  • 与 Deployment 相关联的所有副本都可用。
  • 没有 Deployment 的旧副本正在运行。

当推出变为“完成”时,Deployment 控制器会在 Deployment 的 `.status.conditions` 中设置一个具有以下属性的条件:

  • type: Progressing
  • status: "True"
  • reason: NewReplicaSetAvailable

此 `Progressing` 条件将保持 `“True”` 状态值,直到启动新的推出。即使副本的可用性发生变化(这会影响 `Available` 条件),该条件也保持不变。

你可以使用 `kubectl rollout status` 检查 Deployment 是否已完成。如果推出成功完成,`kubectl rollout status` 将返回零退出代码。

kubectl rollout status deployment/nginx-deployment

输出类似于:

Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out

并且来自 `kubectl rollout` 的退出状态为 0(成功)

echo $?
0

失败的 Deployment

你的 Deployment 可能会在尝试部署其最新的 ReplicaSet 时卡住,而无法完成。这可能是由于以下一些因素造成的:

  • 配额不足
  • 就绪探针失败
  • 镜像拉取错误
  • 权限不足
  • 限制范围
  • 应用程序运行时配置错误

检测此条件的一种方法是在 Deployment 规约中指定一个截止日期参数:(`.spec.progressDeadlineSeconds`)。`.spec.progressDeadlineSeconds` 表示 Deployment 控制器在指示(在 Deployment 状态中)Deployment 进度已停滞之前等待的秒数。

以下 `kubectl` 命令将 spec 中的 `progressDeadlineSeconds` 设置为 10 分钟,以便控制器在 10 分钟后报告 Deployment 推出没有进展:

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

输出类似于:

deployment.apps/nginx-deployment patched

一旦超过截止日期,Deployment 控制器将在 Deployment 的 `.status.conditions` 中添加一个具有以下属性的 DeploymentCondition:

  • type: Progressing
  • status: "False"
  • reason: ProgressDeadlineExceeded

此条件也可能提前失败,然后由于 `ReplicaSetCreateError` 等原因而设置为 `“False”`。此外,一旦 Deployment 推出完成,截止日期将不再考虑。

有关状态条件的更多信息,请参阅 Kubernetes API 约定

你的 Deployment 可能会遇到瞬时错误,这可能是由于你设置的超时时间过短,或者由于任何其他可以视为瞬时错误的错误。例如,假设你的配额不足。如果你描述 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 yaml`,Deployment 状态类似于:

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 进度截止日期,Kubernetes 会更新 `Progressing` 条件的状态和原因:

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

你可以通过缩减 Deployment、缩减你可能正在运行的其他控制器或增加命名空间中的配额来解决配额不足问题。如果你满足配额条件,并且 Deployment 控制器随后完成 Deployment 推出,你将看到 Deployment 的状态更新为成功的条件(`status: "True"` 和 `reason: NewReplicaSetAvailable`)。

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

`type: Available` 且 `status: "True"` 表示你的 Deployment 具有最小可用性。最小可用性由 Deployment 策略中指定的参数决定。`type: Progressing` 且 `status: "True"` 表示你的 Deployment 正在推出过程中并正在取得进展,或者它已成功完成其进展并且所需的新副本已可用(有关详细信息,请参阅条件的原因——在我们的示例中,`reason: NewReplicaSetAvailable` 表示 Deployment 已完成)。

你可以使用 `kubectl rollout status` 检查 Deployment 是否未能取得进展。如果 Deployment 超出了进度截止日期,`kubectl rollout status` 将返回非零退出代码。

kubectl rollout status deployment/nginx-deployment

输出类似于:

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline

并且来自 `kubectl rollout` 的退出状态为 1(表示错误)

echo $?
1

对失败的 Deployment 进行操作

适用于完整 Deployment 的所有操作也适用于失败的 Deployment。你可以对其进行扩容/缩容,回滚到以前的修订版本,甚至在需要对 Deployment Pod 模板进行多次调整时暂停它。

清理策略

你可以在 Deployment 中设置 `.spec.revisionHistoryLimit` 字段,以指定要保留多少个此 Deployment 的旧 ReplicaSet。其余的将在后台进行垃圾回收。默认值为 10。

清理仅在 Deployment 达到完成状态后才开始。如果你将 `.spec.revisionHistoryLimit` 设置为 0,任何推出仍然会在 Kubernetes 删除旧的 ReplicaSet 之前触发新的 ReplicaSet 的创建。

即使修订历史限制不为零,你也可以拥有比你配置的限制更多的 ReplicaSet。例如,如果 Pod 崩溃循环,并且随着时间的推移触发了多个滚动更新事件,你最终可能会拥有比 `.spec.revisionHistoryLimit` 更多的 ReplicaSet,因为 Deployment 从未达到完整状态。

金丝雀部署

如果你希望使用 Deployment 向一部分用户或服务器推出版本,可以创建多个 Deployment,每个版本一个,遵循管理资源中描述的金丝雀模式。

编写 Deployment 规约

与其他所有 Kubernetes 配置一样,Deployment 需要 `.apiVersion`、`.kind` 和 `.metadata` 字段。有关配置文件的通用信息,请参阅部署应用程序、配置容器和使用 kubectl 管理资源文档。

当控制平面为 Deployment 创建新的 Pod 时,Deployment 的 `.metadata.name` 是命名这些 Pod 的基础。Deployment 的名称必须是有效的DNS 子域名值,但这可能会导致 Pod 主机名出现意外结果。为了获得最佳兼容性,名称应遵循更严格的DNS 标签规则。

Deployment 还需要一个 `.spec` 节

Pod 模板

`.spec.template` 和 `.spec.selector` 是 `.spec` 唯一必填的字段。

`.spec.template` 是一个Pod 模板。它与Pod 的模式完全相同,只是它是嵌套的,没有 `apiVersion` 或 `kind`。

除了 Pod 的必需字段外,Deployment 中的 Pod 模板必须指定适当的标签和适当的重启策略。对于标签,请确保不要与其他控制器重叠。请参阅选择器

只允许 `.spec.template.spec.restartPolicy` 等于 `Always`,这是未指定时的默认值。

副本

`.spec.replicas` 是一个可选字段,用于指定所需 Pod 的数量。它默认为 1。

如果你手动扩缩 Deployment,例如通过 `kubectl scale deployment deployment --replicas=X`,然后你根据清单更新该 Deployment(例如:通过运行 `kubectl apply -f deployment.yaml`),那么应用该清单会覆盖你之前手动进行的扩缩。

如果 HorizontalPodAutoscaler(或任何类似的水平扩缩 API)正在管理 Deployment 的扩缩,请不要设置 `.spec.replicas`。

相反,允许 Kubernetes 控制平面 自动管理 `.spec.replicas` 字段。

选择器

`.spec.selector` 是一个必需字段,指定了此 Deployment 目标 Pod 的标签选择器

`.spec.selector` 必须与 `.spec.template.metadata.labels` 匹配,否则将被 API 拒绝。

在 API 版本 `apps/v1` 中,如果未设置 `.spec.selector` 和 `.metadata.labels`,它们不会默认为 `.spec.template.metadata.labels`。因此它们必须明确设置。另请注意,在 `apps/v1` 中创建 Deployment 后,`.spec.selector` 是不可变的。

如果 Pod 的标签与选择器匹配但其模板与 `.spec.template` 不同,或者此类 Pod 的总数超过 `.spec.replicas`,Deployment 可能会终止这些 Pod。如果 Pod 数量少于所需数量,它将使用 `.spec.template` 启动新的 Pod。

如果多个控制器具有重叠的选择器,它们将相互冲突,并且无法正常工作。

策略

`.spec.strategy` 指定用于替换旧 Pod 的新 Pod 的策略。`.spec.strategy.type` 可以是 "Recreate" 或 "RollingUpdate"。 "RollingUpdate" 是默认值。

重新创建 Deployment

当 `.`spec.strategy.type==Recreate` 时,所有现有 Pod 在创建新 Pod 之前都会被杀死。

滚动更新 Deployment

当 `.`spec.strategy.type==RollingUpdate` 时,Deployment 会以滚动更新的方式更新 Pod(逐步缩减旧 ReplicaSet 并扩容新的 ReplicaSet)。你可以指定 `maxUnavailable` 和 `maxSurge` 来控制滚动更新过程。

最大不可用数

`.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.strategy.rollingUpdate.maxSurge` 是一个可选字段,它指定可以创建超出所需 Pod 数量的最大 Pod 数量。该值可以是绝对数字(例如 5)或所需 Pod 的百分比(例如 10%)。如果 `maxUnavailable` 为 0,则该值不能为 0。绝对数字通过向上取整从百分比计算。默认值为 25%。

例如,当此值设置为 30% 时,新的 ReplicaSet 可以在滚动更新开始时立即扩容,从而使新旧 Pod 的总数不超过所需 Pod 的 130%。一旦旧 Pod 被杀死,新的 ReplicaSet 可以进一步扩容,确保在更新期间任何时候运行的 Pod 总数最多为所需 Pod 的 130%。

以下是一些使用 `maxUnavailable` 和 `maxSurge` 的滚动更新 Deployment 示例:

apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxUnavailable: 1

apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxSurge: 1

apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   app: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.14.2
       ports:
       - containerPort: 80
 strategy:
   type: RollingUpdate
   rollingUpdate:
     maxSurge: 1
     maxUnavailable: 1

进度截止秒数

`.spec.progressDeadlineSeconds` 是一个可选字段,它指定 Deployment 在系统报告 Deployment 未能取得进展之前你希望等待的秒数——在资源状态中显示为 `type: Progressing`、`status: "False"` 和 `reason: ProgressDeadlineExceeded` 的条件。Deployment 控制器将继续重试 Deployment。默认值为 600。将来,一旦实现了自动回滚,Deployment 控制器将在观察到此类条件后立即回滚 Deployment。

如果指定,此字段必须大于 `.spec.minReadySeconds`。

最小就绪秒数

`.spec.minReadySeconds` 是一个可选字段,它指定新创建的 Pod 在其任何容器未崩溃的情况下应保持就绪的最短秒数,以便将其视为可用。默认值为 0(Pod 一旦就绪即被视为可用)。要了解有关 Pod 何时被视为就绪的更多信息,请参阅容器探针

终止 Pods

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

你可以通过在API 服务器kube-controller-manager 上设置 `DeploymentReplicaSetTerminatingReplicas` 特性门控来启用此特性。

由于删除或缩减而进入终止状态的 Pod 可能需要很长时间才能终止,并且在此期间可能会消耗额外的资源。因此,所有 Pod 的总数可能会暂时超过 `.spec.replicas`。可以使用 Deployment 的 `.status.terminatingReplicas` 字段跟踪正在终止的 Pod。

修订历史限制

Deployment 的修订历史记录存储在其控制的 ReplicaSet 中。

`.spec.revisionHistoryLimit` 是一个可选字段,它指定要保留的旧 ReplicaSet 的数量,以允许回滚。这些旧 ReplicaSet 会消耗 `etcd` 中的资源,并使 `kubectl get rs` 的输出变得混乱。每个 Deployment 修订的配置都存储在其 ReplicaSet 中;因此,一旦旧 ReplicaSet 被删除,你将失去回滚到该 Deployment 修订的能力。默认情况下,将保留 10 个旧 ReplicaSet,但其理想值取决于新 Deployment 的频率和稳定性。

更具体地说,将此字段设置为零意味着所有具有 0 个副本的旧 ReplicaSet 都将被清理。在这种情况下,新的 Deployment 推出无法撤消,因为其修订历史记录已被清理。

暂停

`.spec.paused` 是一个可选的布尔字段,用于暂停和恢复 Deployment。暂停的 Deployment 与未暂停的 Deployment 之间的唯一区别是,只要它处于暂停状态,对暂停的 Deployment 的 PodTemplateSpec 的任何更改都不会触发新的推出。Deployment 在创建时默认不暂停。

下一步

最后修改于 2025 年 8 月 29 日下午 5:11 PST:澄清 Deployment 更新行为 (808824fa27)