部署
Deployment 为 Pod 和 ReplicaSet 提供声明式更新。
你在 Deployment 中描述了**期望状态**,而 Deployment Controller 以受控速率将实际状态更改为期望状态。你可以定义 Deployment 来创建新的 ReplicaSet,或者删除现有的 Deployment 并用新的 Deployment 采用其所有资源。
注意
不要管理由 Deployment 所拥有的 ReplicaSet。如果你的用例未在下面介绍,请考虑在 Kubernetes 主仓库中提交一个 Issue。用例
以下是 Deployment 的典型用例
- 创建 Deployment 来 rollout 一个 ReplicaSet。ReplicaSet 在后台创建 Pod。检查 rollout 状态,以查看其是否成功。
- 通过更新 Deployment 的 PodTemplateSpec 来声明 Pod 的新状态。会创建一个新的 ReplicaSet,并且 Deployment 以受控速率将 Pod 从旧的 ReplicaSet 迁移到新的 ReplicaSet。每个新的 ReplicaSet 都更新 Deployment 的修订版本。
- 如果 Deployment 的当前状态不稳定,则回滚到较早的 Deployment 修订版本。每次回滚都会更新 Deployment 的修订版本。
- 扩容 Deployment 以处理更多负载.
- 暂停 Deployment 的 rollout 以对其 PodTemplateSpec 应用多个修复,然后恢复它以开始新的 rollout。
- 将Deployment 的状态用作 rollout 是否卡住的指示器。
- 清理不再需要的旧 ReplicaSet。
创建 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 规约。Deployment 创建一个 ReplicaSet,该 ReplicaSet 根据
.spec.replicas
字段指定的数量创建三个副本 Pod。.spec.selector
字段定义了所创建的 ReplicaSet 如何找到它要管理的 Pod。在本例中,你选择 Pod 模板中定义的标签(app: nginx
)。但是,可以使用更复杂的选择规则,只要 Pod 模板本身满足这些规则即可。注意
.spec.selector.matchLabels
字段是一个 {key,value} 键值对映射。matchLabels
映射中的单个 {key,value} 等效于matchExpressions
中的一个元素,其key
字段是“key”,operator
是“In”,而values
数组只包含“value”。matchLabels
和matchExpressions
中的所有条件都必须满足才能匹配。.spec.template
字段包含以下子字段- Pod 使用
.metadata.labels
字段被打上标签app: nginx
。 - Pod 模板的规约,或者说
.spec
字段,表明这些 Pod 运行一个容器nginx
,它运行 Docker Hub 中的nginx
镜像,版本为 1.14.2。 - 使用
.spec.containers[0].name
字段创建一个容器并将其命名为nginx
。
- Pod 使用
开始之前,请确保你的 Kubernetes 集群正在运行。按照以下步骤创建上述 Deployment
通过运行以下命令创建 Deployment
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
运行
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。要查看 Deployment 的 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
几秒钟后再次运行
kubectl get deployments
。输出类似于此NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 18s
注意 Deployment 创建了所有三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板)且可用。
要查看 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
标签相同。要查看为每个 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。
注意
你必须在 Deployment 中指定适当的选择算符和 Pod 模板标签(在本例中为 app: nginx
)。
不要让标签或选择算符与其他控制器(包括其他 Deployment 和 StatefulSet)重叠。Kubernetes 不会阻止你重叠,但如果多个控制器具有重叠的选择算符,这些控制器可能会冲突并出现意外行为。
Pod 模板哈希标签
注意
不要更改此标签。pod-template-hash
标签由 Deployment 控制器添加到 Deployment 创建或采用的每个 ReplicaSet 中。
此标签确保 Deployment 的子 ReplicaSet 不重叠。它是通过对 ReplicaSet 的 PodTemplate 进行哈希计算,并将计算出的哈希值用作标签值,添加到 ReplicaSet 的选择算符、Pod 模板标签以及 ReplicaSet 可能拥有的任何现有 Pod 中。
更新 Deployment
注意
只有当 Deployment 的 Pod 模板(即.spec.template
)发生更改时,例如模板的标签或容器镜像被更新,Deployment 的 rollout 才会触发。其他更新,例如扩缩 Deployment,不会触发 rollout。按照以下步骤更新你的 Deployment
让我们将
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
要查看 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
获取关于已更新 Deployment 的更多详情
rollout 成功后,你可以通过运行
kubectl get deployments
查看 Deployment。输出类似于此NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 36s
运行
kubectl get rs
查看 Deployment 如何通过创建新的 ReplicaSet 并将其扩容到 3 个副本来更新 Pod,同时将旧的 ReplicaSet 缩容到 0 个副本。kubectl get rs
输出类似于此
NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 6s nginx-deployment-2035384211 0 0 0 36s
现在运行
get pods
应该只显示新的 Podkubectl 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 数量不会超过期望数量的一定比例。默认情况下,它确保最多有 125% 的期望 Pod 数量处于可用状态(最多 25% 额外 Pod)。
例如,如果你仔细查看上面的 Deployment,你会看到它首先创建一个新的 Pod,然后删除一个旧的 Pod,再创建一个新的 Pod。它不会杀死旧的 Pod,直到足够数量的新 Pod 启动;它也不会创建新的 Pod,直到足够数量的旧 Pod 被终止。它确保至少有 3 个 Pod 可用,并且总共最多有 4 个 Pod 可用。如果 Deployment 有 4 个副本,则 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。
注意
Kubernetes 在计算availableReplicas
数量时,不计算正在终止的 Pod。availableReplicas
必须在 replicas - maxUnavailable
和 replicas + maxSurge
之间。因此,你可能会注意到在 rollout 期间 Pod 数量比预期多,并且 Deployment 消耗的总资源超过 replicas + maxSurge
,直到正在终止的 Pod 的 terminationGracePeriodSeconds
过期。覆盖(也称为正在进行的多个更新)
每当 Deployment 控制器发现新的 Deployment 时,就会创建一个 ReplicaSet 来启动期望的 Pod。如果 Deployment 被更新,则现有的 ReplicaSet(控制标签匹配 .spec.selector
但模板不匹配 .spec.template
的 Pod)将被缩容。最终,新的 ReplicaSet 会扩容到 .spec.replicas
,所有旧的 ReplicaSet 都将缩容到 0。
如果在现有 rollout 正在进行时更新 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
副本创建完毕后才改变策略。
标签选择算符更新
通常不鼓励进行标签选择算符的更新,建议提前规划好选择算符。无论如何,如果你需要执行标签选择算符更新,务必非常小心,并确保你已充分理解所有影响。
注意
在 API 版本apps/v1
中,Deployment 的标签选择算符创建后是不可变的。- 选择算符的添加要求 Deployment 规约中的 Pod 模板标签也随新标签一起更新,否则将返回验证错误。此更改是非重叠式的,意味着新的选择算符不会选中使用旧选择算符创建的 ReplicaSet 和 Pod,从而导致所有旧的 ReplicaSet 成为孤儿并创建一个新的 ReplicaSet。
- 选择算符更新改变了选择算符键中的现有值 -- 导致与添加相同的行为。
- 选择算符删除从 Deployment 选择算符中移除一个现有键 -- 不需要在 Pod 模板标签中进行任何更改。现有的 ReplicaSet 不会被孤儿化,也不会创建新的 ReplicaSet,但请注意,已移除的标签仍存在于任何现有的 Pod 和 ReplicaSet 中。
回滚 Deployment
有时,你可能想要回滚 Deployment;例如,当 Deployment 不稳定时,例如持续崩溃重启。默认情况下,所有 Deployment 的 rollout 历史都保留在系统中,以便你可以随时回滚(你可以通过修改修订历史限制来更改此设置)。
注意
只有当 Deployment 的 rollout 被触发时,才会创建 Deployment 的修订版本。这意味着只有当 Deployment 的 Pod 模板(.spec.template
)发生更改时,例如更新了模板的标签或容器镜像,才会创建新的修订版本。其他更新,例如扩缩 Deployment,不会创建 Deployment 修订版本,以便于同时进行手动或自动扩缩容。这意味着当你回滚到较早的修订版本时,只会回滚 Deployment 的 Pod 模板部分。假设你在更新 Deployment 时输错了图像名称,将
nginx:1.16.1
写成了nginx:1.161
kubectl set image deployment/nginx-deployment nginx=nginx:1.161
输出类似于此
deployment.apps/nginx-deployment image updated
rollout 卡住了。你可以通过检查 rollout 状态来验证
kubectl rollout status deployment/nginx-deployment
输出类似于此
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
按 Ctrl-C 停止上面 rollout 状态的 监视(Watch)。有关卡住的 rollout 的更多信息,请在此阅读更多。
你看到旧副本的数量(
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 控制器会自动停止这个有问题的 rollout,并停止扩容新的 ReplicaSet。这取决于你指定的 rollingUpdate 参数(特别是maxUnavailable
)。Kubernetes 默认将其值设置为 25%。获取 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 的 Rollout 历史
按照以下步骤检查 rollout 历史
首先,检查此 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 添加注解 - 手动编辑资源的清单。
- 使用命令
要查看每个修订版本的详细信息,请运行
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。
现在你已决定撤销当前的 rollout 并回滚到上一个修订版本
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
有关 rollout 相关命令的更多详细信息,请阅读
kubectl rollout
。Deployment 现在已回滚到以前的稳定修订版本。正如你所见,Deployment 控制器生成了一个回滚到修订版本 2 的
DeploymentRollback
事件。运行以下命令检查回滚是否成功以及 Deployment 是否按预期运行
kubectl get deployment nginx-deployment
输出类似于此
NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 30m
获取 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
按比例扩缩
RollingUpdate 类型的 Deployment 支持同时运行多个版本的应用程序。当你或自动扩缩器扩缩一个正在 rollout 中的 RollingUpdate 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
镜像更新启动了新的 rollout,并创建了 ReplicaSet
nginx-deployment-1989198191
,但由于你上面提到的maxUnavailable
要求而卡住了。检查 rollout 状态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 中。假设新的副本变得健康,rollout 进程最终会将所有副本迁移到新的 ReplicaSet。要确认这一点,请运行
kubectl get deploy
输出类似于此
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
rollout 状态确认了副本是如何添加到每个 ReplicaSet 的。
kubectl get rs
输出类似于此
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
暂停和恢复 Deployment 的 rollout
当你更新或计划更新 Deployment 时,可以在触发一次或多次更新之前暂停该 Deployment 的 rollout。当你准备好应用这些更改时,恢复 Deployment 的 rollout。这种方法允许你在暂停和恢复之间应用多个修复,而不会触发不必要的 rollout。
例如,对于已创建的 Deployment
获取 Deployment 详细信息
kubectl get deploy
输出类似于此
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 3 3 3 3 1m
获取 rollout 状态
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
注意没有新的 rollout 开始
kubectl rollout history deployment/nginx-deployment
输出类似于此
deployments "nginx" REVISION CHANGE-CAUSE 1 <none>
获取 rollout 状态以验证现有 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 在暂停 rollout 之前的初始状态将继续其功能,但是只要 Deployment rollout 处于暂停状态,对 Deployment 的新更新将不会产生任何影响。
最终,恢复 Deployment rollout 并观察一个新的 ReplicaSet 带着所有新更新启动
kubectl rollout resume deployment/nginx-deployment
输出类似于此
deployment.apps/nginx-deployment resumed
监视(Watch) rollout 的状态直到完成。
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
获取最新 rollout 的状态
kubectl get rs
输出类似于此
NAME DESIRED CURRENT READY AGE nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 28s
注意
除非你恢复一个暂停的 Deployment,否则不能回滚它。Deployment 状态
Deployment 在其生命周期中会进入各种状态。它可能在 rollout 新的 ReplicaSet 时处于进行中(progressing),可能已完成(complete),或者未能进展(fail to progress)。
正在进行的 Deployment
当执行以下一项任务时,Kubernetes 会将 Deployment 标记为**进行中**
- Deployment 创建了一个新的 ReplicaSet。
- Deployment 正在扩容其最新的 ReplicaSet。
- Deployment 正在缩容其较旧的 ReplicaSet。
- 新的 Pod 变得就绪或可用(至少在MinReadySeconds 内保持就绪)。
当 rollout 进入“进行中”状态时,Deployment 控制器会向 Deployment 的 .status.conditions
中添加一个具有以下属性的条件
type: Progressing
status: "True"
reason: NewReplicaSetCreated
|reason: FoundNewReplicaSet
|reason: ReplicaSetUpdated
你可以使用 kubectl rollout status
监视 Deployment 的进度。
已完成的 Deployment
当 Deployment 具有以下特征时,Kubernetes 会将其标记为**已完成**
- 与 Deployment 相关联的所有副本都已更新到你指定的最新版本,这意味着你请求的所有更新都已完成。
- 与 Deployment 相关联的所有副本都可用。
- 没有旧的 Deployment 副本在运行。
当 rollout 进入“完成”状态时,Deployment 控制器会向 Deployment 的 .status.conditions
设置一个具有以下属性的条件
type: Progressing
status: "True"
reason: NewReplicaSetAvailable
这个 Progressing
条件将保留 "True"
的状态值,直到启动新的 rollout。即使副本的可用性发生变化(这会影响 Available
条件),此条件仍然保持。
你可以使用 kubectl rollout status
检查 Deployment 是否已完成。如果 rollout 成功完成,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 时卡住,永远无法完成。这可能是由于以下一些因素造成的
- 配额不足
- 就绪探针失败
- 镜像拉取错误
- 权限不足
- LimitRange
- 应用程序运行时配置错误
检测此情况的一种方法是在 Deployment 规约中指定一个期限参数:(.spec.progressDeadlineSeconds
)。.spec.progressDeadlineSeconds
表示 Deployment 控制器在标记(在 Deployment 状态中)Deployment 进度停滞之前等待的秒数。
以下 kubectl
命令设置带有 progressDeadlineSeconds
的规约,以便控制器在 10 分钟后报告 Deployment rollout 没有进展
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
等原因将 status 值设置为 "False"
。此外,一旦 Deployment 滚动更新完成,将不再考虑该截止时间。
更多关于状态条件的信息,请参阅Kubernetes API 约定。
注意
对于停滞的 Deployment,Kubernetes 除了报告状态条件reason: ProgressDeadlineExceeded
外,不采取任何其他行动。更高级别的协调器可以利用此信息并采取相应行动,例如将 Deployment 回滚到以前的版本。注意
如果你暂停了 Deployment 滚动更新,Kubernetes 不会对照你指定的截止时间检查进度。你可以在滚动更新过程中安全地暂停 Deployment 滚动更新,并在之后恢复,而不会触发超过截止时间的条件。你的 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 具有最低可用性。最低可用性由部署策略中指定的参数决定。type: Progressing
且 status: "True"
意味着你的 Deployment 正在进行滚动更新并且正在取得进展,或者它已成功完成进度并且所需的最低数量的新副本已可用(有关详细信息,请参阅条件的 Reason——在本例中,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。
注意
将此字段显式设置为 0,将导致清理你 Deployment 的所有历史记录,从而该 Deployment 将无法回滚。清理过程仅在 Deployment 达到 完成状态后开始。如果你将 .spec.revisionHistoryLimit
设置为 0,任何滚动更新仍会在 Kubernetes 删除旧的 ReplicaSet 之前触发创建新的 ReplicaSet。
即使设置了非零的 revision history limit,你拥有的 ReplicaSet 数量也可能超过你配置的限制。例如,如果 Pod 正在崩溃循环,并且随着时间的推移触发了多个滚动更新事件,你最终拥有的 ReplicaSet 数量可能会超过 .spec.revisionHistoryLimit
,因为 Deployment 永远无法达到完成状态。
金丝雀部署
如果你想使用 Deployment 向部分用户或服务器发布版本,你可以创建多个 Deployment,每个版本一个,遵循管理资源中描述的金丝雀模式。
编写 Deployment Spec
与其他所有 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 模板必须指定适当的标签和适当的重启策略。对于标签,请确保不要与其他控制器重叠。请参阅selector。
仅允许 .spec.template.spec.restartPolicy
等于 Always
,如果未指定,这是默认值。
副本数
.spec.replicas
是一个可选字段,指定所需的 Pod 数量。默认为 1。
如果你手动缩放 Deployment(例如通过 kubectl scale deployment deployment --replicas=X
),然后你基于 manifest 文件更新该 Deployment(例如:通过运行 kubectl apply -f deployment.yaml
),那么应用该 manifest 会覆盖你之前手动进行的缩放操作。
如果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 数量少于所需数量,则会根据 .spec.template
启动新的 Pod。
注意
你不应该创建标签与此选择器匹配的其他 Pod,无论是直接创建,还是通过创建另一个 Deployment,或者创建 ReplicaSet 或 ReplicationController 等其他控制器。如果你这样做,第一个 Deployment 会认为它创建了这些其他 Pod。Kubernetes 不会阻止你这样做。如果你有多个控制器具有重叠的选择器,这些控制器将相互冲突,并且无法正常工作。
策略
.spec.strategy
指定用于将旧 Pod 替换为新 Pod 的策略。.spec.strategy.type
可以是 "Recreate" 或 "RollingUpdate"。"RollingUpdate" 是默认值。
重建式部署
当 .spec.strategy.type==Recreate
时,所有现有的 Pod 都会被杀死,然后才会创建新的 Pod。
注意
这仅能确保升级时在新 Pod 创建之前终止旧 Pod。如果你升级 Deployment,旧版本的所有 Pod 将立即被终止。等待成功删除后,才会创建新版本的 Pod。如果你手动删除了一个 Pod,其生命周期由 ReplicaSet 控制,新的 Pod 将立即创建(即使旧 Pod 仍处于 Terminating 状态)。如果你需要 Pod 的“最多”保证,应该考虑使用 StatefulSet。滚动更新式部署
当 .spec.strategy.type==RollingUpdate
时,Deployment 会以滚动更新的方式更新 Pod。你可以指定 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 的总数不超过期望 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 取得进展的秒数——这在资源的 status 中会显示为一个条件,其中 type: Progressing
,status: "False"
,以及 reason: ProgressDeadlineExceeded
。Deployment 控制器将继续重试 Deployment。该字段默认为 600。将来,一旦实现了自动回滚,Deployment 控制器在观察到此条件后会立即回滚 Deployment。
如果指定,此字段需要大于 .spec.minReadySeconds
。
最小就绪秒数
.spec.minReadySeconds
是一个可选字段,指定新创建的 Pod 在没有容器崩溃的情况下保持就绪的最小秒数,以便将其视为可用。默认值为 0(Pod 一旦就绪即被视为可用)。要详细了解 Pod 何时被视为就绪,请参阅容器探针。
正在终止的 Pod
Kubernetes v1.33 [alpha]
(默认启用: false)你可以通过在 API server 和 kube-controller-manager 上设置 DeploymentReplicaSetTerminatingReplicas
特性门控来启用此功能。
由于删除或缩减而变为 terminating 状态的 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 时,默认不处于暂停状态。
接下来
- 了解更多关于 Pod 的信息。
- 使用 Deployment 运行无状态应用.
- 阅读 Deployment 以了解 Deployment API。
- 了解 PodDisruptionBudget 以及如何使用它来在中断期间管理应用的可用性。
- 使用 kubectl 创建 Deployment。