diff --git a/content/zh/docs/concepts/workloads/pods/disruptions.md b/content/zh/docs/concepts/workloads/pods/disruptions.md index e47577bfe1..304f3703d5 100644 --- a/content/zh/docs/concepts/workloads/pods/disruptions.md +++ b/content/zh/docs/concepts/workloads/pods/disruptions.md @@ -1,19 +1,13 @@ --- -title: 干扰 +title: 干扰(Disruptions) content_type: concept weight: 60 --- @@ -22,31 +16,23 @@ This guide is for application owners who want to build highly available applications, and thus need to understand what types of Disruptions can happen to Pods. --> - 本指南针对的是希望构建高可用性应用程序的应用所有者,他们有必要了解可能发生在 pod 上的干扰类型。 - 文档同样适用于想要执行自动化集群操作(例如升级和自动扩展集群)的集群管理员。 - - - -## 自愿干扰和非自愿干扰 - - +## 自愿干扰和非自愿干扰 {#voluntary-and-involuntary-disruptions} Pod 不会消失,除非有人(用户或控制器)将其销毁,或者出现了不可避免的硬件或软件系统错误。 @@ -54,8 +40,7 @@ Pod 不会消失,除非有人(用户或控制器)将其销毁,或者出 We call these unavoidable cases *involuntary disruptions* to an application. Examples are: --> - -我们把这些不可避免的情况称为应用的*非自愿干扰*。例如: +我们把这些不可避免的情况称为应用的*非自愿干扰(Involuntary Disruptions)*。例如: - 除了资源不足的情况,大多数用户应该都熟悉这些情况;它们不是特定于 Kubernetes 的。 - -我们称其他情况为*自愿干扰*。包括由应用程序所有者发起的操作和由集群管理员发起的操作。典型的应用程序所有者的操 +我们称其他情况为*自愿干扰(Voluntary Disruptions)*。 +包括由应用程序所有者发起的操作和由集群管理员发起的操作。典型的应用程序所有者的操 作包括: - -- 删除 deployment 或其他管理 pod 的控制器 -- 更新了 deployment 的 pod 模板导致 pod 重启 -- 直接删除 pod(例如,因为误操作) +- 删除 Deployment 或其他管理 Pod 的控制器 +- 更新了 Deployment 的 Pod 模板导致 Pod 重启 +- 直接删除 Pod(例如,因为误操作) -集群管理员操作包括: - - +集群管理员操作包括: -- [排空(drain)节点](/docs/tasks/administer-cluster/safely-drain-node/)进行修复或升级。 -- 从集群中排空节点以缩小集群(了解[集群自动扩缩](/docs/tasks/administer-cluster/cluster-management/#cluster-autoscaler))。 -- 从节点中移除一个 pod,以允许其他 pod 使用该节点。 +- [排空(drain)节点](/zh/docs/tasks/administer-cluster/safely-drain-node/)进行修复或升级。 +- 从集群中排空节点以缩小集群(了解[集群自动扩缩](/zh/docs/tasks/administer-cluster/cluster-management/#cluster-autoscaler))。 +- 从节点中移除一个 Pod,以允许其他 Pod 使用该节点。 - 这些操作可能由集群管理员直接执行,也可能由集群管理员所使用的自动化工具执行,或者由集群托管提供商自动执行。 - -咨询集群管理员或联系云提供商,或者查询发布文档,以确定是否为集群启用了任何资源干扰源。如果没有启用,可以不用创建 Pod Disruption Budgets(Pod 干扰预算) - -{{< caution >}} +咨询集群管理员或联系云提供商,或者查询发布文档,以确定是否为集群启用了任何资源干扰源。 +如果没有启用,可以不用创建 Pod Disruption Budgets(Pod 干扰预算) - -并非所有的自愿干扰都会受到 pod 干扰预算的限制。例如,删除 deployment 或 pod 的删除操作就会跳过 pod 干扰预算检查。 - +{{< caution >}} +并非所有的自愿干扰都会受到 Pod 干扰预算的限制。 +例如,删除 Peployment 或 Pod 的删除操作就会跳过 Pod 干扰预算检查。 {{< /caution >}} -## 处理干扰 - - +## 处理干扰 以下是减轻非自愿干扰的一些方法: @@ -167,10 +141,13 @@ spread applications across racks (using or across zones (if using a [multi-zone cluster](/docs/setup/multiple-zones).) --> - -- 确保 pod[请求所需资源](/docs/tasks/configure-pod-container/assign-cpu-ram-container)。 -- 如果需要更高的可用性,请复制应用程序。(了解有关运行多副本的[无状态](/docs/tasks/run-application/run-stateless-application-deployment/)和[有状态](/docs/tasks/run-application/run-replicated-stateful-application/)应用程序的信息。) -- 为了在运行复制应用程序时获得更高的可用性,请跨机架(使用[反亲和性](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature))或跨区域(如果使用[多区域集群](/docs/setup/multiple-zones))扩展应用程序。 +- 确保 Pod 在请求中给出[所需资源](/zh/docs/tasks/configure-pod-container/assign-memory-resource/)。 +- 如果需要更高的可用性,请复制应用程序。 + (了解有关运行多副本的[无状态](/zh/docs/tasks/run-application/run-stateless-application-deployment/) + 和[有状态](/zh/docs/tasks/run-application/run-replicated-stateful-application/)应用程序的信息。) +- 为了在运行复制应用程序时获得更高的可用性,请跨机架(使用 + [反亲和性](/zh/docs/concepts/scheduling-eviction/assign-pod-node/))或跨区域 + (如果使用[多区域集群](/zh/docs/setup/best-practices/multiple-zones/))扩展应用程序。 - 自愿干扰的频率各不相同。在一个基本的 Kubernetes 集群中,根本没有自愿干扰。然而,集群管理 或托管提供商可能运行一些可能导致自愿干扰的额外服务。例如,节点软 更新可能导致自愿干扰。另外,集群(节点)自动缩放的某些 @@ -193,16 +169,15 @@ Kubernetes offers features to help run highly available applications at the same time as frequent voluntary disruptions. We call this set of features *Disruption Budgets*. --> - -Kubernetes 提供特性来满足在出现频繁自愿干扰的同时运行高可用的应用程序。我们称这些特性为*干扰预算* +Kubernetes 提供特性来满足在出现频繁自愿干扰的同时运行高可用的应用程序。我们称这些特性为 +*干扰预算(Disruption Budget)*。 +## Pod disruption budgets -## 干扰预算工作原理 +Kubernetes offers features to help you run highly available applications even when you +introduce frequent voluntary disruptions. - +## 干扰预算 -应用程序所有者可以为每个应用程序创建 `PodDisruptionBudget` 对象(PDB)。PDB 将限制在同一时间因自愿干扰导致的复制应用程序中宕机的 pod 数量。例如,基于定额的应用程序希望确保运行的副本数 -永远不会低于仲裁所需的数量。Web 前端可能希望确保提供负载的副本数量永远不会低于总数的某个百分比。 +{{< feature-state for_k8s_version="v1.5" state="beta" >}} + +即使你会经常引入自愿性干扰,Kubernetes 也能够支持你运行高度可用的应用。 + +应用程序所有者可以为每个应用程序创建 `PodDisruptionBudget` 对象(PDB)。 +PDB 将限制在同一时间因自愿干扰导致的复制应用程序中宕机的 pod 数量。 +例如,基于票选机制的应用程序希望确保运行的副本数永远不会低于仲裁所需的数量。 +Web 前端可能希望确保提供负载的副本数量永远不会低于总数的某个百分比。 - -集群管理员和托管提供商应该使用遵循 Pod Disruption Budgets 的接口(通过调用[驱逐 API](/docs/tasks/administer-cluster/safely-drain-node/#the-eviction-api)),而不是直接删除 pod 或 deployment。示例包括 `kubectl drain` 命令和 Kubernetes-on-GCE 集群升级脚本(`cluster/gce/upgrade.sh`)。 +集群管理员和托管提供商应该使用遵循 Pod Disruption Budgets 的接口 +(通过调用[Eviction API](/zh/docs/tasks/administer-cluster/safely-drain-node/#the-eviction-api)), +而不是直接删除 Pod 或 Deployment。 - -当集群管理员想排空一个节点时,可以使用 `kubectl drain` 命令。该命令试图驱逐机器上的所有 pod。驱逐请求可能会暂时被拒绝,且该工具定时重试失败的请求直到所有的 pod 都被终止,或者达到配置的超时时间。 +例如,`kubectl drain` 命令可以用来标记某个节点即将停止服务。 +运行 `kubectl drain` 命令时,工具会尝试驱逐机器上的所有 Pod。 +`kubectl` 所提交的驱逐请求可能会暂时被拒绝,所以该工具会定时重试失败的请求, +直到所有的 Pod 都被终止,或者达到配置的超时时间。 - -PDB 指定应用程序可以容忍的副本数量(相当于应该有多少副本)。例如,具有 `.spec.replicas: 5` 的 deployment 在任何时间都应该有 5 个 pod。如果 PDB 允许其在某一时刻有 4 个副本,那么驱逐 API 将允许同一时刻仅有一个而不是两个 pod 自愿干扰。 +PDB 指定应用程序可以容忍的副本数量(相当于应该有多少副本)。 +例如,具有 `.spec.replicas: 5` 的 Deployment 在任何时间都应该有 5 个 Pod。 +如果 PDB 允许其在某一时刻有 4 个副本,那么驱逐 API 将允许同一时刻仅有一个而不是两个 Pod 自愿干扰。 - -使用标签选择器来指定构成应用程序的一组 pod,这与应用程序的控制器(deployment,stateful-set 等)选择 pod 的逻辑一样。 +使用标签选择器来指定构成应用程序的一组 Pod,这与应用程序的控制器(Deployment,StatefulSet 等) +选择 Pod 的逻辑一样。 - -Pod 控制器的 `.spec.replicas` 计算“预期的” pod 数量。根据 pod 对象的 `.metadata.ownerReferences` 字段来发现控制器。 +Pod 控制器的 `.spec.replicas` 计算“预期的” Pod 数量。 +根据 Pod 对象的 `.metadata.ownerReferences` 字段来发现控制器。 - PDB 不能阻止[非自愿干扰](#voluntary-and-involuntary-disruptions)的发生,但是确实会计入 -算。 +预算。 - -由于应用程序的滚动升级而被删除或不可用的 pod 确实会计入干扰预算,但是控制器(如 deployment 和 stateful-set)在进行滚动升级时不受 PDB -的限制。应用程序更新期间的故障处理是在控制器的 spec 中配置的。(了解[更新 deployment](/docs/concepts/workloads/controllers/deployment/#updating-a-deployment)。) +由于应用程序的滚动升级而被删除或不可用的 Pod 确实会计入干扰预算, +但是控制器(如 Deployment 和 StatefulSet)在进行滚动升级时不受 PDB +的限制。应用程序更新期间的故障处理方式是在对应的工作负载资源的 `spec` 中配置的。 - -当使用驱逐 API 驱逐 pod 时,pod 会被优雅地终止(参考 [PodSpec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core) 中的 `terminationGracePeriodSeconds`)。 +当使用驱逐 API 驱逐 Pod 时,Pod 会被体面地 +[终止](/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination),期间会 +参考 [PodSpec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core) +中的 `terminationGracePeriodSeconds` 配置值。 -## PDB 例子 - - +## PDB 例子 {#pdb-example} -假设集群有 3 个节点,`node-1` 到 `node-3`。集群上运行了一些应用。其中一个应用有 3 个副本,分别是 `pod-a`,`pod-b` 和 `pod-c`。另外,还有一个不带 PDB 的无关 pod `pod-x` 也同样显示。最初,所有的 pod 分布如下: - +假设集群有 3 个节点,`node-1` 到 `node-3`。集群上运行了一些应用。 +其中一个应用有 3 个副本,分别是 `pod-a`,`pod-b` 和 `pod-c`。 +另外,还有一个不带 PDB 的无关 pod `pod-x` 也同样显示出来。 +最初,所有的 Pod 分布如下: | node-1 | node-2 | node-3 | |:--------------------:|:-------------------:|:------------------:| @@ -308,8 +295,7 @@ Initially, the pods are laid out as follows: All 3 pods are part of a deployment, and they collectively have a PDB which requires there be at least 2 of the 3 pods to be available at all times. --> - -3 个 pod 都是 deployment 的一部分,并且共同拥有同一个 PDB,要求 3 个 pod 中至少有 2 个 pod 始终处于可用状态。 +3 个 Pod 都是 deployment 的一部分,并且共同拥有同一个 PDB,要求 3 个 Pod 中至少有 2 个 Pod 始终处于可用状态。 -例如,假设集群管理员想要重启系统,升级内核版本来修复内核中的 bug。集群管理员首先使用 `kubectl drain` 命令尝试排空 `node-1` 节点。命令尝试驱逐 `pod-a` 和 `pod-x`。操作立即就成功了。两个 pod 同时进入 `terminating` 状态。这时的集群处于下面的状态: +例如,假设集群管理员想要重启系统,升级内核版本来修复内核中的权限。 +集群管理员首先使用 `kubectl drain` 命令尝试排空 `node-1` 节点。 +命令尝试驱逐 `pod-a` 和 `pod-x`。操作立即就成功了。 +两个 Pod 同时进入 `terminating` 状态。这时的集群处于下面的状态: | node-1 *draining* | node-2 | node-3 | |:--------------------:|:-------------------:|:------------------:| @@ -331,21 +320,21 @@ The deployment notices that one of the pods is terminating, so it creates a repl called `pod-d`. Since `node-1` is cordoned, it lands on another node. Something has also created `pod-y` as a replacement for `pod-x`. --> - -Deployment 控制器观察到其中一个 pod 正在终止,因此它创建了一个替代 pod `pod-d`。由于 `node-1` 被封锁(cordon),`pod-d` 落在另一个节点上。同样其他控制器也创建了 `pod-y` 作为 `pod-x` 的替代品。 +Deployment 控制器观察到其中一个 Pod 正在终止,因此它创建了一个替代 Pod `pod-d`。 +由于 `node-1` 被封锁(cordon),`pod-d` 落在另一个节点上。 +同样其他控制器也创建了 `pod-y` 作为 `pod-x` 的替代品。 - -(注意:对于 StatefulSet 来说,`pod-a`(也称为 `pod-0`)需要在替换 pod 创建之前完全终止,替代它的也称为 `pod-0`,但是具有不同的 UID。反之,样例也适用于 StatefulSet。) +(注意:对于 StatefulSet 来说,`pod-a`(也称为 `pod-0`)需要在替换 Pod 创建之前完全终止, +替代它的也称为 `pod-0`,但是具有不同的 UID。除此之外,此示例也适用于 StatefulSet。) - 当前集群的状态如下: | node-1 *draining* | node-2 | node-3 | @@ -356,8 +345,7 @@ Now the cluster is in this state: - -在某一时刻,pod 被终止,集群如下所示: +在某一时刻,Pod 被终止,集群如下所示: | node-1 *drained* | node-2 | node-3 | |:--------------------:|:-------------------:|:------------------:| @@ -369,13 +357,13 @@ At this point, if an impatient cluster administrator tries to drain `node-2` or `node-3`, the drain command will block, because there are only 2 available pods for the deployment, and its PDB requires at least 2. After some time passes, `pod-d` becomes available. --> - -此时,如果一个急躁的集群管理员试图排空(drain)`node-2` 或 `node-3`,drain 命令将被阻塞,因为对于 deployment 来说只有 2 个可用的 pod,并且它的 PDB 至少需要 2 个。经过一段时间,`pod-d` 变得可用。 +此时,如果一个急躁的集群管理员试图排空(drain)`node-2` 或 `node-3`,drain 命令将被阻塞, +因为对于 Deployment 来说只有 2 个可用的 Pod,并且它的 PDB 至少需要 2 个。 +经过一段时间,`pod-d` 变得可用。 - 集群状态如下所示: | node-1 *drained* | node-2 | node-3 | @@ -390,8 +378,10 @@ The drain command will try to evict the two pods in some order, say But, when it tries to evict `pod-d`, it will be refused because that would leave only one pod available for the deployment. --> - -现在,集群管理员试图排空(drain)`node-2`。drain 命令将尝试按照某种顺序驱逐两个 pod,假设先是 `pod-b`,然后是 `pod-d`。命令成功驱逐 `pod-b`,但是当它尝试驱逐 `pod-d`时将被拒绝,因为对于 deployment 来说只剩一个可用的 pod 了。 +现在,集群管理员试图排空(drain)`node-2`。 +drain 命令将尝试按照某种顺序驱逐两个 Pod,假设先是 `pod-b`,然后是 `pod-d`。 +命令成功驱逐 `pod-b`,但是当它尝试驱逐 `pod-d`时将被拒绝,因为对于 +Deployment 来说只剩一个可用的 Pod 了。 - -Deployment 创建 `pod-b` 的替代 pod `pod-e`。因为集群中没有足够的资源来调度 `pod-e`,drain 命令再次阻塞。集群最终将是下面这种状态: +Deployment 创建 `pod-b` 的替代 Pod `pod-e`。 +因为集群中没有足够的资源来调度 `pod-e`,drain 命令再次阻塞。集群最终将是下面这种状态: | node-1 *drained* | node-2 | node-3 | *no node* | |:--------------------:|:-------------------:|:------------------:|:------------------:| @@ -411,14 +401,12 @@ Deployment 创建 `pod-b` 的替代 pod `pod-e`。因为集群中没有足够的 At this point, the cluster administrator needs to add a node back to the cluster to proceed with the upgrade. --> - 此时,集群管理员需要增加一个节点到集群中以继续升级操作。 - 可以看到 Kubernetes 如何改变干扰发生的速率,根据: - - 应用程序需要多少个副本 - 优雅关闭应用实例需要多长时间 - 启动应用新实例需要多长时间 @@ -437,16 +424,13 @@ can happen, according to: -## 分离集群所有者和应用所有者角色 - - +## 分离集群所有者和应用所有者角色 通常,将集群管理者和应用所有者视为彼此了解有限的独立角色是很有用的。这种责任分离在下面这些场景下是有意义的: @@ -455,7 +439,6 @@ may make sense in these scenarios: there is natural specialization of roles - when third-party tools or services are used to automate cluster management --> - - 当有许多应用程序团队共用一个 Kubernetes 集群,并且有自然的专业角色 - 当第三方工具或服务用于集群自动化管理 @@ -463,30 +446,24 @@ may make sense in these scenarios: Pod Disruption Budgets support this separation of roles by providing an interface between the roles. --> - Pod 干扰预算通过在角色之间提供接口来支持这种分离。 - 如果你的组织中没有这样的责任分离,则可能不需要使用 Pod 干扰预算。 -## 如何在集群上执行干扰操作 - - +## 如何在集群上执行干扰性操作 如果你是集群管理员,并且需要对集群中的所有节点执行干扰操作,例如节点或系统软件升级,则可以使用以下选项 - - -* 参考[配置 Pod 干扰预算](/docs/tasks/run-application/configure-pdb/)中的方法来保护你的 -用。 - - - -* 了解更多关于[排空节点](/docs/tasks/administer-cluster/safely-drain-node/)的信息。 - +* 参考[配置 Pod 干扰预算](/zh/docs/tasks/run-application/configure-pdb/)中的方法来保护你的应用。 +* 进一步了解[排空节点](/zh/docs/tasks/administer-cluster/safely-drain-node/)的信息。 +* 了解[更新 Deployment](/zh/docs/concepts/workloads/controllers/deployment/#updating-a-deployment) + 的过程,包括如何在其进程中维持应用的可用性 diff --git a/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md b/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md index 7e9a894d8d..430a1d3c55 100644 --- a/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md +++ b/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md @@ -5,14 +5,9 @@ weight: 80 --- @@ -21,12 +16,13 @@ weight: 80 - -此页面概述了临时容器:一种特殊的容器,该容器在现有 {{< glossary_tooltip term_id="pod" >}} 中临时运行,为了完成用户启动的操作,例如故障排查。使用临时容器来检查服务,而不是构建应用程序。 +本页面概述了临时容器:一种特殊的容器,该容器在现有 {{< glossary_tooltip text="Pod" term_id="pod" >}} +中临时运行,以便完成用户发起的操作,例如故障排查。 +你会使用临时容器来检查服务,而不是用它来构建应用程序。 - {{< warning >}} -临时容器处于早期的 alpha 阶段,不适用于生产环境集群。应该预料到临时容器在某些情况下不起作用,例如在定位容器的命名空间时。根据 [Kubernetes 弃用政策](/docs/reference/using-api/deprecation-policy/),该 alpha 功能将来可能发生重大变化或完全删除。 +临时容器处于早期的 alpha 阶段,不适用于生产环境集群。 +应该预料到临时容器在某些情况下不起作用,例如在定位容器的命名空间时。 +根据 [Kubernetes 弃用政策](/zh/docs/reference/using-api/deprecation-policy/), +此 alpha 功能将来可能发生重大变化或被完全删除。 {{< /warning >}} - - -## 了解临时容器 - - +## 了解临时容器 -{{< glossary_tooltip text="Pods" term_id="pod" >}} 是 Kubernetes 应用程序的基本构建块。由于 pod 是一次性且可替换的,因此一旦 Pod 创建,就无法将容器加入到 Pod 中。取而代之的是,通常使用 {{< glossary_tooltip text="deployments" term_id="deployment" >}} 以受控的方式来删除并替换 Pod。 +{{< glossary_tooltip text="Pod" term_id="pod" >}} 是 Kubernetes 应用程序的基本构建块。 +由于 Pod 是一次性且可替换的,因此一旦 Pod 创建,就无法将容器加入到 Pod 中。 +取而代之的是,通常使用 {{< glossary_tooltip text="Deployment" term_id="deployment" >}} +以受控的方式来删除并替换 Pod。 - -有时有必要检查现有 Pod 的状态,例如,对于难以复现的故障进行排查。在这些场景中,可以在现有 Pod 中运行临时容器来检查其状态并运行任意命令。 +有时有必要检查现有 Pod 的状态。例如,对于难以复现的故障进行排查。 +在这些场景中,可以在现有 Pod 中运行临时容器来检查其状态并运行任意命令。 -### 什么是临时容器? - - +### 什么是临时容器? -临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。临时容器使用与常规容器相同的 `ContainerSpec` 段进行描述,但许多字段是不相容且不允许的。 +临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启, +因此不适用于构建应用程序。 +临时容器使用与常规容器相同的 `ContainerSpec` 节来描述,但许多字段是不兼容和不允许的。 +- 临时容器没有端口配置,因此像 `ports`,`livenessProbe`,`readinessProbe` + 这样的字段是不允许的。 -- 临时容器没有端口配置,因此像 `ports`,`livenessProbe`,`readinessProbe` 这样的字段是不允许的。 - Pod 资源分配是不可变的,因此 `resources` 配置是不允许的。 -- 有关允许字段的完整列表,请参见[临时容器参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#ephemeralcontainer-v1-core)。 + +- 有关允许字段的完整列表,请参见 + [EphemeralContainer 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#ephemeralcontainer-v1-core)。 - -临时容器是使用 API 中的一种特殊的 `ephemeralcontainers` 处理器进行创建的,而不是直接添加到 `pod.spec` 段,因此无法使用 `kubectl edit` 来添加一个临时容器。 +临时容器是使用 API 中的一种特殊的 `ephemeralcontainers` 处理器进行创建的, +而不是直接添加到 `pod.spec` 段,因此无法使用 `kubectl edit` 来添加一个临时容器。 - 与常规容器一样,将临时容器添加到 Pod 后,将不能更改或删除临时容器。 -## 临时容器的用途 - - +## 临时容器的用途 -当由于容器崩溃或容器镜像不包含调试实用程序而导致 `kubectl exec` 无用时,临时容器对于交互式故障排查很有用。 +当由于容器崩溃或容器镜像不包含调试工具而导致 `kubectl exec` 无用时, +临时容器对于交互式故障排查很有用。 - -尤其是,[distroless 镜像](https://github.com/GoogleContainerTools/distroless)能够使得部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。由于 distroless 镜像不包含 shell 或任何的调试工具,因此很难单独使用 `kubectl exec` 命令进行故障排查。 +尤其是,[distroless 镜像](https://github.com/GoogleContainerTools/distroless) +允许用户部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。 +由于 distroless 镜像不包含 Shell 或任何的调试工具,因此很难单独使用 +`kubectl exec` 命令进行故障排查。 - -使用临时容器时,启用[进程命名空间共享](/docs/tasks/configure-pod-container/share-process-namespace/)很有帮助,可以查看其他容器中的进程。 +使用临时容器时,启用[进程名字空间共享](/zh/docs/tasks/configure-pod-container/share-process-namespace/) +很有帮助,可以查看其他容器中的进程。 -### 示例 - - +### 示例 {{< note >}} -本节中的示例要求启用 `EphemeralContainers` [特性](/docs/reference/command-line-tools-reference/feature-gates/),并且 kubernetes 客户端和服务端版本要求为 v1.16 或更高版本。 +本节中的示例要求启用 `EphemeralContainers` +[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/), +并且 kubernetes 客户端和服务端版本要求为 v1.16 或更高版本。 {{< /note >}} - -本节中的示例演示了临时容器如何出现在 API 中。 通常,您可以使用 `kubectl` 插件进行故障排查,从而自动化执行这些步骤。 +本节中的示例演示了临时容器如何出现在 API 中。 +通常,你可以使用 `kubectl` 插件进行故障排查,从而自动化执行这些步骤。 - -临时容器是使用 Pod 的 `ephemeralcontainers` 子资源创建的,可以使用 `kubectl --raw` 命令进行显示。首先描述临时容器被添加为一个 `EphemeralContainers` 列表: +临时容器是使用 Pod 的 `ephemeralcontainers` 子资源创建的,可以使用 +`kubectl --raw` 命令进行显示。 +首先描述临时容器被添加为一个 `EphemeralContainers` 列表: ```json { @@ -200,7 +197,6 @@ the ephemeral container to add as an `EphemeralContainers` list: - 使用如下命令更新已运行的临时容器 `example-pod`: ```shell @@ -210,7 +206,6 @@ kubectl replace --raw /api/v1/namespaces/default/pods/example-pod/ephemeralconta - 这将返回临时容器的新列表: ```json @@ -247,13 +242,14 @@ This will return the new list of ephemeral containers: - 可以使用以下命令查看新创建的临时容器的状态: ```shell kubectl describe pod example-pod ``` +输出为: + ``` ... Ephemeral Containers: @@ -277,7 +273,6 @@ Ephemeral Containers: - 可以使用以下命令连接到新的临时容器: ```shell @@ -288,22 +283,16 @@ kubectl attach -it example-pod -c debugger If process namespace sharing is enabled, you can see processes from all the containers in that Pod. For example, after attaching, you run `ps` in the debugger container: --> - 如果启用了进程命名空间共享,则可以查看该 Pod 所有容器中的进程。 例如,运行上述 `attach` 操作后,在调试器容器中运行 `ps` 操作: - - ```shell # 在 "debugger" 临时容器内中运行此 shell 命令 ps auxww ``` + 运行命令后,输出类似于: + ``` PID USER TIME COMMAND 1 root 0:00 /pause @@ -321,4 +310,3 @@ PID USER TIME COMMAND 29 root 0:00 ps auxww ``` - diff --git a/content/zh/docs/concepts/workloads/pods/init-containers.md b/content/zh/docs/concepts/workloads/pods/init-containers.md index 814891bcd0..956b0518c2 100644 --- a/content/zh/docs/concepts/workloads/pods/init-containers.md +++ b/content/zh/docs/concepts/workloads/pods/init-containers.md @@ -12,30 +12,26 @@ This page provides an overview of init containers: specialized containers that r Init containers can contain utilities or setup scripts not present in an app image. --> -本页提供了 Init 容器的概览,它是一种专用的容器,在{{< glossary_tooltip text="Pod" term_id="pod" >}}内的应用容器启动之前运行,并包括一些应用镜像中不存在的实用工具和安装脚本。 - - +本页提供了 Init 容器的概览,它是一种特殊容器,在 {{< glossary_tooltip text="Pod" term_id="pod" >}} +内的应用容器启动之前运行,可以包括一些应用镜像中不存在的实用工具和安装脚本。 -你可以在Pod的规格信息中与containers数组同级的位置指定 Init 容器。 - +你可以在 Pod 的规约中与用来描述应用容器的 `containers` 数组平行的位置指定 +Init 容器。 + - ## 理解 Init 容器 - - -{{< glossary_tooltip text="Pod" term_id="pod" >}} 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。 - +每个 {{< glossary_tooltip text="Pod" term_id="pod" >}} 中可以包含多个容器, +应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。 -如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 `restartPolicy` 值为 Never,它不会重新启动。 - +如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。 +然而,如果 Pod 对应的 `restartPolicy` 值为 Never,Kubernetes 不会重新启动 Pod。 -指定容器为 Init 容器,需要在 Pod 的 spec 中添加 `initContainers` 字段, 该字段內以[Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core) 类型对象数组的形式组织,和应用的 `containers` 数组同级相邻。 -Init 容器的状态在 `status.initContainerStatuses` 字段中以容器状态数组的格式返回(类似 `status.containerStatuses` 字段)。 - +为 Pod 设置 Init 容器需要在 Pod 的 `spec` 中添加 `initContainers` 字段, +该字段以 [Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core) +类型对象数组的形式组织,和应用的 `containers` 数组同级相邻。 +Init 容器的状态在 `status.initContainerStatuses` 字段中以容器状态数组的格式返回 +(类似 `status.containerStatuses` 字段)。 - ### 与普通容器的不同之处 -Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同,在下面 [资源](#资源) 处有说明。 +Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 +然而,Init 容器对资源请求和限制的处理稍有不同,在下面[资源](#resources)节有说明。 -同时 Init 容器不支持 `lifecycle`、`livenessProbe`、`readinessProbe` 和 `startupProbe`,因为它们必须在 Pod 就绪之前运行完成。 - -如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时,Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。 +同时 Init 容器不支持 `lifecycle`、`livenessProbe`、`readinessProbe` 和 `startupProbe`, +因为它们必须在 Pod 就绪之前运行完成。 +如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 +每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, +Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。 -## Init 容器能做什么? +## 使用 Init 容器 因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势: -* Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在安装过程中使用类似 `sed`、 `awk`、 `python` 或 `dig` 这样的工具而去`FROM` 一个镜像来生成一个新的镜像。 -* Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。 -* 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。 -* Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 {{< glossary_tooltip text="Secrets" term_id="secret" >}} 的权限,而应用容器不能够访问。 -* 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。 +* Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 + 例如,没有必要仅为了在安装过程中使用类似 `sed`、`awk`、`python` 或 `dig` + 这样的工具而去 `FROM` 一个镜像来生成一个新的镜像。 +* Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。 + +* 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。 + +* Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问 + 应用容器不能访问的 {{< glossary_tooltip text="Secret" term_id="secret" >}} 的权限。 + +* 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器 + 提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 + 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。 - -### 示例 +### 示例 {#examples} 下面是一些如何使用 Init 容器的想法: * 等待一个 Service 完成创建,通过类似如下 shell 命令: - for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1 + ```shell + for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1 + ``` * 注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下: - curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$()&ip=$()' + ```shell + curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register \ + -d 'instance=$()&ip=$()' + ``` * 在启动应用容器之前等一段时间,使用类似命令: - sleep 60 + ```shell + sleep 60 + ``` -* 克隆 Git 仓库到 {{< glossary_tooltip text="Volume" term_id="volume" >}}。 -* 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。 +* 克隆 Git 仓库到{{< glossary_tooltip text="卷" term_id="volume" >}}中。 +* 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。 + 例如,在配置文件中存放 `POD_IP` 值,并使用 Jinja 生成主应用配置文件。 -### 使用 Init 容器 +### 使用 Init 容器的情况 -下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 `myservice` 启动,第二个等待 `mydb` 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动`spec`区域中的应用容器。 +下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 `myservice` 启动, +第二个等待 `mydb` 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动 `spec` 节中的应用容器。 ```yaml apiVersion: v1 @@ -211,24 +225,26 @@ spec: targetPort: 9377 ``` - 要启动这个 Pod,可以执行如下命令: -``` +```shell kubectl apply -f myapp.yaml ``` +输出为: + ``` pod/myapp-pod created ``` - - 要检查其状态: -``` + +```shell kubectl get -f myapp.yaml ``` +输出类似于: + ``` NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 6m @@ -236,10 +252,12 @@ myapp-pod 0/1 Init:0/2 0 6m 如需更详细的信息: -``` +```shell kubectl describe -f myapp.yaml ``` +输出类似于: + ``` Name: myapp-pod Namespace: default @@ -275,11 +293,11 @@ Events: 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634 ``` -如需查看Pod内 Init 容器的日志,请执行: +如需查看 Pod 内 Init 容器的日志,请执行: -``` -$ kubectl logs myapp-pod -c init-myservice # Inspect the first init container -$ kubectl logs myapp-pod -c init-mydb # Inspect the second init container +```shell +kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器 +kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器 ``` - -在这一刻,Init 容器将会等待至发现名称为`mydb`和`myservice`的 Service。 +在这一刻,Init 容器将会等待至发现名称为 `mydb` 和 `myservice` 的 Service。 如下为创建这些 Service 的配置文件: -``` +```yaml --- apiVersion: v1 kind: Service @@ -315,75 +332,90 @@ spec: targetPort: 9377 ``` - -创建`mydb`和`myservice`的 service 命令: +创建 `mydb` 和 `myservice` 服务的命令: ```shell -$ kubectl create -f services.yaml +kubectl create -f services.yaml ``` +输出类似于: + ``` service "myservice" created service "mydb" created ``` -这样你将能看到这些 Init容器 执行完毕,随后`my-app`的Pod转移进入 Running 状态: +这样你将能看到这些 Init 容器执行完毕,随后 `my-app` 的 Pod 进入 `Running` 状态: + ```shell $ kubectl get -f myapp.yaml ``` -```shell + +``` NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 0 9m ``` -一旦我们启动了 `mydb` 和 `myservice` 这两个 Service,我们能够看到 Init 容器完成,并且 `myapp-pod` 被创建: - +一旦我们启动了 `mydb` 和 `myservice` 这两个服务,我们能够看到 Init 容器完成, +并且 `myapp-pod` 被创建。 -这个简单的例子应该能为你创建自己的 Init 容器提供一些启发。 [What's next](#what-s-next) 部分提供了更详细例子的链接。 - +这个简单例子应该能为你创建自己的 Init 容器提供一些启发。 +[接下来](#what-s-next)节提供了更详细例子的链接。 +## 具体行为 {#detailed-behavior} +在 Pod 启动过程中,每个 Init 容器在网络和数据卷初始化之后会按顺序启动。 +每个 Init 容器成功退出后才会启动下一个 Init 容器。 +如果它们因为容器运行时的原因无法启动,或以错误状态退出,它会根据 Pod 的 `restartPolicy` 策略进行重试。 +然而,如果 Pod 的 `restartPolicy` 设置为 "Always",Init 容器失败时会使用 `restartPolicy` +的 "OnFailure" 策略。 + +在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。 +Init 容器的端口将不会在 Service 中进行聚集。正在初始化中的 Pod 处于 `Pending` 状态, +但会将状况 `Initializing` 设置为 true。 + +如果 Pod [重启](#pod-restart-reasons),所有 Init 容器必须重新执行。 + + +对 Init 容器规约的修改仅限于容器的 `image` 字段。 +更改 Init 容器的 `image` 字段,等同于重启该 Pod。 +因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 +特别地,基于 `emptyDirs` 写文件的代码,应该对输出文件可能已经存在做好准备。 + +Init 容器具有应用容器的所有字段。然而 Kubernetes 禁止使用 `readinessProbe`, +因为 Init 容器不能定义不同于完成态(Completion)的就绪态(Readiness)。 +Kubernetes 会在校验时强制执行此检查。 + + +在 Pod 上使用 `activeDeadlineSeconds` 和在容器上使用 `livenessProbe` 可以避免 +Init 容器一直重复失败。`activeDeadlineSeconds` 时间包含了 Init 容器启动的时间。 -## 具体行为 - -在 Pod 启动过程中,每个Init 容器在网络和数据卷初始化之后会按顺序启动。每个 Init容器 成功退出后才会启动下一个 Init容器。 如果因为运行或退出时失败引发容器启动失败,它会根据 Pod 的 `restartPolicy` 策略进行重试。 -然而,如果 Pod 的 `restartPolicy` 设置为 Always,Init 容器失败时会使用 `restartPolicy` 的 OnFailure 策略。 - -在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。 Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 `Pending` 状态,但会将条件 `Initializing` 设置为 true。 - -如果 Pod [重启](#pod-restart-reasons),所有 Init 容器必须重新执行。 - -对 Init 容器 spec 的修改仅限于容器的 image 字段。 更改 Init 容器的 image 字段,等同于重启该 Pod。 - -因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 特别地,基于 `EmptyDirs` 写文件的代码,应该对输出文件可能已经存在做好准备。 - -Init 容器具有应用容器的所有字段。 然而 Kubernetes 禁止使用 `readinessProbe`,因为 Init 容器不能定义不同于完成(completion)的就绪(readiness)。 这一点会在校验时强制执行。 - -在 Pod 上使用 `activeDeadlineSeconds`和在容器上使用 `livenessProbe` 可以避免 Init 容器一直重复失败。 `activeDeadlineSeconds` 时间包含了 Init 容器启动的时间。 - -在 Pod 中的每个应用容器和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在校验时抛出错误。 - +在 Pod 中的每个应用容器和 Init 容器的名称必须唯一; +与任何其它容器共享同一个名称,会在校验时抛出错误。 +### 资源 {#resources} -### 资源 - -给定Init 容器的执行顺序下,资源使用适用于如下规则: +在给定的 Init 容器执行顺序下,资源使用适用于如下规则: * 所有 Init 容器上定义的任何特定资源的 limit 或 request 的最大值,作为 Pod *有效初始 request/limit* * Pod 对资源的 *有效 limit/request* 是如下两者的较大者: * 所有应用容器对某个资源的 limit/request 之和 * 对某个资源的有效初始 limit/request -* 基于有效 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源,这些资源在 Pod 生命周期过程中并没有被使用。 +* 基于有效 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源, + 这些资源在 Pod 生命周期过程中并没有被使用。 * Pod 的 *有效 QoS 层* ,与 Init 容器和应用容器的一样。 配额和限制适用于有效 Pod的 limit/request。 Pod 级别的 cgroups 是基于有效 Pod 的 limit/request,和调度器相同。 - -### Pod 重启的原因 - -Pod重启导致 Init 容器重新执行,主要有如下几个原因: - -* 用户更新 Pod 的 Spec 导致 Init 容器镜像发生改变。Init 容器镜像的变更会引起 Pod 重启. 应用容器镜像的变更仅会重启应用容器。 -* Pod 的基础设施容器 (译者注:如 pause 容器) 被重启。 这种情况不多见,必须由具备 root 权限访问 Node 的人员来完成。 -* 当 `restartPolicy` 设置为 Always,Pod 中所有容器会终止而强制重启,由于垃圾收集导致 Init 容器的完成记录丢失。 +### Pod 重启的原因 {#pod-restart-reasons} +Pod 重启会导致 Init 容器重新执行,主要有如下几个原因: +* 用户更新 Pod 的规约导致 Init 容器镜像发生改变。Init 容器镜像的变更会引起 Pod 重启。 + 应用容器镜像的变更仅会重启应用容器。 +* Pod 的基础设施容器 (译者注:如 `pause` 容器) 被重启。这种情况不多见, + 必须由具备 root 权限访问节点的人员来完成。 +* 当 `restartPolicy` 设置为 "`Always`",Pod 中所有容器会终止而强制重启。 + 由于垃圾收集机制的原因,Init 容器的完成记录将会丢失。 ## {{% heading "whatsnext" %}} - -* 阅读[创建包含 Init 容器的 Pod](/docs/tasks/configure-pod-container/configure-pod-initialization/#create-a-pod-that-has-an-init-container) -* 学习如何[调测 Init 容器](/docs/tasks/debug-application-cluster/debug-init-containers/) +* 阅读[创建包含 Init 容器的 Pod](/zh/docs/tasks/configure-pod-container/configure-pod-initialization/#create-a-pod-that-has-an-init-container) +* 学习如何[调试 Init 容器](/zh/docs/tasks/debug-application-cluster/debug-init-containers/) + diff --git a/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md index 826ca5bd78..4e7a2c5536 100644 --- a/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md +++ b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md @@ -5,13 +5,9 @@ weight: 50 --- @@ -24,20 +20,16 @@ You can use _topology spread constraints_ to control how {{< glossary_tooltip te 可以使用*拓扑扩展约束*来控制 {{< glossary_tooltip text="Pods" term_id="Pod" >}} 在集群内故障域(例如地区,区域,节点和其他用户自定义拓扑域)之间的分布。这可以帮助实现高可用以及提升资源利用率。 - - - ## 先决条件 - ### 启用功能 -确保 `EvenPodsSpread` 功能已开启(在 1.16 版本中该功能默认关闭)。阅读[功能选项](/docs/reference/command-line-tools-reference/feature-gates/)了解如何开启该功能。`EvenPodsSpread` 必须在 {{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} **和** {{< glossary_tooltip text="scheduler" term_id="kube-scheduler" >}} 中都要开启。 +确保 `EvenPodsSpread` 功能已开启(在 1.16 版本中该功能默认关闭)。 +阅读[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)了解如何开启该功能。 +`EvenPodsSpread` 必须在 {{< glossary_tooltip text="API 服务器" term_id="kube-apiserver" >}} **和** +{{< glossary_tooltip text="调度器" term_id="kube-scheduler" >}} 中都开启。 - ### 节点标签 - 拓扑扩展约束依赖于节点标签来标识每个节点所在的拓扑域。例如,一个节点可能具有标签:`node=node1,zone=us-east-1a,region=us-east-1` - 假设你拥有一个具有以下标签的 4 节点集群: ``` @@ -79,7 +71,6 @@ node4 Ready 2m43s v1.16.0 node=node4,zone=zoneB - 然后从逻辑上看集群如下: ``` @@ -93,13 +84,11 @@ Then the cluster is logically viewed as below: - -可以复用在大多数集群上自动创建和填充的[知名标签](/docs/reference/kubernetes-api/labels-annotations-taints/),而不是手动添加标签。 +可以复用在大多数集群上自动创建和填充的[常用标签](/zh/docs/reference/kubernetes-api/labels-annotations-taints/),而不是手动添加标签。 - ## Pod 的拓扑约束 ### API @@ -107,7 +96,6 @@ Instead of manually applying labels, you can also reuse the [well-known labels]( - `pod.spec.topologySpreadConstraints` 字段定义如下所示: ```yaml @@ -126,7 +114,6 @@ spec: - 可以定义一个或多个 `topologySpreadConstraint` 来指示 kube-scheduler 如何将每个传入的 Pod 根据与现有的 Pod 的关联关系在集群中部署。字段包括: - 执行 `kubectl explain Pod.spec.topologySpreadConstraints` 命令了解更多关于 topologySpreadConstraints 的信息。 -### 例子:单个拓扑扩展约束 - - +### 例子:单个拓扑扩展约束 假设你拥有一个 4 节点集群,其中标记为 `foo:bar` 的 3 个 pod 分别位于 node1,node2 和 node3 中(`P` 表示 pod): @@ -176,7 +160,6 @@ Suppose you have a 4-node cluster where 3 Pods labeled `foo:bar` are located in - 如果希望传入的 pod 均匀散布在现有的 pod 区域,则可以指定字段如下: {{< codenew file="pods/topology-spread-constraints/one-constraint.yaml" >}} @@ -184,14 +167,15 @@ If we want an incoming Pod to be evenly spread with existing Pods across zones, - -`topologyKey: zone` 意味着均匀分布将只应用于存在标签对为 "zone:<any value>" 的节点上。`whenUnsatisfiable: DoNotSchedule` 告诉调度器,如果传入的 pod 不满足约束,则让它保持挂起状态。 +`topologyKey: zone` 意味着均匀分布将只应用于存在标签对为 "zone:<any value>" 的节点上。 +`whenUnsatisfiable: DoNotSchedule` 告诉调度器,如果传入的 pod 不满足约束,则让它保持悬决状态。 - -如果调度器将传入的 pod 放入 "zoneA",pod 分布将变为 [3, 1],因此实际的倾斜为 2(3 - 1)。这违反了 `maxSkew: 1`。此示例中,传入的 pod 只能放置在 "zoneB" 上: +如果调度器将传入的 pod 放入 "zoneA",pod 分布将变为 [3, 1],因此实际的倾斜为 2(3 - 1)。 +这违反了 `maxSkew: 1`。此示例中,传入的 pod 只能放置在 "zoneB" 上: ``` +---------------+---------------+ +---------------+---------------+ @@ -206,7 +190,6 @@ If the scheduler placed this incoming Pod into "zoneA", the Pods distribution wo - 可以调整 pod 规格以满足各种要求: - - 将 `maxSkew` 更改为更大的值,比如 "2",这样传入的 pod 也可以放在 "zoneA" 上。 -- 将 `topologyKey` 更改为 "node",以便将 pod 均匀分布在节点上而不是区域中。在上面的例子中,如果 `maxSkew` 保持为 "1",那么传入的 pod 只能放在 "node4" 上。 -- 将 `whenUnsatisfiable: DoNotSchedule` 更改为 `whenUnsatisfiable: ScheduleAnyway`,以确保传入的 pod 始终可以调度(假设满足其他的调度 API)。但是,最好将其放置在具有较少匹配 pod 的拓扑域中。(请注意,此优先性与其他内部调度优先级(如资源使用率等)一起进行标准化。) +- 将 `topologyKey` 更改为 "node",以便将 pod 均匀分布在节点上而不是区域中。 + 在上面的例子中,如果 `maxSkew` 保持为 "1",那么传入的 pod 只能放在 "node4" 上。 +- 将 `whenUnsatisfiable: DoNotSchedule` 更改为 `whenUnsatisfiable: ScheduleAnyway`, + 以确保传入的 Pod 始终可以调度(假设满足其他的调度 API)。 + 但是,最好将其放置在具有较少匹配 Pod 的拓扑域中。 + (请注意,此优先性与其他内部调度优先级(如资源使用率等)一起进行标准化。) - ### 例子:多个拓扑扩展约束 -下面的例子建立在前面例子的基础上。假设你拥有一个 4 节点集群,其中 3 个标记为 `foo:bar` 的 pod 分别位于 node1,node2 和 node3 上(`P` 表示 pod): +下面的例子建立在前面例子的基础上。假设你拥有一个 4 节点集群,其中 3 个标记为 `foo:bar` 的 +Pod 分别位于 node1,node2 和 node3 上(`P` 表示 Pod): ``` +---------------+---------------+ @@ -244,7 +230,6 @@ This builds upon the previous example. Suppose you have a 4-node cluster where 3 - 可以使用 2 个拓扑扩展约束来控制 pod 在 区域和节点两个维度上进行分布: {{< codenew file="pods/topology-spread-constraints/two-constraints.yaml" >}} @@ -252,13 +237,12 @@ You can use 2 TopologySpreadConstraints to control the Pods spreading on both zo - -在这种情况下,为了匹配第一个约束,传入的 pod 只能放置在 "zoneB" 中;而在第二个约束中,传入的 pod 只能放置在 "node4" 上。然后两个约束的结果加在一起,因此唯一可行的选择是放置在 "node4" 上。 +在这种情况下,为了匹配第一个约束,传入的 pod 只能放置在 "zoneB" 中;而在第二个约束中, +传入的 Pod 只能放置在 "node4" 上。然后两个约束的结果加在一起,因此唯一可行的选择是放置在 "node4" 上。 - 多个约束可能导致冲突。假设有一个跨越 2 个区域的 3 节点集群: ``` @@ -274,58 +258,53 @@ Multiple constraints can lead to conflicts. Suppose you have a 3-node cluster ac - -如果对集群应用 "two-constraints.yaml",会发现 "mypod" 处于 `Pending` 状态。这是因为:为了满足第一个约束,"mypod" 只能放在 "zoneB" 中,而第二个约束要求 "mypod" 只能放在 "node2" 上。pod 调度无法满足两种约束。 +如果对集群应用 "two-constraints.yaml",会发现 "mypod" 处于 `Pending` 状态。 +这是因为:为了满足第一个约束,"mypod" 只能放在 "zoneB" 中,而第二个约束要求 +"mypod" 只能放在 "node2" 上。pod 调度无法满足两种约束。 - -为了克服这种情况,可以增加 `maxSkew` 或修改其中一个约束,让其使用 `whenUnsatisfiable: ScheduleAnyway`。 +为了克服这种情况,可以增加 `maxSkew` 或修改其中一个约束,让其使用 +`whenUnsatisfiable: ScheduleAnyway`。 -### 约定 - - +### 约定 这里有一些值得注意的隐式约定: - -- 只有与传入 pod 具有相同命名空间的 pod 才能作为匹配候选者。 - - - +- 只有与传入 pod 具有相同命名空间的 pod 才能作为匹配候选者。 - 没有 `topologySpreadConstraints[*].topologyKey` 的节点将被忽略。这意味着: - 1. 位于这些节点上的 pod 不影响 `maxSkew` 的计算。在上面的例子中,假设 "node1" 没有标签 "zone",那么 2 个 pod 将被忽略,因此传入的 pod 将被调度到 "zoneA" 中。 - 2. 传入的 pod 没有机会被调度到这类节点上。在上面的例子中,假设一个带有标签 `{zone-typo: zoneC}` 的 "node5" 加入到集群,它将由于没有标签键 "zone" 而被忽略。 + 1. 位于这些节点上的 pod 不影响 `maxSkew` 的计算。 + 在上面的例子中,假设 "node1" 没有标签 "zone",那么 2 个 Pod 将被忽略, + 因此传入的 Pod 将被调度到 "zoneA" 中。 + 2. 传入的 Pod 没有机会被调度到这类节点上。 + 在上面的例子中,假设一个带有标签 `{zone-typo: zoneC}` 的 "node5" 加入到集群, + 它将由于没有标签键 "zone" 而被忽略。 - -注意,如果传入 pod 的 `topologySpreadConstraints[*].labelSelector` 与自身的标签不匹配,将会发生什么。在上面的例子中,如果移除传入 pod 的标签,pod 仍然可以调度到 "zoneB",因为约束仍然满足。然而,在调度之后,集群的不平衡程度保持不变。zoneA 仍然有 2 个带有 {foo:bar} 标签的 pod,zoneB 有 1 个带有 {foo:bar} 标签的 pod。因此,如果这不是你所期望的,建议工作负载的 `topologySpreadConstraints[*].labelSelector` 与其自身的标签匹配。 +注意,如果传入 Pod 的 `topologySpreadConstraints[*].labelSelector` 与自身的标签不匹配,将会发生什么。 +在上面的例子中,如果移除传入 Pod 的标签,Pod 仍然可以调度到 "zoneB",因为约束仍然满足。 +然而,在调度之后,集群的不平衡程度保持不变。zoneA 仍然有 2 个带有 {foo:bar} 标签的 Pod, +zoneB 有 1 个带有 {foo:bar} 标签的 Pod。 +因此,如果这不是你所期望的,建议工作负载的 `topologySpreadConstraints[*].labelSelector` +与其自身的标签匹配。 - - - - @@ -349,14 +328,11 @@ There are some implicit conventions worth noting here: -## 与 PodAffinity/PodAntiAffinity 相比较 - - +## 与 PodAffinity/PodAntiAffinity 相比较 在 Kubernetes 中,与 "Affinity" 相关的指令控制 pod 的调度方式(更密集或更分散)。 @@ -366,7 +342,6 @@ topology domain(s) - For `PodAntiAffinity`, only one Pod can be scheduled into a single topology domain. --> - - 对于 `PodAffinity`,可以尝试将任意数量的 pod 打包到符合条件的拓扑域中。 - 对于 `PodAntiAffinity`,只能将一个 pod 调度到单个拓扑域中。 @@ -376,26 +351,24 @@ topology domains - to achieve high availability or cost-saving. This can also he workloads and scaling out replicas smoothly. See [Motivation](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-pod-topology-spread.md#motivation) for more details. --> - -"EvenPodsSpread" 功能提供灵活的选项来将 pod 均匀分布到不同的拓扑域中,以实现高可用性或节省成本。这也有助于滚动更新工作负载和平滑扩展副本。有关详细信息,请参考[动机](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-pod-topology-spread.md#motivation)。 +"EvenPodsSpread" 功能提供灵活的选项来将 pod 均匀分布到不同的拓扑域中,以实现高可用性或节省成本。 +这也有助于滚动更新工作负载和平滑扩展副本。 +有关详细信息,请参考[动机](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-pod-topology-spread.md#motivation)。 ## 已知局限性 - - 1.16 版本(此功能为 alpha)存在下面的一些限制: - - `Deployment` 的缩容可能导致 pod 分布不平衡。 - pod 匹配到污点节点是允许的。参考 [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)。 diff --git a/content/zh/docs/concepts/workloads/pods/podpreset.md b/content/zh/docs/concepts/workloads/pods/podpreset.md index 69b052b868..f4e0f85675 100644 --- a/content/zh/docs/concepts/workloads/pods/podpreset.md +++ b/content/zh/docs/concepts/workloads/pods/podpreset.md @@ -5,13 +5,9 @@ weight: 50 --- -本文提供了 PodPreset 的概述。 在 Pod 创建时,用户可以使用 PodPreset 对象将特定信息注入 Pod 中,这些信息可以包括 secret、 卷、卷挂载和环境变量。 +{{< feature-state for_k8s_version="v1.6" state="alpha" >}} +本文提供了 PodPreset 的概述。 在 Pod 创建时,用户可以使用 PodPreset 对象将特定信息注入 Pod 中,这些信息可以包括 Secret、卷、卷挂载和环境变量。 @@ -38,7 +35,8 @@ You use [label selectors](/docs/concepts/overview/working-with-objects/labels/#l to specify the Pods to which a given Pod Preset applies. --> `Pod Preset` 是一种 API 资源,在 Pod 创建时,用户可以用它将额外的运行时需求信息注入 Pod。 -使用[标签选择器(label selector)](/docs/concepts/overview/working-with-objects/labels/#label-selectors)来指定 Pod Preset 所适用的 Pod。 +使用[标签选择算符](/zh/docs/concepts/overview/working-with-objects/labels/#label-selectors) +来指定 Pod Preset 所适用的 Pod。 +## Enable PodPreset in your cluster {#enable-pod-preset} -了解更多的相关背景信息,请参考 [ PodPreset 设计提案](https://git.k8s.io/community/contributors/design-proposals/service-catalog/pod-preset.md)。 +In order to use Pod Presets in your cluster you must ensure the following: +--> +## 在你的集群中启用 Pod Preset {#enable-pod-preset} + +为了在集群中使用 Pod Preset,必须确保以下几点: + + +1. 已启用 API 类型 `settings.k8s.io/v1alpha1/podpreset`。 例如,这可以通过在 API 服务器的 `--runtime-config` + 配置项中包含 `settings.k8s.io/v1alpha1=true` 来实现。 + 在 minikube 部署的集群中,启动集群时添加此参数 `--extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true`。 +1. 已启用准入控制器 `PodPreset`。 启用的一种方式是在 API 服务器的 `--enable-admission-plugins` + 配置项中包含 `PodPreset` 。在 minikube 部署的集群中,启动集群时添加以下参数: + + ```shell + --extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodPreset + ``` - ## PodPreset 如何工作 Kubernetes 提供了准入控制器 (`PodPreset`),该控制器被启用时,会将 Pod Preset @@ -87,7 +113,7 @@ Kubernetes 提供了准入控制器 (`PodPreset`),该控制器被启用时, 1. 尝试合并 `PodPreset` 中定义的各种资源,并注入要创建的 Pod。 1. 发生错误时抛出事件,该事件记录了 pod 信息合并错误,同时在 _不注入_ `PodPreset` 信息的情况下创建 Pod。 1. 为改动的 Pod spec 添加注解,来表明它被 `PodPreset` 所修改。 注解形如: -`podpreset.admission.kubernetes.io/podpreset-": ""`。 + `podpreset.admission.kubernetes.io/podpreset-": "<资源版本>"`。 {{< note >}} 适当时候,Pod Preset 可以修改 Pod 规范中的以下字段: - `.spec.containers` 字段 -- `initContainers` 字段 (需要 Kubernetes 1.14.0 或更高版本)。 +- `initContainers` 字段 {{< /note >}} -### 为特定 Pod 禁用 Pod Preset - -在一些情况下,用户不希望 Pod 被 Pod Preset 所改动,这时,用户可以在 Pod spec 中添加形如 `podpreset.admission.kubernetes.io/exclude: "true"` 的注解。 - - -## 启用 Pod Preset - - -为了在集群中使用 Pod Preset,必须确保以下几点: - - - -1. 已启用 API 类型 `settings.k8s.io/v1alpha1/podpreset`。 例如,这可以通过在 API 服务器的 `--runtime-config` 配置项中包含 `settings.k8s.io/v1alpha1=true` 来实现。在 minikube 部署的集群中,启动集群时添加此参数 `--extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true`。 -1. 已启用准入控制器 `PodPreset`。 启用的一种方式是在 API 服务器的 `--enable-admission-plugins` 配置项中包含 `PodPreset` 。在 minikube 部署的集群中,启动集群时添加以下参数: - - ```shell - --extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodPreset - ``` - -1. 已经通过在相应的命名空间中创建 `PodPreset` 对象,定义了 Pod Preset。 - - +### 为特定 Pod 禁用 Pod Preset +在一些情况下,用户不希望 Pod 被 Pod Preset 所改动,这时,用户可以在 Pod +的 `.spec` 中添加形如 `podpreset.admission.kubernetes.io/exclude: "true"` 的注解。 ## {{% heading "whatsnext" %}} -* [使用 PodPreset 将信息注入 Pod](/docs/tasks/inject-data-application/podpreset/) - +* 参考[使用 PodPreset 将信息注入 Pod](/zh/docs/tasks/inject-data-application/podpreset/)。 +* 若要更多地了解背景知识,请参阅 [PodPreset 的设计提案](https://git.k8s.io/community/contributors/design-proposals/service-catalog/pod-preset.md)。