--- reviewers: - janetkuo title: Deployments feature: title: 自动化展开和回滚 description: > Kubernetes 会逐步推出针对应用或其配置的更改,确保在监视应用程序运行状况的同时,不会终止所有实例。如果出现问题,Kubernetes 会为您回滚更改。充分利用不断成长的部署解决方案生态系统。 content_type: concept weight: 30 --- 一个 _Deployment_ 控制器为 [Pods](/docs/concepts/workloads/pods/pod/)和 [ReplicaSets](/docs/concepts/workloads/controllers/replicaset/)提供描述性的更新方式。 描述 Deployment 中的 _desired state_,并且 Deployment 控制器以受控速率更改实际状态,以达到期望状态。可以定义 Deployments 以创建新的 ReplicaSets ,或删除现有 Deployments ,并通过新的 Deployments 使用其所有资源。 {{< note >}} 不要管理 Deployment 拥有的 ReplicaSets 。如果存在下面未介绍的用例,请考虑在主 Kubernetes 仓库中提出 issue。 {{< /note >}} You describe a _desired state_ in a Deployment, and the Deployment controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments. --> 描述 Deployment 中的 _desired state_,并且 Deployment 控制器以受控速率更改实际状态,以达到期望状态。可以定义 Deployments 以创建新的 ReplicaSets ,或删除现有 Deployments ,并通过新的 Deployments 使用其所有资源。 ## 用例 以下是典型的 Deployments 用例: * [创建 Deployment 以展开 ReplicaSet ](#creating-a-deployment)。 ReplicaSet 在后台创建 Pods。检查 ReplicaSet 展开的状态,查看其是否成功。 * [声明 Pod 的新状态](#updating-a-deployment) 通过更新 Deployment 的 PodTemplateSpec。将创建新的 ReplicaSet ,并且 Deployment 管理器以受控速率将 Pod 从旧 ReplicaSet 移动到新 ReplicaSet 。每个新的 ReplicaSet 都会更新 Deployment 的修改历史。 * [回滚到较早的 Deployment 版本](#rolling-back-a-deployment),如果 Deployment 的当前状态不稳定。每次回滚都会更新 Deployment 的修改。 * [扩展 Deployment 以承担更多负载](#scaling-a-deployment). * [暂停 Deployment ](#pausing-and-resuming-a-deployment) 对其 PodTemplateSpec 进行修改,然后恢复它以启动新的展开。 * [使用 Deployment 状态](#deployment-status) 作为卡住展开的指示器。 * [清理较旧的 ReplicaSets ](#clean-up-policy) ,那些不再需要的。 ## 创建 Deployment 下面是 Deployment 示例。创建一个 ReplicaSet 展开三个 `nginx` Pods: {{< codenew file="controllers/nginx-deployment.yaml" >}} 在该例中: * 将创建名为 `nginx-deployment` 的 Deployment ,由 `.metadata.name` 字段指示。 * Deployment 创建三个复制的 Pods,由 `replicas` 字段指示。 * `selector` 字段定义 Deployment 如何查找要管理的 Pods。 在这种情况下,只需选择在 Pod 模板(`app: nginx`)中定义的标签。但是,更复杂的选择规则是可能的,只要 Pod 模板本身满足规则。 {{< note >}} `matchLabels` 字段是 {key,value} 的映射。单个 {key,value}在 `matchLabels` 映射中的值等效于 `matchExpressions` 的元素,其键字段是“key”,运算符为“In”,值数组仅包含“value”。所有要求,从 `matchLabels` 和 `matchExpressions`,必须满足才能匹配。 {{< /note >}} * `template` 字段包含以下子字段: * Pod 标记为`app: nginx`,使用`labels`字段。 * Pod 模板规范或 `.template.spec` 字段指示 Pods 运行一个容器, `nginx`,运行 `nginx` [Docker Hub](https://hub.docker.com/)版本1.7.9的镜像 。 * 创建一个容器并使用`name`字段将其命名为 `nginx`。 按照以下步骤创建上述 Deployment : 开始之前,请确保的 Kubernetes 集群已启动并运行。 1. 通过运行以下命令创建 Deployment : {{< note >}} 可以指定 `--record` 标志来写入在资源注释`kubernetes.io/change-cause`中执行的命令。它对以后的检查是有用的。 例如,查看在每个 Deployment 修改中执行的命令。 {{< /note >}} ```shell kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml ``` 2. 运行 `kubectl get deployments` 以检查 Deployment 是否已创建。如果仍在创建 Deployment ,则输出以下内容: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 0 0 0 1s ``` 检查集群中的 Deployments 时,将显示以下字段: * `NAME` 列出了集群中 Deployments 的名称。 * `DESIRED` 显示应用程序的所需 _副本_ 数,在创建 Deployment 时定义这些副本。这是 _期望状态_。 * `CURRENT`显示当前正在运行的副本数。 * `UP-TO-DATE`显示已更新以实现期望状态的副本数。 * `AVAILABLE`显示应用程序可供用户使用的副本数。 * `AGE` 显示应用程序运行的时间量。 请注意,根据`.spec.replicas`副本字段,所需副本的数量为 3。 3. 要查看 Deployment 展开状态,运行 `kubectl rollout status deployment.v1.apps/nginx-deployment`。输出: ```shell Waiting for rollout to finish: 2 out of 3 new replicas have been updated... deployment.apps/nginx-deployment successfully rolled out ``` 4. 几秒钟后再次运行 `kubectl get deployments`。输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 18s ``` 请注意, Deployment 已创建所有三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板)并且可用。 5. 要查看 Deployment 创建的 ReplicaSet (`rs`),运行 `kubectl get rs`。输出: ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-75675f5897 3 3 3 18s ``` 请注意, ReplicaSet 的名称始终被格式化为`[DEPLOYMENT-NAME]-[RANDOM-STRING]`。随机字符串是随机生成并使用 pod-template-hash 作为种子。 6. 要查看每个 Pod 自动生成的标签,运行 `kubectl get pods --show-labels`。返回以下输出: ```shell NAME READY STATUS RESTARTS AGE LABELS nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 ``` 创建的复制集可确保有三个 `nginx` Pods。 {{< note >}} 必须在 Deployment 中指定适当的选择器和 Pod 模板标签(在本例中为`app: nginx`)。不要与其他控制器(包括其他 Deployments 和状态设置)重叠标签或选择器。Kubernetes 不会阻止重叠,如果多个控制器具有重叠的选择器,这些控制器可能会冲突并运行意外。 {{< /note >}} ### Pod-template-hash 标签 {{< note >}} 不要更改此标签。 {{< /note >}} Deployment 控制器将 `pod-template-hash` 标签添加到 Deployment 创建或使用的每个 ReplicaSet 。 此标签可确保 Deployment 的子 ReplicaSets 不重叠。它通过对 ReplicaSet 的 `PodTemplate` 进行哈希处理,并使用生成的哈希值添加到 ReplicaSet 选择器、Pod 模板标签,并在 ReplicaSet 可能具有的任何现有 Pod 中。 ## 更新 Deployment {{< note >}} 仅当 Deployment Pod 模板(即 `.spec.template`)时,才会触发 Deployment 展开,例如,如果模板的标签或容器镜像已更新,其他更新(如扩展 Deployment )不会触发展开。 {{< /note >}} 按照以下步骤更新 Deployment : 1. 让我们更新 nginx Pods,以使用 `nginx:1.9.1` 镜像 ,而不是 `nginx:1.7.9` 镜像 。 ```shell kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 ``` 输出: ```shell deployment.apps/nginx-deployment image updated ``` 或者,可以 `edit` Deployment 并将 `.spec.template.spec.containers[0].image` 从 `nginx:1.7.9` 更改至 `nginx:1.9.1`。 ```shell kubectl edit deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployment.apps/nginx-deployment edited ``` 2. 要查看展开状态,运行: ```shell kubectl rollout status deployment.v1.apps/nginx-deployment ``` 输出: ```shell Waiting for rollout to finish: 2 out of 3 new replicas have been updated... ``` 或者 ```shell deployment.apps/nginx-deployment successfully rolled out ``` 在更新后的 Deployment 上获取更多信息 * 在展开成功后,可以通过运行 `kubectl get deployments`来查看 Deployment 。 输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 36s ``` * 运行 `kubectl get rs` 以查看 Deployment 通过创建新的 ReplicaSet 并缩放它更新了 Pods 最多 3 个副本,以及将旧 ReplicaSet 缩放到 0 个副本。 ```shell kubectl get rs ``` 输出: ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 6s nginx-deployment-2035384211 0 0 0 36s ``` * 运行 `get pods` 现在应仅显示新的 Pods: ```shell kubectl get pods ``` 输出: ```shell 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 ``` 下次要更新这些 Pods 时,只需再次更新 Deployment Pod 模板。 Deployment 可确保在更新时仅关闭一定数量的 Pods。默认情况下,它确保至少 75%所需 Pods 运行(25%最大不可用)。 Deployment 还确保仅创建一定数量的 Pods 高于期望的 Pods 数。默认情况下,它可确保最多增加 25% 期望 Pods 数(25%最大增量)。 例如,如果仔细查看上述 Deployment ,将看到它首先创建了一个新的 Pod,然后删除了一些旧的 Pods,并创建了新的 Pods。它不会杀死老 Pods,直到有足够的数量新的 Pods 已经出现,并没有创造新的 Pods,直到足够数量的旧 Pods 被杀死。它确保至少 2 个 Pods 可用,并且总共最多 4 个 Pods 可用。 * 获取 Deployment 的更多信息 ```shell kubectl describe deployments ``` 输出: ```shell 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.9.1 Port: 80/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: 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,以便至少有 2 个 Pod 可用,并且最多创建 4 个 Pod。然后,它继续向上和向下扩展新的和旧的 ReplicaSet ,具有相同的滚动更新策略。最后,将有 3 个可用的副本在新的 ReplicaSet 中,旧 ReplicaSet 将缩小到 0。 ### 翻转(多 Deployment 动态更新) 每次 Deployment 控制器观察新 Deployment 时,都会创建一个 ReplicaSet 以启动所需的 Pods。如果更新了 Deployment ,则控制其标签的 Pods 的现有 ReplicaSet 匹配 `.spec.selector`,但其模板不匹配 `.spec.template` 被缩小。最终,新的 ReplicaSet 缩放为 `.spec.replicas`,所有旧 ReplicaSets 缩放为 0。 当 Deployment 正在展开时进行更新, Deployment 会为每个更新创建一个新的 ReplicaSet 并开始向上扩展,之前的 ReplicaSet 会被添加到旧 ReplicaSets 队列并开始向下扩展。 例如,假设创建一个 Deployment 以创建 `nginx:1.7.9` 的 5 个副本,然后更新 Deployment 以创建 5 个 `nginx:1.9.1` 的副本,而此时只有 3 个`nginx:1.7.9` 的副本已创建。在这种情况下, Deployment 会立即开始杀死3个 `nginx:1.7.9` Pods,并开始创建 `nginx:1.9.1` Pods。它不等待 `nginx:1.7.9` 的 5 个副本在改变任务之前完成创建。 ### 使用标签选择器进行更新 通常不鼓励更新标签选择器,建议提前规划选择器。在任何情况下,如果需要执行标签选择器更新,请格外小心,并确保已掌握所有的含义。 {{< note >}} 在 API 版本 `apps/v1` 中, Deployment 标签选择器在创建后是不可变的。 {{< /note >}} * 选择器添加还需要使用新标签更新 Deployment 规范中的 Pod 模板标签,否则将返回验证错误。此更改是非重叠的,这意味着新的选择器不选择使用旧选择器创建的 ReplicaSets 和 Pod,从而导致弃用所有旧 ReplicaSets 和创建新的 ReplicaSet 。 * 选择器更新更改选择器键中的现有值 -- 导致发生与添加相同的行为。 * 选择器删除从 Deployment 选择器中删除现有密钥 -- 不需要在Pod 模板标签做任意更改。现有 ReplicaSets 不会孤立,并且不会创建新的 ReplicaSet ,但请注意,已删除的标签仍然存在于任何现有的 Pods 和 ReplicaSets 中。 ## 回滚 Deployment 有时,可能需要回滚 Deployment ;例如,当 Deployment 不稳定时,例如循环崩溃。默认情况下,所有 Deployment 历史记录都保留在系统中,以便可以随时回滚(可以通过修改修改历史记录限制来更改该限制)。 {{< note >}} 触发 Deployment 展开时,将创建 Deployment 修改版。这意味着仅当 Deployment Pod 模板 (`.spec.template`) 发生更改时,才会创建新修改版本,例如,如果更新模板的标签或容器镜像 。其他更新,如扩展 Deployment 、不要创建 Deployment 修改版,以便方便同时手动或自动缩放。这意味着,当回滚到较早的修改版时,只有 Deployment Pod 模板部分回滚。 {{< /note >}} * 假设在更新 Deployment 时犯了一个拼写错误,将镜像名称命名为 `nginx:1.91` 而不是 `nginx:1.9.1`: ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true ``` 输出: ```shell deployment.apps/nginx-deployment image updated ``` * 展开遇到问题。可以通过检查展开状态来验证它: ```shell kubectl rollout status deployment.v1.apps/nginx-deployment ``` 输出: ```shell Waiting for rollout to finish: 1 out of 3 new replicas have been updated... ``` * 按 Ctrl-C 停止上述展开状态表。有关卡住展开的详细信息,[参考这里](#deployment-status) * 查看旧 ReplicaSets : ```shell kubectl get rs ``` 输出: ```shell 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 卡在镜像拉取循环中。 ```shell kubectl get pods ``` 输出: ```shell 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 ``` {{< note >}} Deployment 控制器自动停止不良展开,并停止向上扩展新的 ReplicaSet 。这取决于指定的滚动更新参数(具体为 `maxUnavailable`)。默认情况下,Kubernetes 将值设置为 25%。 {{< /note >}} * 获取 Deployment 描述信息: ```shell kubectl describe deployment ``` 输出: ```shell 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.91 Port: 80/TCP Host Port: 0/TCP Environment: Mounts: Volumes: 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 修改历史: ```shell kubectl rollout history deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployments "nginx-deployment" REVISION CHANGE-CAUSE 1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true 2 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true 3 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true ``` `CHANGE-CAUSE` 从 Deployment 注释 `kubernetes.io/change-cause` 创建时复制到其修改版。可以通过以下条件指定 `CHANGE-CAUSE` 消息: * 使用 `kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.9.1"` Deployment 对 Deployment 进行分号。 * 追加 `--record` 以保存正在更改资源的 `kubectl` 命令。 * 手动编辑资源的清单。 2. 查看修改历史的详细信息,运行: ```shell kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2 ``` 输出: ```shell deployments "nginx-deployment" revision 2 Labels: app=nginx pod-template-hash=1159050644 Annotations: kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true Containers: nginx: Image: nginx:1.9.1 Port: 80/TCP QoS Tier: cpu: BestEffort memory: BestEffort Environment Variables: No volumes. ``` ### 回滚到上一次修改 按照下面给出的步骤将 Deployment 从当前版本回滚到以前的版本(即版本 2)。 1. 现在已决定撤消当前展开并回滚到以前的版本: ```shell kubectl rollout undo deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployment.apps/nginx-deployment ``` 或者,可以通过使用 `--to-revision` 来回滚到特定修改版本: ```shell kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2 ``` 输出: ```shell deployment.apps/nginx-deployment ``` 更多有关回滚相关指令,请参考 [`kubectl rollout`](/docs/reference/generated/kubectl/kubectl-commands#rollout). 现在, Deployment 将回滚到以前的稳定版本。如所见, Deployment 回滚事件回滚到修改版 2 是从 Deployment 控制器生成的。 2. 检查回滚是否成功、 Deployment 是否正在运行,运行: ```shell kubectl get deployment nginx-deployment ``` 输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 30m ``` 3. 获取 Deployment 描述信息: ```shell kubectl describe deployment nginx-deployment ``` 输出: ```shell 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.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true 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.9.1 Port: 80/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: 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 : ```shell kubectl scale deployment.v1.apps/nginx-deployment --replicas=10 ``` 输出: ```shell deployment.apps/nginx-deployment scaled ``` 假设启用[水平自动缩放 Pod](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/)在集群中,可以为 Deployment 设置自动缩放器,并选择最小和最大 要基于现有 Pods 的 CPU 利用率运行的 Pods。 ```shell kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80 ``` 输出: ```shell deployment.apps/nginx-deployment scaled ``` ### 比例缩放 滚动更新 Deployments 支持同时运行应用程序的多个版本。当自动缩放器缩放处于展开中间的滚动更新 Deployment (仍在进行中或暂停)时, Deployment 控制器平衡现有活动中的其他 ReplicaSets (带 Pods 的 ReplicaSets ),以降低风险。这称为比例缩放。 例如,运行一个10个副本的 Deployment ,[最大增加](#max-surge)=3, [最大不可用](#max-unavailable)=2. * 确保这10个副本都在运行。 ```shell kubectl get deploy ``` 输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 10 10 10 10 50s ``` * 更新到新镜像,该镜像恰好无法从集群内部解析。 ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag ``` 输出: ```shell deployment.apps/nginx-deployment image updated ``` * 镜像更新使用 ReplicaSet nginx-deployment-1989198191 启动新的展开,但由于上面提到的最大不可用要求。检查展开状态: ```shell kubectl get rs ``` 输出: ```shell 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 中。使用比例缩放,可以将其他副本分布到所有 ReplicaSets 。更大的比例转到 ReplicaSets 与大多数副本和较低的比例都转到副本较少的 ReplicaSets 。任何剩余部分都添加到具有最多副本的 ReplicaSet 。具有零副本的 ReplicaSets 不会放大。 在上面的示例中,3 个副本添加到旧 ReplicaSet 中,2 个副本添加到新 ReplicaSet 。展开过程最终应将所有副本移动到新的 ReplicaSet ,假定新的副本变得正常。要确认这一点,请运行: ```shell kubectl get deploy ``` 输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 15 18 7 8 7m ``` 展开状态确认副本如何添加到每个 ReplicaSet 。 ```shell kubectl get rs ``` 输出: ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1989198191 7 7 0 7m nginx-deployment-618515232 11 11 11 7m ``` ## 暂停、恢复 Deployment 可以在触发一个或多个更新之前暂停 Deployment ,然后继续它。这允许在暂停和恢复之间应用多个修补程序,而不会触发不必要的 Deployment 。 * 例如,对于一个刚刚创建的 Deployment : 获取 Deployment 信息: ```shell kubectl get deploy ``` 输出: ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 3 3 3 3 1m ``` 获取 Deployment 状态: ```shell kubectl get rs ``` 输出: ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 1m ``` 使用如下指令中断运行: ```shell kubectl rollout pause deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployment.apps/nginx-deployment paused ``` * 然后更新 Deployment 镜像: ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 ``` 输出: ```shell deployment.apps/nginx-deployment image updated ``` * 注意没有新的展开: ```shell kubectl rollout history deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployments "nginx" REVISION CHANGE-CAUSE 1 ``` * 获取展开状态确保 Deployment 更新已经成功: ```shell kubectl get rs ``` 输出: ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 2m ``` * 更新是很容易的,例如,可以这样更新使用到的资源: ```shell kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi ``` 输出: ```shell deployment.apps/nginx-deployment resource requirements updated ``` 暂停 Deployment 之前的初始状态将继续其功能,但新的更新只要暂停 Deployment , Deployment 就不会产生任何效果。 * 最后,恢复 Deployment 并观察新的 ReplicaSet ,并更新所有新的更新: ```shell kubectl rollout resume deployment.v1.apps/nginx-deployment ``` 输出: ```shell deployment.apps/nginx-deployment resumed ``` * 观察展开的状态,直到完成。 ```shell kubectl get rs -w ``` 输出: ```shell 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 ``` * 获取最近展开的状态: ```shell kubectl get rs ``` 输出: ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 28s ``` 可以在触发一个或多个更新之前暂停 Deployment ,然后继续它。这允许在暂停和恢复之间应用多个修补程序,而不会触发不必要的 Deployment 。 * 例如,对于一个刚刚创建的 Deployment : 获取 Deployment 信息: ```shell kubectl get deploy ``` 输出: ``` NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 3 3 3 3 1m ``` 获取 Deployment 状态: ```shell kubectl get rs ``` 输出: ``` NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 1m ``` 使用如下指令中断运行: ```shell kubectl rollout pause deployment.v1.apps/nginx-deployment ``` 输出: ``` deployment.apps/nginx-deployment paused ``` * 然后更新 Deployment 镜像: ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 ``` 输出: ``` deployment.apps/nginx-deployment image updated ``` * 注意没有新的展开: ```shell kubectl rollout history deployment.v1.apps/nginx-deployment ``` 输出: ``` deployments "nginx" REVISION CHANGE-CAUSE 1 ``` * 获取展开状态确保 Deployment 更新已经成功: ```shell kubectl get rs ``` 输出: ``` NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 2m ``` * 更新是很容易的,例如,可以这样更新使用到的资源: ```shell kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi ``` 输出: ``` deployment.apps/nginx-deployment resource requirements updated ``` 暂停 Deployment 之前的初始状态将继续其功能,但新的更新只要暂停 Deployment , Deployment 就不会产生任何效果。 * 最后,恢复 Deployment 并观察新的 ReplicaSet ,并更新所有新的更新: ```shell kubectl rollout resume deployment.v1.apps/nginx-deployment ``` 输出: ``` deployment.apps/nginx-deployment resumed ``` * 观察展开的状态,直到完成。 ```shell 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 ``` * 获取最近展开的状态: ```shell kubectl get rs ``` 输出: ``` NAME DESIRED CURRENT READY AGE nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 28s ``` {{< note >}} 暂停的 Deployment 不可以回滚,除非恢复它以后。 {{< /note >}} ## Deployment 状态 一个 Deployment 的生命周期中会有许多状态。当正在生产新的 ReplicaSet 时可能是[正在运行](#progressing-deployment),可能是[已完成](#complete-deployment),也可能是[ Deployment 失败](#failed-deployment)。 ### 正在 Deployment Kubernetes 使用 _运行中_ 来标记一个 Deployment ,当下面的任务被执行时: * 创建新的 ReplicaSet 。 * 正在向上扩展最新的 ReplicaSet 。 * Deployment 向下扩展旧的 ReplicaSet(s) 。 * 新的 Pods 已经就绪或者可用(在[最小就绪时间](#min-ready-seconds)内就绪)。 可以使用 `kubectl rollout status` 监视 Deployment 的进度。 ### 完成 Deployment Kubernetes 将 Deployment 标记为 _完成_,当它具有以下特征时: * 与 Deployment 关联的所有副本都已更新到指定的最新版本,这意味着请求的任何更新都已完成。 * 与 Deployment 关联的所有副本都可用。 * 未运行 Deployment 的旧副本。 可以使用 `kubectl rollout status` 检查 Deployment 是否已完成。如果展开成功完成,`kubectl rollout status` 返回退出代码 0。 ```shell kubectl rollout status deployment.v1.apps/nginx-deployment ``` 输出: ```shell Waiting for rollout to finish: 2 of 3 updated replicas are available... deployment.apps/nginx-deployment successfully rolled out $ echo $? 0 ``` ### Deployment 失败 你的 Deployment 可能会在未完成的情况下尝试 Deployment 其最新的 ReplicaSet 时遇到问题。可能发生此情况由于以下一些因素: * 配额不足 * 就绪探测失败 * 镜像拉取错误 * 权限不足 * 限制范围 * 应用程序运行时配置错误 检测此条件的一种方法是在 Deployment 规范中指定截止时间参数:([`.spec.progressDeadlineSeconds`](#progress-deadline-seconds))。`.spec.progressDeadlineSeconds` 进度截止时间秒表示 Deployment 控制器在指示(处于 Deployment 状态)之前等待的秒数 Deployment 进度已停止。 以下 `kubectl` 命令设置具有进度的规范,使控制器报告 10 分钟后 Deployment 进度不足: ```shell kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}' ``` 输出: ```shell deployment.apps/nginx-deployment patched ``` 超过截止时间后, Deployment 控制器将添加具有以下属性到 Deployment 的 `.status.conditions` : * Type=Progressing * Status=False * Reason=ProgressDeadlineExceeded 参考 [Kubernetes API 约定](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties) 获取更多状态条件相关信息。 {{< note >}} Kubernetes 对已停止的 Deployment 不执行任何操作,只需使用`Reason=ProgressDeadlineExceeded`。更高级别的编排器可以利用它并相应地采取行动,例如,将 Deployment 回滚到其以前的版本。 {{< /note >}} {{< note >}} 如果暂停 Deployment ,Kubernetes 不会根据指定的截止时间检查进度。可以在展开栏中间安全地暂停 Deployment ,并在不触发超过最后期限时恢复。 {{< /note >}} Deployments 可能会出现短暂的错误,既不是因为设置的超时时间过短,也不是因为任何真正的暂时性错误。例如配额不足。如果描述 Deployment ,将注意到以下部分: ```shell kubectl describe deployment nginx-deployment ``` 输出: ```shell <...> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True ReplicaSetUpdated ReplicaFailure True FailedCreate <...> ``` 如果运行 `kubectl get deployment nginx-deployment -o yaml`, Deployment 状态输出: ```shell 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 将更新状态和进度状态: ```shell Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing False ProgressDeadlineExceeded ReplicaFailure True FailedCreate ``` 可以通过缩减 Deployment 来解决配额不足的问题,或者直接在命名空间中增加配额。如果配额条件满足, Deployment 控制器完成了 Deployment 展开, Deployment 状态会更新为成功(`Status=True` and `Reason=NewReplicaSetAvailable`)。 ```shell 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 是否未能取得进展。`kubectl rollout status`如果 Deployment 已超过进度截止时间,则返回非零退出代码。 ```shell kubectl rollout status deployment.v1.apps/nginx-deployment ``` 输出: ```shell 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 模板中应用多个调整,甚至将其暂停。 ## 清理策略 可以在 Deployment 中设置 `.spec.revisionHistoryLimit` ,以指定保留多少此 Deployment 的 ReplicaSets。其余的将在后台进行垃圾回收。默认情况下,是10。 {{< note >}} 显式将此字段设置为 0 将导致清理 Deployment 的所有历史记录,因此 Deployment 将无法回滚。 {{< /note >}} ## 金丝雀 Deployment 如果要使用 Deployment 向用户或服务器子集展开版本,则可以创建多个 Deployments ,每个版本一个,遵循[资源管理](/docs/concepts/cluster-administration/manage-deployment/#canary-deployments)。 ## 编写 Deployment 脚本 同其他 Kubernetes 配置, Deployment 需要 `apiVersion`, `kind`, 和 `metadata` 字段。有关配置文件的其他信息,参考 [应用 Deployment ](/docs/tutorials/stateless-application/run-stateless-application-deployment/),配置容器,和 [使用 kubectl 管理资源](/docs/concepts/overview/working-with-objects/object-management/) 相关文档。 Deployment 还需要 [`.spec` 部分](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status)。 ### Pod 示例 `.spec`仅需要 `.spec.template` 和 `.spec.selector`。 `.spec.template` 是一个 [Pod 示例](/docs/concepts/workloads/pods/pod-overview/#pod-templates)。它和 [Pod](/docs/concepts/workloads/pods/pod/)的约束完全相同,除了它是嵌套的,而且没有 `apiVersion` 或 `kind`。 除了 Pod 的必填字段外, Deployment 中的 Pod 模板必须指定适当的标签和适当的重新启动策略。对于标签,请确保不要与其他控制器重叠。请参考[选择器](#selector))。 只有 [`.spec.template.spec.restartPolicy`](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) 等于 `Always` 被允许,这是在没有指定时的默认设置。 ### 副本 `.spec.replicas` 是指定所需 Pod 的可选字段。它的默认值是1。 ### 选择器 `.spec.selector` 是指定本次 Deployment Pods [标签选择器](/docs/concepts/overview/working-with-objects/labels/)的必要字段。 `.spec.selector` 必须匹配 `.spec.template.metadata.labels`,否则请求会被 API 拒绝。 在 API `apps/v1`版本中,`.spec.selector` 和 `.metadata.labels` 不会被默认设置为 `.spec.template.metadata.labels`,如果没有设置的话。所以需要明确进行设置。同时在 `apps/v1`版本中, Deployment 创建后 `.spec.selector` 是可变的。 当 Pods 的标签和选择器匹配时,此类 Pods 的模板和 `.spec.template` 不同,或者此类 Pods 的总数超过 `.spec.replicas`, Deployment 会终结这些 Pods。如果 Pods 总数达不到期望值,会用 `.spec.template` 创建新的 Pods。 {{< note >}} 不应创建其标签与此选择器匹配的 Pods,或者直接创建另一个 Deployment ,或通过创建其他控制器(如 ReplicaSet 或复制控制器)。如果这样做,第一个 Deployment 认为它创建了这些其他 Pods。Kubernetes 不会阻止你这么做。 {{< /note >}} 如果有多个具有重叠选择器的控制器,则控制器之间会因冲突而故障。 ### 策略 `.spec.strategy` 策略指定用于用新 Pods 替换旧 Pods 的策略。`.spec.strategy.type` 可以是“Recreate”或“RollingUpdate”。“RollingUpdate”是默认值。 #### 重新创建 Deployment 当 `.spec.strategy.type==Recreate`,所有现有的 Pods 在创建新 Pods 之前被杀死。 #### 滚动更新 Deployment Deployment 会在 `.spec.strategy.type==RollingUpdate`时,采取 [滚动更新](/docs/tasks/run-application/rolling-update-replication-controller/)的方式更新Pods。可以指定 `maxUnavailable` 和 `maxSurge` 来控制滚动更新操作。 ##### 最大不可用 `.spec.strategy.rollingUpdate.maxUnavailable` 是指定最大数量的可选字段,表示在更新过程中不可用的 Pods。该值可以是绝对数字(例如,5)或所需 Pods 的百分比(例如,10%)。绝对数按百分比计算,四舍五入下来。如果 `.spec.strategy.rollingUpdate.maxSurge` 为 0,则该值不能为 0。默认值为 25%。 例如,当此值设置为 30% 时,滚动更新开始时会立即将旧 ReplicaSet 向下扩展到期望 Pods 的70%。新 Pods 准备就绪后,可以缩放旧 ReplicaSet 进一步向下,然后向上扩展新的 ReplicaSet ,确保可用的 Pods 总数在更新期间,任何时候都至少为 70% 所需的 Pods。 ##### 最大增量 `.spec.strategy.rollingUpdate.maxSurge` 是指定最大 Pods 数的可选字段可在所需的 Pods 数上创建。该值可以是绝对数(例如,5)或所需 Pods 的百分比(例如,10%)。如果 `MaxUnavailable` 0,则值不能为 0。绝对数通过舍入从百分比计算。默认值为 25%。 例如,当此值设置为 30% 时,启动滚动更新后,会立即展开新的 ReplicaSet ,以便新旧 Pod 的总数不超过所需的 130%。一旦旧 Pods 被杀死,新的 ReplicaSet 可以进一步扩展,确保更新期间任何时间运行的 Pods 总数最多为所需 Pods 总数的130%。 ### Deployment 失败等待时间 `.spec.progressDeadlineSeconds` 是一个可选字段,用于指定等待的秒数而后在系统报告中返回[ Deployment 失败](#failed-deployment),同时在资源状态中 `Type=Progressing`、 `Status=False` 、 `Reason=ProgressDeadlineExceeded` 。 Deployment 控制器将保留正在重试 Deployment 。将来,一旦实现自动回滚, Deployment 控制器将回滚 Deployment ,只要它探测到这样的条件。 如果指定,则此字段需要大于 `.spec.minReadySeconds`。 ### 最小就绪时间 `.spec.minReadySeconds` 是一个可选字段,用于指定新创建的 Pod 在没有任意容器崩溃情况下的最小就绪时间,以便将其视为可用。默认值为 0(Pod 在准备就绪后立即将被视为可用)。了解有关何时Pod 被视为已准备就绪,参考[容器探针](/docs/concepts/workloads/pods/pod-lifecycle/#container-probes)。 ### 回滚 `.spec.rollbackTo` 字段已经在 API 版本 `extensions/v1beta1` 和 `apps/v1beta1`中废弃了,并且从 `apps/v1beta2`版本开始不在支持。相应的,会开始使用已经引入[回滚到上一个版本](#rolling-back-to-a-previous-revision)中的 `kubectl rollout undo`。 ### 修改历史限制 Deployment 修改历史记录存储在它所控制的 ReplicaSets 中。 `.spec.revisionHistoryLimit` 修改历史记录限制是一个可选字段,用于指定要保留的旧 ReplicaSets 的数量以允许回滚。这些旧 ReplicaSets 消耗 etcd 中的资源,并占用 `kubectl get rs` 的输出。每个 Deployment 修改版的配置都存储在其 ReplicaSets 中;因此,一旦删除了旧的 ReplicaSet ,将失去回滚到 Deployment 版本的能力。默认情况下,将保留 10 个旧 ReplicaSets ,但其理想值取决于新 Deployment 的频率和稳定性。 更具体地说,将此字段设置为 0 意味着将清理所有具有 0 个副本的旧 ReplicaSets 。在这种情况下,无法撤消新的 Deployment 展开,因为它的修改历史被清除了。 ### 暂停 `.spec.paused` 是用于暂停和恢复 Deployment 的可选布尔字段。暂停的 Deployment 和未暂停的 Deployment 唯一的区别,只要暂停 Deployment 处于暂停状态, PodTemplateSpec 的任意修改都不会触发新的展开。默认 Deployment 在创建时是不会被暂停的。 ## Deployments 的替代方案 ### kubectl滚动更新 [`kubectl rolling update`](/docs/reference/generated/kubectl/kubectl-commands#rolling-update)更新 Pods 和副本控制器的方式类似。但是,建议采取 Deployments 的方式来更新,因为它们是声明性的,在服务器端,并且具有其他功能,例如,即使在滚动更新完成后,也会回滚到以前的任何修改版本。