Switch language name 'zh' to 'zh-cn'

This is the first step to rename 'zh' to 'zh-cn'. There are several reasons why we rename the language name.

- The upstream docsy theme changed the language name, leading to many warnings during site build;
  The side-effect is that the i18n strings are no longer working.
- We believe renaming the language is the right thing to do, because this move can make room for other variants of Chinese language, such as 'zh-tw', 'zh-sg' etc.

There would be several follow-ups to this PR, such as fixing the intra-site links, adding redirects etc.

We will lock up changes to zh/zh-cn pages for the moment, until this one gets in.

This PR is based on commit cdad0a7342.
This commit is contained in:
Qiming Teng
2022-06-10 20:25:27 +08:00
parent 3d345b1816
commit c52818c03d
1347 changed files with 8 additions and 6 deletions
@@ -0,0 +1,644 @@
---
title: Pods
content_type: concept
weight: 10
no_list: true
card:
name: concepts
weight: 60
---
<!--
reviewers:
- erictune
title: Pods
content_type: concept
weight: 10
no_list: true
card:
name: concepts
weight: 60
-->
<!-- overview -->
<!--
_Pods_ are the smallest deployable units of computing that you can create and manage in Kubernetes.
A _Pod_ (as in a pod of whales or pea pod) is a group of one or more
{{< glossary_tooltip text="containers" term_id="container" >}}
with shared storage and network resources, and a specification
for how to run the containers. A Pod's contents are always co-located and
co-scheduled, and run in a shared context. A Pod models an
application-specific "logical host": it contains one or more application
containers which are relatively tightly coupled.
In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host.
-->
_Pod_ 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
_Pod_ (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个)
{{< glossary_tooltip text="容器" term_id="container" >}}
这些容器共享存储、网络、以及怎样运行这些容器的声明。
Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。
Pod 所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器,
这些容器是相对紧密的耦合在一起的。
在非云环境中,在相同的物理机或虚拟机上运行的应用类似于
在同一逻辑主机上运行的云应用。
<!--
As well as application containers, a Pod can contain
[init containers](/docs/concepts/workloads/pods/init-containers/) that run
during Pod startup. You can also inject
[ephemeral containers](/docs/concepts/workloads/pods/ephemeral-containers/)
for debugging if your cluster offers this.
-->
除了应用容器,Pod 还可以包含在 Pod 启动期间运行的
[Init 容器](/zh/docs/concepts/workloads/pods/init-containers/)。
你也可以在集群中支持[临时性容器](/zh/docs/concepts/workloads/pods/ephemeral-containers/)
的情况下,为调试的目的注入临时性容器。
<!-- body -->
## 什么是 Pod {#what-is-a-pod}
<!--
While Kubernetes supports more
{{< glossary_tooltip text="container runtimes" term_id="container-runtime" >}}
than just Docker, [Docker](https://www.docker.com/) is the most commonly known
runtime, and it helps to describe Pods using some terminology from Docker.
-->
{{< note >}}
除了 Docker 之外,Kubernetes 支持
很多其他{{< glossary_tooltip text="容器运行时" term_id="container-runtime" >}}
[Docker](https://www.docker.com/) 是最有名的运行时,
使用 Docker 的术语来描述 Pod 会很有帮助。
{{< /note >}}
<!--
The shared context of a Pod is a set of Linux namespaces, cgroups, and
potentially other facets of isolation - the same things that isolate a Docker
container. Within a Pod's context, the individual applications may have
further sub-isolations applied.
In terms of Docker concepts, a Pod is similar to a group of Docker containers
with shared namespaces and shared filesystem volumes.
-->
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离
方面,即用来隔离 Docker 容器的技术。
在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。
就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker
容器。
<!--
## Using Pods
The following is an example of a Pod which consists of a container running the image `nginx:1.14.2`.
{{< codenew file="pods/simple-pod.yaml" >}}
To create the Pod shown above, run the following command:
-->
## 使用 Pod {#using-pods}
下面是一个 Pod 示例,它由一个运行镜像 `nginx:1.14.2` 的容器组成。
{{< codenew file="pods/simple-pod.yaml" >}}
要创建上面显示的 Pod,请运行以下命令:
```shell
kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml
```
<!--
Pods are generally not created directly and are created using workload resources.
See [Working with Pods](#working-with-pods) for more information on how Pods are used
with workload resources.
### Workload resources for managing pods
-->
Pod 通常不是直接创建的,而是使用工作负载资源创建的。
有关如何将 Pod 用于工作负载资源的更多信息,请参阅 [使用 Pod](#working-with-pods)。
### 用于管理 pod 的工作负载资源
<!--
Usually you don't need to create Pods directly, even singleton Pods.
Instead, create them using workload resources such as {{< glossary_tooltip text="Deployment"
term_id="deployment" >}} or {{< glossary_tooltip text="Job" term_id="job" >}}.
If your Pods need to track state, consider the
{{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}} resource.
Pods in a Kubernetes cluster are used in two main ways:
-->
通常你不需要直接创建 Pod,甚至单实例 Pod。
相反,你会使用诸如
{{< glossary_tooltip text="Deployment" term_id="deployment" >}} 或
{{< glossary_tooltip text="Job" term_id="job" >}} 这类工作负载资源
来创建 Pod。如果 Pod 需要跟踪状态,
可以考虑 {{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}}
资源。
Kubernetes 集群中的 Pod 主要有两种用法:
<!--
* **Pods that run a single container**. The "one-container-per-Pod" model is the
most common Kubernetes use case; in this case, you can think of a Pod as a
wrapper around a single container; Kubernetes manages Pods rather than managing
the containers directly.
* **Pods that run multiple containers that need to work together**. A Pod can
encapsulate an application composed of multiple co-located containers that are
tightly coupled and need to share resources. These co-located containers
form a single cohesive unit of service—for example, one container serving data
stored in a shared volume to the public, while a separate _sidecar_ container
refreshes or updates those files.
The Pod wraps these containers, storage resources, and an ephemeral network
identity together as a single unit.
Grouping multiple co-located and co-managed containers in a single Pod is a
relatively advanced use case. You should use this pattern only in specific
instances in which your containers are tightly coupled.
-->
* **运行单个容器的 Pod**。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例;
在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
* **运行多个协同工作的容器的 Pod**。
Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。
这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众,
而另一个单独的“边车”(sidecar)容器则刷新或更新这些文件。
Pod 将这些容器和存储资源打包为一个可管理的实体。
{{< note >}}
将多个并置、同管的容器组织到一个 Pod 中是一种相对高级的使用场景。
只有在一些场景中,容器之间紧密关联时你才应该使用这种模式。
{{< /note >}}
<!--
Each Pod is meant to run a single instance of a given application. If you want to
scale your application horizontally (to provide more overall resources by running
more instances), you should use multiple Pods, one for each instance. In
Kubernetes, this is typically referred to as _replication_.
Replicated Pods are usually created and managed as a group by a workload resource
and its {{< glossary_tooltip text="controller" term_id="controller" >}}.
See [Pods and controllers](#pods-and-controllers) for more information on how
Kubernetes uses workload resources, and their controllers, to implement application
scaling and auto-healing.
-->
每个 Pod 都旨在运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例
以提供更多的资源),则应该使用多个 Pod,每个实例使用一个 Pod。
在 Kubernetes 中,这通常被称为 _副本(Replication_
通常使用一种工作负载资源及其{{< glossary_tooltip text="控制器" term_id="controller" >}}
来创建和管理一组 Pod 副本。
参见 [Pod 和控制器](#pods-and-controllers)以了解 Kubernetes
如何使用工作负载资源及其控制器以实现应用的扩缩和自动修复。
<!--
### How Pods manage multiple containers
Pods are designed to support multiple cooperating processes (as containers) that form
a cohesive unit of service. The containers in a Pod are automatically co-located and
co-scheduled on the same physical or virtual machine in the cluster. The containers
can share resources and dependencies, communicate with one another, and coordinate
when and how they are terminated.
-->
### Pod 怎样管理多个容器
Pod 被设计成支持形成内聚服务单元的多个协作过程(形式为容器)。
Pod 中的容器被自动安排到集群中的同一物理机或虚拟机上,并可以一起进行调度。
容器之间可以共享资源和依赖、彼此通信、协调何时以及何种方式终止自身。
<!--
For example, you might have a container that
acts as a web server for files in a shared volume, and a separate "sidecar" container
that updates those files from a remote source, as in the following diagram:
-->
例如,你可能有一个容器,为共享卷中的文件提供 Web 服务器支持,以及一个单独的
"边车 (sidercar)" 容器负责从远端更新这些文件,如下图所示:
{{< figure src="/images/docs/pod.svg" alt="Pod creation diagram" class="diagram-medium" >}}
<!--
Some Pods have {{< glossary_tooltip text="init containers" term_id="init-container" >}}
as well as {{< glossary_tooltip text="app containers" term_id="app-container" >}}.
Init containers run and complete before the app containers are started.
Pods natively provide two kinds of shared resources for their constituent containers:
[networking](#pod-networking) and [storage](#pod-storage).
-->
有些 Pod 具有 {{< glossary_tooltip text="Init 容器" term_id="init-container" >}} 和
{{< glossary_tooltip text="应用容器" term_id="app-container" >}}。
Init 容器会在启动应用容器之前运行并完成。
Pod 天生地为其成员容器提供了两种共享资源:[网络](#pod-networking)和
[存储](#pod-storage)。
<!--
## Working with Pods
You'll rarely create individual Pods directly in Kubernetes—even singleton Pods. This
is because Pods are designed as relatively ephemeral, disposable entities. When
a Pod gets created (directly by you, or indirectly by a
{{< glossary_tooltip text="controller" term_id="controller" >}}), the new Pod is
scheduled to run on a {{< glossary_tooltip term_id="node" >}} in your cluster.
The Pod remains on that node until the Pod finishes execution, the Pod object is deleted,
the Pod is *evicted* for lack of resources, or the node fails.
-->
## 使用 Pod {#working-with-pods}
你很少在 Kubernetes 中直接创建一个个的 Pod,甚至是单实例(Singleton)的 Pod。
这是因为 Pod 被设计成了相对临时性的、用后即抛的一次性实体。
当 Pod 由你或者间接地由 {{< glossary_tooltip text="控制器" term_id="controller" >}}
创建时,它被调度在集群中的{{< glossary_tooltip text="节点" term_id="node" >}}上运行。
Pod 会保持在该节点上运行,直到 Pod 结束执行、Pod 对象被删除、Pod 因资源不足而被
*驱逐* 或者节点失效为止。
<!--
Restarting a container in a Pod should not be confused with restarting a Pod. A Pod
is not a process, but an environment for running container(s). A Pod persists until
it is deleted.
-->
{{< note >}}
重启 Pod 中的容器不应与重启 Pod 混淆。
Pod 不是进程,而是容器运行的环境。
在被删除之前,Pod 会一直存在。
{{< /note >}}
<!--
When you create the manifest for a Pod object, make sure the name specified is a valid
[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names).
-->
当你为 Pod 对象创建清单时,要确保所指定的 Pod 名称是合法的
[DNS 子域名](/zh/docs/concepts/overview/working-with-objects/names#dns-subdomain-names)。
<!--
### Pods and controllers
You can use workload resources to create and manage multiple Pods for you. A controller
for the resource handles replication and rollout and automatic healing in case of
Pod failure. For example, if a Node fails, a controller notices that Pods on that
Node have stopped working and creates a replacement Pod. The scheduler places the
replacement Pod onto a healthy Node.
Here are some examples of workload resources that manage one or more Pods:
-->
### Pod 和控制器 {#pods-and-controllers}
你可以使用工作负载资源来创建和管理多个 Pod。
资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。
例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作,
就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。
下面是一些管理一个或者多个 Pod 的工作负载资源的示例:
* {{< glossary_tooltip text="Deployment" term_id="deployment" >}}
* {{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}}
* {{< glossary_tooltip text="DaemonSet" term_id="daemonset" >}}
<!--
### Pod templates
Controllers for {{< glossary_tooltip text="workload" term_id="workload" >}} resources create Pods
from a _pod template_ and manage those Pods on your behalf.
PodTemplates are specifications for creating Pods, and are included in workload resources such as
[Deployments](/docs/concepts/workloads/controllers/deployment/),
[Jobs](/docs/concepts/workloads/controllers/job/), and
[DaemonSets](/docs/concepts/workloads/controllers/daemonset/).
-->
### Pod 模版 {#pod-templates}
{{< glossary_tooltip text="负载" term_id="workload" >}}资源的控制器通常使用
_Pod 模板(Pod Template_ 来替你创建 Pod 并管理它们。
Pod 模板是包含在工作负载对象中的规范,用来创建 Pod。这类负载资源包括
[Deployment](/zh/docs/concepts/workloads/controllers/deployment/)、
[Job](/zh/docs/concepts/workloads/controllers/job/) 和
[DaemonSets](/zh/docs/concepts/workloads/controllers/daemonset/) 等。
<!--
Each controller for a workload resource uses the `PodTemplate` inside the workload
object to make actual Pods. The `PodTemplate` is part of the desired state of whatever
workload resource you used to run your app.
The sample below is a manifest for a simple Job with a `template` that starts one
container. The container in that Pod prints a message then pauses.
-->
工作负载的控制器会使用负载对象中的 `PodTemplate` 来生成实际的 Pod。
`PodTemplate` 是你用来运行应用时指定的负载资源的目标状态的一部分。
下面的示例是一个简单的 Job 的清单,其中的 `template` 指示启动一个容器。
该 Pod 中的容器会打印一条消息之后暂停。
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
# 这里是 Pod 模版
spec:
containers:
- name: hello
image: busybox:1.28
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# 以上为 Pod 模版
```
<!--
Modifying the pod template or switching to a new pod template has no effect on the
Pods that already exist. Pods do not receive template updates directly. Instead,
a new Pod is created to match the revised pod template.
For example, the deployment controller ensures that the running Pods match the current
pod template for each Deployment object. If the template is updated, the Deployment has
to remove the existing Pods and create new Pods based on the updated template. Each workload
resource implements its own rules for handling changes to the Pod template.
-->
修改 Pod 模版或者切换到新的 Pod 模版都不会对已经存在的 Pod 起作用。
Pod 不会直接收到模版的更新。相反,
新的 Pod 会被创建出来,与更改后的 Pod 模版匹配。
例如,Deployment 控制器针对每个 Deployment 对象确保运行中的 Pod 与当前的 Pod
模版匹配。如果模版被更新,则 Deployment 必须删除现有的 Pod,基于更新后的模版
创建新的 Pod。每个工作负载资源都实现了自己的规则,用来处理对 Pod 模版的更新。
<!--
On Nodes, the {{< glossary_tooltip term_id="kubelet" text="kubelet" >}} does not
directly observe or manage any of the details around pod templates and updates; those
details are abstracted away. That abstraction and separation of concerns simplifies
system semantics, and makes it feasible to extend the cluster's behavior without
changing existing code.
-->
在节点上,{{< glossary_tooltip term_id="kubelet" text="kubelet" >}} 并不直接监测
或管理与 Pod 模版相关的细节或模版的更新,这些细节都被抽象出来。
这种抽象和关注点分离简化了整个系统的语义,并且使得用户可以在不改变现有代码的
前提下就能扩展集群的行为。
<!--
## Pod update and replacement
As mentioned in the previous section, when the Pod template for a workload
resource is changed, the controller creates new Pods based on the updated
template instead of updating or patching the existing Pods.
-->
## Pod 更新与替换 {#pod-update-and-replacement}
正如前面章节所述,当某工作负载的 Pod 模板被改变时,控制器会基于更新的模板
创建新的 Pod 对象而不是对现有 Pod 执行更新或者修补操作。
<!--
Kubernetes doesn't prevent you from managing Pods directly. It is possible to
update some fields of a running Pod, in place. However, Pod update operations
like
[`patch`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#patch-pod-v1-core), and
[`replace`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#replace-pod-v1-core)
have some limitations:
-->
Kubernetes 并不禁止你直接管理 Pod。对运行中的 Pod 的某些字段执行就地更新操作
还是可能的。不过,类似
[`patch`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#patch-pod-v1-core) 和
[`replace`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#replace-pod-v1-core)
这类更新操作有一些限制:
<!--
- Most of the metadata about a Pod is immutable. For example, you cannot
change the `namespace`, `name`, `uid`, or `creationTimestamp` fields;
the `generation` field is unique. It only accepts updates that increment the
field's current value.
- If the `metadata.deletionTimestamp` is set, no new entry can be added to the
`metadata.finalizers` list.
- Pod updates may not change fields other than `spec.containers[*].image`,
`spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or
`spec.tolerations`. For `spec.tolerations`, you can only add new entries.
- When updating the `spec.activeDeadlineSeconds` field, two types of updates
are allowed:
1. setting the unassigned field to a positive number;
1. updating the field from a positive number to a smaller, non-negative
number.
-->
- Pod 的绝大多数元数据都是不可变的。例如,你不可以改变其 `namespace``name`
`uid` 或者 `creationTimestamp` 字段;`generation` 字段是比较特别的,如果更新
该字段,只能增加字段取值而不能减少。
- 如果 `metadata.deletionTimestamp` 已经被设置,则不可以向 `metadata.finalizers`
列表中添加新的条目。
- Pod 更新不可以改变除 `spec.containers[*].image``spec.initContainers[*].image`
`spec.activeDeadlineSeconds``spec.tolerations` 之外的字段。
对于 `spec.tolerations`,你只被允许添加新的条目到其中。
- 在更新`spec.activeDeadlineSeconds` 字段时,以下两种更新操作是被允许的:
1. 如果该字段尚未设置,可以将其设置为一个正数;
1. 如果该字段已经设置为一个正数,可以将其设置为一个更小的、非负的整数。
<!--
## Resource sharing and communication
Pods enable data sharing and communication among their constituent
containters.
-->
### 资源共享和通信 {#resource-sharing-and-communication}
Pod 使它的成员容器间能够进行数据共享和通信。
<!--
### Storage in Pods {#pod-storage}
A Pod can specify a set of shared storage
{{< glossary_tooltip text="volumes" term_id="volume" >}}. All containers
in the Pod can access the shared volumes, allowing those containers to
share data. Volumes also allow persistent data in a Pod to survive
in case one of the containers within needs to be restarted. See
[Storage](/docs/concepts/storage/) for more information on how
Kubernetes implements shared storage and makes it available to Pods.
-->
### Pod 中的存储 {#pod-storage}
一个 Pod 可以设置一组共享的存储{{< glossary_tooltip text="卷" term_id="volume" >}}。
Pod 中的所有容器都可以访问该共享卷,从而允许这些容器共享数据。
卷还允许 Pod 中的持久数据保留下来,即使其中的容器需要重新启动。
有关 Kubernetes 如何在 Pod 中实现共享存储并将其提供给 Pod 的更多信息,
请参考[](/zh/docs/concepts/storage/)。
<!--
### Pod networking
Each Pod is assigned a unique IP address for each address family. Every
container in a Pod shares the network namespace, including the IP address and
network ports. Inside a Pod (and **only** then), the containers that belong to the Pod
can communicate with one another using `localhost`. When containers in a Pod communicate
with entities *outside the Pod*,
they must coordinate how they use the shared network resources (such as ports).
-->
### Pod 联网 {#pod-networking}
每个 Pod 都在每个地址族中获得一个唯一的 IP 地址。
Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口。
*Pod 内* 的容器可以使用 `localhost` 互相通信。
当 Pod 中的容器与 *Pod 之外* 的实体通信时,它们必须协调如何使用共享的网络资源
(例如端口)。
<!--
Within a Pod, containers share an IP address and port space, and
can find each other via `localhost`. The containers in a Pod can also communicate
with each other using standard inter-process communications like SystemV semaphores
or POSIX shared memory. Containers in different Pods have distinct IP addresses
and can not communicate by IPC without
and can not communicate by OS-level IPC without special configuration.
Containers that want to interact with a container running in a different Pod can
use IP networking to communicate.
-->
在同一个 Pod 内,所有容器共享一个 IP 地址和端口空间,并且可以通过 `localhost` 发现对方。
他们也能通过如 SystemV 信号量或 POSIX 共享内存这类标准的进程间通信方式互相通信。
不同 Pod 中的容器的 IP 地址互不相同,没有特殊配置,无法通过 OS 级 IPC 进行通信就不能使用 IPC 进行通信。
如果某容器希望与运行于其他 Pod 中的容器通信,可以通过 IP 联网的方式实现。
<!--
Containers within the Pod see the system hostname as being the same as the configured
`name` for the Pod. There's more about this in the [networking](/docs/concepts/cluster-administration/networking/)
section.
-->
Pod 中的容器所看到的系统主机名与为 Pod 配置的 `name` 属性值相同。
[网络](/zh/docs/concepts/cluster-administration/networking/)部分提供了更多有关此内容的信息。
<!--
## Privileged mode for containers
In Linux, any container in a Pod can enable privileged mode using the `privileged` (Linux) flag on the [security context](/docs/tasks/configure-pod-container/security-context/) of the container spec. This is useful for containers that want to use operating system administrative capabilities such as manipulating the network stack or accessing hardware devices.
If your cluster has the `WindowsHostProcessContainers` feature enabled, you can create a [Windows HostProcess pod](/docs/tasks/configure-pod-container/create-hostprocess-pod) by setting the `windowsOptions.hostProcess` flag on the security context of the pod spec. All containers in these pods must run as Windows HostProcess containers. HostProcess pods run directly on the host and can also be used to perform administrative tasks as is done with Linux privileged containers.
-->
## 容器的特权模式 {#privileged-mode-for-containers}
在 Linux 中,Pod 中的任何容器都可以使用容器规约中的
[安全性上下文](/zh/docs/tasks/configure-pod-container/security-context/)中的
`privileged`Linux)参数启用特权模式。
这对于想要使用操作系统管理权能(Capabilities,如操纵网络堆栈和访问设备)
的容器很有用。
如果你的集群启用了 `WindowsHostProcessContainers` 特性,你可以使用 Pod 规约中安全上下文的
`windowsOptions.hostProcess` 参数来创建
[Windows HostProcess Pod](/zh/docs/tasks/configure-pod-container/create-hostprocess-pod/)。
这些 Pod 中的所有容器都必须以 Windows HostProcess 容器方式运行。
HostProcess Pod 可以直接运行在主机上,它也能像 Linux 特权容器一样,用于执行管理任务。
<!--
Your {{< glossary_tooltip text="container runtime" term_id="container-runtime" >}} must support the concept of a privileged container for this setting to be relevant.
-->
{{< note >}}
你的{{< glossary_tooltip text="容器运行时" term_id="container-runtime" >}}必须支持
特权容器的概念才能使用这一配置。
{{< /note >}}
<!--
## Static Pods
_Static Pods_ are managed directly by the kubelet daemon on a specific node,
without the {{< glossary_tooltip text="API server" term_id="kube-apiserver" >}}
observing them.
Whereas most Pods are managed by the control plane (for example, a
{{< glossary_tooltip text="Deployment" term_id="deployment" >}}), for static
Pods, the kubelet directly supervises each static Pod (and restarts it if it fails).
-->
## 静态 Pod {#static-pods}
_静态 PodStatic Pod_ 直接由特定节点上的 `kubelet` 守护进程管理,
不需要{{< glossary_tooltip text="API 服务器" term_id="kube-apiserver" >}}看到它们。
尽管大多数 Pod 都是通过控制面(例如,{{< glossary_tooltip text="Deployment" term_id="deployment" >}}
来管理的,对于静态 Pod 而言,`kubelet` 直接监控每个 Pod,并在其失效时重启之。
<!--
Static Pods are always bound to one {{< glossary_tooltip term_id="kubelet" >}} on a specific node.
The main use for static Pods is to run a self-hosted control plane: in other words,
using the kubelet to supervise the individual [control plane components](/docs/concepts/overview/components/#control-plane-components).
The kubelet automatically tries to create a {{< glossary_tooltip text="mirror Pod" term_id="mirror-pod" >}}
on the Kubernetes API server for each static Pod.
This means that the Pods running on a node are visible on the API server,
but cannot be controlled from there.
-->
静态 Pod 通常绑定到某个节点上的 {{< glossary_tooltip text="kubelet" term_id="kubelet" >}}。
其主要用途是运行自托管的控制面。
在自托管场景中,使用 `kubelet` 来管理各个独立的
[控制面组件](/zh/docs/concepts/overview/components/#control-plane-components)。
`kubelet` 自动尝试为每个静态 Pod 在 Kubernetes API 服务器上创建一个
{{< glossary_tooltip text="镜像 Pod" term_id="mirror-pod" >}}。
这意味着在节点上运行的 Pod 在 API 服务器上是可见的,但不可以通过 API
服务器来控制。
{{< note >}}
<!--
The `spec` of a static Pod cannot refer to other API objects
(e.g., {{< glossary_tooltip text="ServiceAccount" term_id="service-account" >}},
{{< glossary_tooltip text="ConfigMap" term_id="configmap" >}},
{{< glossary_tooltip text="Secret" term_id="secret" >}}, etc).
-->
静态 Pod 的 `spec` 不能引用其他的 API 对象(例如:{{< glossary_tooltip text="ServiceAccount" term_id="service-account" >}}、{{< glossary_tooltip text="ConfigMap" term_id="configmap" >}}、{{< glossary_tooltip text="Secret" term_id="secret" >}}等)。
{{< /note >}}
<!--
## Container probes
A _probe_ is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet can invoke different actions:
- `ExecAction` (performed with the help of the container runtime)
- `TCPSocketAction` (checked directly by the kubelet)
- `HTTPGetAction` (checked directly by the kubelet)
You can read more about [probes](/docs/concepts/workloads/pods/pod-lifecycle/#container-probes)
in the Pod Lifecycle documentation.
-->
## 容器探针 {#container-probes}
_Probe_ 是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 可以执行三种动作:
- `ExecAction`(借助容器运行时执行)
- `TCPSocketAction`(由 kubelet 直接检测)
- `HTTPGetAction`(由 kubelet 直接检测)
你可以参阅 Pod 的生命周期文档中的[探针](/zh/docs/concepts/workloads/pods/pod-lifecycle/#container-probes)部分。
## {{% heading "whatsnext" %}}
<!--
* Learn about the [lifecycle of a Pod](/docs/concepts/workloads/pods/pod-lifecycle/).
* Learn about [RuntimeClass](/docs/concepts/containers/runtime-class/) and how you can use it to
configure different Pods with different container runtime configurations.
* Read about [Pod topology spread constraints](/docs/concepts/workloads/pods/pod-topology-spread-constraints/).
* Read about [PodDisruptionBudget](/docs/concepts/workloads/pods/disruptions/) and how you can use it to manage application availability during disruptions.
* Pod is a top-level resource in the Kubernetes REST API.
The {{< api-reference page="workload-resources/pod-v1" >}}
object definition describes the object in detail.
* [The Distributed System Toolkit: Patterns for Composite Containers](/blog/2015/06/the-distributed-system-toolkit-patterns/) explains common layouts for Pods with more than one container.
-->
* 了解 [Pod 生命周期](/zh/docs/concepts/workloads/pods/pod-lifecycle/)
* 了解 [RuntimeClass](/zh/docs/concepts/containers/runtime-class/),以及如何使用它
来配置不同的 Pod 使用不同的容器运行时配置
* 了解 [Pod 拓扑分布约束](/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints/)
* 了解 [PodDisruptionBudget](/zh/docs/concepts/workloads/pods/disruptions/),以及你
如何可以利用它在出现干扰因素时管理应用的可用性。
* Pod 在 Kubernetes REST API 中是一个顶层资源。
{{< api-reference page="workload-resources/pod-v1" >}}
对象的定义中包含了更多的细节信息。
* 博客 [分布式系统工具箱:复合容器模式](/blog/2015/06/the-distributed-system-toolkit-patterns/)
中解释了在同一 Pod 中包含多个容器时的几种常见布局。
<!--
To understand the context for why Kubernetes wraps a common Pod API in other resources (such as {{< glossary_tooltip text="StatefulSets" term_id="statefulset" >}} or {{< glossary_tooltip text="Deployments" term_id="deployment" >}}), you can read about the prior art, including:
-->
要了解为什么 Kubernetes 会在其他资源
(如 {{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}}
或 {{< glossary_tooltip text="Deployment" term_id="deployment" >}}
封装通用的 Pod API,相关的背景信息可以在前人的研究中找到。具体包括:
* [Aurora](https://aurora.apache.org/documentation/latest/reference/configuration/#job-schema)
* [Borg](https://research.google.com/pubs/pub43438.html)
* [Marathon](https://mesosphere.github.io/marathon/docs/rest-api.html)
* [Omega](https://research.google/pubs/pub41684/)
* [Tupperware](https://engineering.fb.com/data-center-engineering/tupperware/).
@@ -0,0 +1,512 @@
---
title: 干扰(Disruptions
content_type: concept
weight: 60
---
<!--
reviewers:
- erictune
- foxish
- davidopp
title: Disruptions
content_type: concept
weight: 60
-->
<!-- overview -->
<!--
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 上的干扰类型。
<!--
It is also for Cluster Administrators who want to perform automated
cluster actions, like upgrading and autoscaling clusters.
-->
文档同样适用于想要执行自动化集群操作(例如升级和自动扩展集群)的集群管理员。
<!-- body -->
<!--
## Voluntary and Involuntary Disruptions
Pods do not disappear until someone (a person or a controller) destroys them, or
there is an unavoidable hardware or system software error.
-->
## 自愿干扰和非自愿干扰 {#voluntary-and-involuntary-disruptions}
Pod 不会消失,除非有人(用户或控制器)将其销毁,或者出现了不可避免的硬件或软件系统错误。
<!--
We call these unavoidable cases *involuntary disruptions* to
an application. Examples are:
-->
我们把这些不可避免的情况称为应用的*非自愿干扰(Involuntary Disruptions*。例如:
<!--
- a hardware failure of the physical machine backing the node
- cluster administrator deletes VM (instance) by mistake
- cloud provider or hypervisor failure makes VM disappear
- a kernel panic
- the node disappears from the cluster due to cluster network partition
- eviction of a pod due to the node being [out-of-resources](/docs/concepts/scheduling-eviction/node-pressure-eviction/).
-->
- 节点下层物理机的硬件故障
- 集群管理员错误地删除虚拟机(实例)
- 云提供商或虚拟机管理程序中的故障导致的虚拟机消失
- 内核错误
- 节点由于集群网络隔离从集群中消失
- 由于节点[资源不足](/zh/docs/concepts/scheduling-eviction/node-pressure-eviction/)导致 pod 被驱逐。
<!--
Except for the out-of-resources condition, all these conditions
should be familiar to most users; they are not specific
to Kubernetes.
-->
除了资源不足的情况,大多数用户应该都熟悉这些情况;它们不是特定于 Kubernetes 的。
<!--
We call other cases *voluntary disruptions*. These include both
actions initiated by the application owner and those initiated by a Cluster
Administrator. Typical application owner actions include:
-->
我们称其他情况为*自愿干扰(Voluntary Disruptions*。
包括由应用程序所有者发起的操作和由集群管理员发起的操作。典型的应用程序所有者的操
作包括:
<!--
- deleting the deployment or other controller that manages the pod
- updating a deployment's pod template causing a restart
- directly deleting a pod (e.g. by accident)
-->
- 删除 Deployment 或其他管理 Pod 的控制器
- 更新了 Deployment 的 Pod 模板导致 Pod 重启
- 直接删除 Pod(例如,因为误操作)
<!--
Cluster Administrator actions include:
- [Draining a node](/docs/tasks/administer-cluster/safely-drain-node/) for repair or upgrade.
- Draining a node from a cluster to scale the cluster down (learn about
[Cluster Autoscaling](https://github.com/kubernetes/autoscaler/#readme)
).
- Removing a pod from a node to permit something else to fit on that node.
-->
集群管理员操作包括:
- [排空(drain)节点](/zh/docs/tasks/administer-cluster/safely-drain-node/)进行修复或升级。
- 从集群中排空节点以缩小集群(了解[集群自动扩缩](https://github.com/kubernetes/autoscaler/#readme))。
- 从节点中移除一个 Pod,以允许其他 Pod 使用该节点。
<!--
These actions might be taken directly by the cluster administrator, or by automation
run by the cluster administrator, or by your cluster hosting provider.
-->
这些操作可能由集群管理员直接执行,也可能由集群管理员所使用的自动化工具执行,或者由集群托管提供商自动执行。
<!--
Ask your cluster administrator or consult your cloud provider or distribution documentation
to determine if any sources of voluntary disruptions are enabled for your cluster.
If none are enabled, you can skip creating Pod Disruption Budgets.
-->
咨询集群管理员或联系云提供商,或者查询发布文档,以确定是否为集群启用了任何资源干扰源。
如果没有启用,可以不用创建 Pod Disruption BudgetsPod 干扰预算)
<!--
Not all voluntary disruptions are constrained by Pod Disruption Budgets. For example,
deleting deployments or pods bypasses Pod Disruption Budgets.
-->
{{< caution >}}
并非所有的自愿干扰都会受到 Pod 干扰预算的限制。
例如,删除 Deployment 或 Pod 的删除操作就会跳过 Pod 干扰预算检查。
{{< /caution >}}
<!--
## Dealing with Disruptions
Here are some ways to mitigate involuntary disruptions:
-->
## 处理干扰
以下是减轻非自愿干扰的一些方法:
<!--
- Ensure your pod [requests the resources](/docs/tasks/configure-pod-container/assign-cpu-ram-container) it needs.
- Replicate your application if you need higher availability. (Learn about running replicated
[stateless](/docs/tasks/run-application/run-stateless-application-deployment/)
and [stateful](/docs/tasks/run-application/run-replicated-stateful-application/) applications.)
- For even higher availability when running replicated applications,
spread applications across racks (using
[anti-affinity](/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity))
or across zones (if using a
[multi-zone cluster](/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/#affinity-and-anti-affinity)
或跨区域(如果使用[多区域集群](/zh/docs/setup/best-practices/multiple-zones/))扩展应用程序。
<!--
The frequency of voluntary disruptions varies. On a basic Kubernetes cluster, there are
no automated voluntary disruptions (only user-triggered ones). However, your cluster administrator or hosting provider
may run some additional services which cause voluntary disruptions. For example,
rolling out node software updates can cause voluntary disruptions. Also, some implementations
of cluster (node) autoscaling may cause voluntary disruptions to defragment and compact nodes.
Your cluster administrator or hosting provider should have documented what level of voluntary
disruptions, if any, to expect. Certain configuration options, such as
[using PriorityClasses](/docs/concepts/scheduling-eviction/pod-priority-preemption/)
in your pod spec can also cause voluntary (and involuntary) disruptions.
-->
自愿干扰的频率各不相同。在一个基本的 Kubernetes 集群中,没有自愿干扰(只有用户触发的干扰)。
然而,集群管理员或托管提供商可能运行一些可能导致自愿干扰的额外服务。例如,节点软
更新可能导致自愿干扰。另外,集群(节点)自动缩放的某些
实现可能导致碎片整理和紧缩节点的自愿干扰。集群
管理员或托管提供商应该已经记录了各级别的自愿干扰(如果有的话)。
有些配置选项,例如在 pod spec 中
[使用 PriorityClasses](/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/)
也会产生自愿(和非自愿)的干扰。
<!--
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 提供特性来满足在出现频繁自愿干扰的同时运行高可用的应用程序。我们称这些特性为
*干扰预算(Disruption Budget*
<!--
## Pod disruption budgets
Kubernetes offers features to help you run highly available applications even when you
introduce frequent voluntary disruptions.
An Application Owner can create a `PodDisruptionBudget` object (PDB) for each application.
A PDB limits the number of pods of a replicated application that are down simultaneously from
voluntary disruptions. For example, a quorum-based application would
like to ensure that the number of replicas running is never brought below the
number needed for a quorum. A web front end might want to
ensure that the number of replicas serving load never falls below a certain
percentage of the total.
-->
## 干扰预算 {#pod-disruption-budgets}
{{< feature-state for_k8s_version="v1.21" state="stable" >}}
即使你会经常引入自愿性干扰,Kubernetes 也能够支持你运行高度可用的应用。
应用程序所有者可以为每个应用程序创建 `PodDisruptionBudget` 对象(PDB)。
PDB 将限制在同一时间因自愿干扰导致的复制应用程序中宕机的 pod 数量。
例如,基于票选机制的应用程序希望确保运行的副本数永远不会低于仲裁所需的数量。
Web 前端可能希望确保提供负载的副本数量永远不会低于总数的某个百分比。
<!--
Cluster managers and hosting providers should use tools which
respect PodDisruptionBudgets by calling the [Eviction API](/docs/tasks/administer-cluster/safely-drain-node/#eviction-api)
instead of directly deleting pods or deployments. Examples are the `kubectl drain` command
and the Kubernetes-on-GCE cluster upgrade script (`cluster/gce/upgrade.sh`).
-->
集群管理员和托管提供商应该使用遵循 PodDisruptionBudgets 的接口
(通过调用[Eviction API](/zh/docs/tasks/administer-cluster/safely-drain-node/#the-eviction-api)),
而不是直接删除 Pod 或 Deployment。
<!--
For example, the `kubectl drain` subcommand lets you mark a node as going out of
service. When you run `kubectl drain`, the tool tries to evict all of the Pods on
the Node you'are taking out of service. The eviction request may be temporarily rejected,
and the tool periodically retries all failed requests until all pods
are terminated, or until a configurable timeout is reached.
-->
例如,`kubectl drain` 命令可以用来标记某个节点即将停止服务。
运行 `kubectl drain` 命令时,工具会尝试驱逐机器上的所有 Pod。
`kubectl` 所提交的驱逐请求可能会暂时被拒绝,所以该工具会定时重试失败的请求,
直到所有的 Pod 都被终止,或者达到配置的超时时间。
<!--
A PDB specifies the number of replicas that an application can tolerate having, relative to how
many it is intended to have. For example, a Deployment which has a `.spec.replicas: 5` is
supposed to have 5 pods at any given time. If its PDB allows for there to be 4 at a time,
then the Eviction API will allow voluntary disruption of one, but not two pods, at a time.
-->
PDB 指定应用程序可以容忍的副本数量(相当于应该有多少副本)。
例如,具有 `.spec.replicas: 5` 的 Deployment 在任何时间都应该有 5 个 Pod。
如果 PDB 允许其在某一时刻有 4 个副本,那么驱逐 API 将允许同一时刻仅有一个而不是两个 Pod 自愿干扰。
<!--
The group of pods that comprise the application is specified using a label selector, the same
as the one used by the application's controller (deployment, stateful-set, etc).
-->
使用标签选择器来指定构成应用程序的一组 Pod,这与应用程序的控制器(DeploymentStatefulSet 等)
选择 Pod 的逻辑一样。
<!--
The "intended" number of pods is computed from the `.spec.replicas` of the pods controller.
The controller is discovered from the pods using the `.metadata.ownerReferences` of the object.
-->
Pod 控制器的 `.spec.replicas` 计算“预期的” Pod 数量。
根据 Pod 对象的 `.metadata.ownerReferences` 字段来发现控制器。
<!--
[Involuntary disruptions](#voluntary-and-involuntary-disruptions) cannot be prevented by PDBs; however they
do count against the budget.
-->
PDB 无法防止[非自愿干扰](#voluntary-and-involuntary-disruptions)
但它们确实计入预算。
<!--
Pods which are deleted or unavailable due to a rolling upgrade to an application do count
against the disruption budget, but controllers (like deployment and stateful-set)
are not limited by PDBs when doing rolling upgrades - the handling of failures
during application updates is configured in spec for the specific workload resource.
-->
由于应用程序的滚动升级而被删除或不可用的 Pod 确实会计入干扰预算,
但是控制器(如 Deployment 和 StatefulSet)在进行滚动升级时不受 PDB
的限制。应用程序更新期间的故障处理方式是在对应的工作负载资源的 `spec` 中配置的。
<!--
When a pod is evicted using the eviction API, it is gracefully
[terminated](/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination),
hornoring the
`terminationGracePeriodSeconds` setting in its [PodSpec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core).
-->
当使用驱逐 API 驱逐 Pod 时,Pod 会被体面地
[终止](/zh/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination),期间会
参考 [PodSpec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core)
中的 `terminationGracePeriodSeconds` 配置值。
<!--
## PDB Example
Consider a cluster with 3 nodes, `node-1` through `node-3`.
The cluster is running several applications. One of them has 3 replicas initially called
`pod-a`, `pod-b`, and `pod-c`. Another, unrelated pod without a PDB, called `pod-x`, is also shown.
Initially, the pods are laid out as follows:
-->
## PDB 例子 {#pdb-example}
假设集群有 3 个节点,`node-1``node-3`。集群上运行了一些应用。
其中一个应用有 3 个副本,分别是 `pod-a``pod-b``pod-c`
另外,还有一个不带 PDB 的无关 pod `pod-x` 也同样显示出来。
最初,所有的 Pod 分布如下:
| node-1 | node-2 | node-3 |
|:--------------------:|:-------------------:|:------------------:|
| pod-a *available* | pod-b *available* | pod-c *available* |
| pod-x *available* | | |
<!--
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 始终处于可用状态。
<!--
For example, assume the cluster administrator wants to reboot into a new kernel version to fix a bug in the kernel.
The cluster administrator first tries to drain `node-1` using the `kubectl drain` command.
That tool tries to evict `pod-a` and `pod-x`. This succeeds immediately.
Both pods go into the `terminating` state at the same time.
This puts the cluster in this state:
-->
例如,假设集群管理员想要重启系统,升级内核版本来修复内核中的权限。
集群管理员首先使用 `kubectl drain` 命令尝试排空 `node-1` 节点。
命令尝试驱逐 `pod-a``pod-x`。操作立即就成功了。
两个 Pod 同时进入 `terminating` 状态。这时的集群处于下面的状态:
| node-1 *draining* | node-2 | node-3 |
|:--------------------:|:-------------------:|:------------------:|
| pod-a *terminating* | pod-b *available* | pod-c *available* |
| pod-x *terminating* | | |
<!--
The deployment notices that one of the pods is terminating, so it creates a replacement
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` 的替代品。
<!--
(Note: for a StatefulSet, `pod-a`, which would be called something like `pod-0`, would need
to terminate completely before its replacement, which is also called `pod-0` but has a
different UID, could be created. Otherwise, the example applies to a StatefulSet as well.)
-->
(注意:对于 StatefulSet 来说,`pod-a`(也称为 `pod-0`)需要在替换 Pod 创建之前完全终止,
替代它的也称为 `pod-0`,但是具有不同的 UID。除此之外,此示例也适用于 StatefulSet。)
<!--
Now the cluster is in this state:
-->
当前集群的状态如下:
| node-1 *draining* | node-2 | node-3 |
|:--------------------:|:-------------------:|:------------------:|
| pod-a *terminating* | pod-b *available* | pod-c *available* |
| pod-x *terminating* | pod-d *starting* | pod-y |
<!--
At some point, the pods terminate, and the cluster looks like this:
-->
在某一时刻,Pod 被终止,集群如下所示:
| node-1 *drained* | node-2 | node-3 |
|:--------------------:|:-------------------:|:------------------:|
| | pod-b *available* | pod-c *available* |
| | pod-d *starting* | pod-y |
<!--
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` 变得可用。
<!--
The cluster state now looks like this:
-->
集群状态如下所示:
| node-1 *drained* | node-2 | node-3 |
|:--------------------:|:-------------------:|:------------------:|
| | pod-b *available* | pod-c *available* |
| | pod-d *available* | pod-y |
<!--
Now, the cluster administrator tries to drain `node-2`.
The drain command will try to evict the two pods in some order, say
`pod-b` first and then `pod-d`. It will succeed at evicting `pod-b`.
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 了。
<!--
The deployment creates a replacement for `pod-b` called `pod-e`.
Because there are not enough resources in the cluster to schedule
`pod-e` the drain will again block. The cluster may end up in this
state:
-->
Deployment 创建 `pod-b` 的替代 Pod `pod-e`
因为集群中没有足够的资源来调度 `pod-e`,drain 命令再次阻塞。集群最终将是下面这种状态:
| node-1 *drained* | node-2 | node-3 | *no node* |
|:--------------------:|:-------------------:|:------------------:|:------------------:|
| | pod-b *terminating* | pod-c *available* | pod-e *pending* |
| | pod-d *available* | pod-y | |
<!--
At this point, the cluster administrator needs to
add a node back to the cluster to proceed with the upgrade.
-->
此时,集群管理员需要增加一个节点到集群中以继续升级操作。
<!--
You can see how Kubernetes varies the rate at which disruptions
can happen, according to:
-->
可以看到 Kubernetes 如何改变干扰发生的速率,根据:
<!--
- how many replicas an application needs
- how long it takes to gracefully shutdown an instance
- how long it takes a new instance to start up
- the type of controller
- the cluster's resource capacity
-->
- 应用程序需要多少个副本
- 优雅关闭应用实例需要多长时间
- 启动应用新实例需要多长时间
- 控制器的类型
- 集群的资源能力
<!--
## Separating Cluster Owner and Application Owner Roles
Often, it is useful to think of the Cluster Manager
and Application Owner as separate roles with limited knowledge
of each other. This separation of responsibilities
may make sense in these scenarios:
-->
## 分离集群所有者和应用所有者角色
通常,将集群管理者和应用所有者视为彼此了解有限的独立角色是很有用的。这种责任分离在下面这些场景下是有意义的:
<!--
- when there are many application teams sharing a Kubernetes cluster, and
there is natural specialization of roles
- when third-party tools or services are used to automate cluster management
-->
- 当有许多应用程序团队共用一个 Kubernetes 集群,并且有自然的专业角色
- 当第三方工具或服务用于集群自动化管理
<!--
Pod Disruption Budgets support this separation of roles by providing an
interface between the roles.
-->
Pod 干扰预算通过在角色之间提供接口来支持这种分离。
<!--
If you do not have such a separation of responsibilities in your organization,
you may not need to use Pod Disruption Budgets.
-->
如果你的组织中没有这样的责任分离,则可能不需要使用 Pod 干扰预算。
<!--
## How to perform Disruptive Actions on your Cluster
If you are a Cluster Administrator, and you need to perform a disruptive action on all
the nodes in your cluster, such as a node or system software upgrade, here are some options:
-->
## 如何在集群上执行干扰性操作
如果你是集群管理员,并且需要对集群中的所有节点执行干扰操作,例如节点或系统软件升级,则可以使用以下选项
<!--
- Accept downtime during the upgrade.
- Failover to another complete replica cluster.
- No downtime, but may be costly both for the duplicated nodes
and for human effort to orchestrate the switchover.
- Write disruption tolerant applications and use PDBs.
- No downtime.
- Minimal resource duplication.
- Allows more automation of cluster administration.
- Writing disruption-tolerant applications is tricky, but the work to tolerate voluntary
disruptions largely overlaps with work to support autoscaling and tolerating
involuntary disruptions.
-->
- 接受升级期间的停机时间。
- 故障转移到另一个完整的副本集群。
- 没有停机时间,但是对于重复的节点和人工协调成本可能是昂贵的。
- 编写可容忍干扰的应用程序和使用 PDB。
- 不停机。
- 最小的资源重复。
- 允许更多的集群管理自动化。
- 编写可容忍干扰的应用程序是棘手的,但对于支持容忍自愿干扰所做的工作,和支持自动扩缩和容忍非
自愿干扰所做工作相比,有大量的重叠
## {{% heading "whatsnext" %}}
<!--
* Follow steps to protect your application by [configuring a Pod Disruption Budget](/docs/tasks/run-application/configure-pdb/).
* Learn more about [draining nodes](/docs/tasks/administer-cluster/safely-drain-node/)
* Learn about [updating a deployment](/docs/concepts/workloads/controllers/deployment/#updating-a-deployment)
including steps to maintain its availability during the rollout.
-->
* 参考[配置 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)
的过程,包括如何在其进程中维持应用的可用性
@@ -0,0 +1,134 @@
---
title: 临时容器
content_type: concept
weight: 80
---
<!--
title: Ephemeral Containers
content_type: concept
weight: 80
-->
<!-- overview -->
{{< feature-state state="beta" for_k8s_version="v1.23" >}}
<!--
This page provides an overview of ephemeral containers: a special type of container
that runs temporarily in an existing {{< glossary_tooltip term_id="pod" >}} to
accomplish user-initiated actions such as troubleshooting. You use ephemeral
containers to inspect services rather than to build applications.
-->
本页面概述了临时容器:一种特殊的容器,该容器在现有
{{< glossary_tooltip text="Pod" term_id="pod" >}}
中临时运行,以便完成用户发起的操作,例如故障排查。
你会使用临时容器来检查服务,而不是用它来构建应用程序。
<!-- body -->
<!--
## Understanding ephemeral containers
{{< glossary_tooltip text="Pods" term_id="pod" >}} are the fundamental building
block of Kubernetes applications. Since Pods are intended to be disposable and
replaceable, you cannot add a container to a Pod once it has been created.
Instead, you usually delete and replace Pods in a controlled fashion using
{{< glossary_tooltip text="deployments" term_id="deployment" >}}.
-->
## 了解临时容器 {#understanding-ephemeral-containers}
{{< glossary_tooltip text="Pod" term_id="pod" >}} 是 Kubernetes 应用程序的基本构建块。
由于 Pod 是一次性且可替换的,因此一旦 Pod 创建,就无法将容器加入到 Pod 中。
取而代之的是,通常使用 {{< glossary_tooltip text="Deployment" term_id="deployment" >}}
以受控的方式来删除并替换 Pod。
<!--
Sometimes it's necessary to inspect the state of an existing Pod, however, for
example to troubleshoot a hard-to-reproduce bug. In these cases you can run
an ephemeral container in an existing Pod to inspect its state and run
arbitrary commands.
-->
有时有必要检查现有 Pod 的状态。例如,对于难以复现的故障进行排查。
在这些场景中,可以在现有 Pod 中运行临时容器来检查其状态并运行任意命令。
<!--
### What is an ephemeral container?
Ephemeral containers differ from other containers in that they lack guarantees
for resources or execution, and they will never be automatically restarted, so
they are not appropriate for building applications. Ephemeral containers are
described using the same `ContainerSpec` as regular containers, but many fields
are incompatible and disallowed for ephemeral containers.
-->
### 什么是临时容器? {#what-is-an-ephemeral-container}
临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,
因此不适用于构建应用程序。
临时容器使用与常规容器相同的 `ContainerSpec` 节来描述,但许多字段是不兼容和不允许的。
<!--
- Ephemeral containers may not have ports, so fields such as `ports`,
`livenessProbe`, `readinessProbe` are disallowed.
- Pod resource allocations are immutable, so setting `resources` is disallowed.
- For a complete list of allowed fields, see the [EphemeralContainer reference
documentation](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#ephemeralcontainer-v1-core).
-->
- 临时容器没有端口配置,因此像 `ports``livenessProbe``readinessProbe`
这样的字段是不允许的。
- Pod 资源分配是不可变的,因此 `resources` 配置是不允许的。
- 有关允许字段的完整列表,请参见
[EphemeralContainer 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#ephemeralcontainer-v1-core)。
<!--
Ephemeral containers are created using a special `ephemeralcontainers` handler
in the API rather than by adding them directly to `pod.spec`, so it's not
possible to add an ephemeral container using `kubectl edit`.
-->
临时容器是使用 API 中的一种特殊的 `ephemeralcontainers` 处理器进行创建的,
而不是直接添加到 `pod.spec` 段,因此无法使用 `kubectl edit` 来添加一个临时容器。
<!--
Like regular containers, you may not change or remove an ephemeral container
after you have added it to a Pod.
-->
与常规容器一样,将临时容器添加到 Pod 后,将不能更改或删除临时容器。
<!--
## Uses for ephemeral containers
Ephemeral containers are useful for interactive troubleshooting when `kubectl
exec` is insufficient because a container has crashed or a container image
doesn't include debugging utilities.
-->
## 临时容器的用途 {#uses-for-ephemeral-containers}
当由于容器崩溃或容器镜像不包含调试工具而导致 `kubectl exec` 无用时,
临时容器对于交互式故障排查很有用。
<!--
In particular, [distroless images](https://github.com/GoogleContainerTools/distroless)
enable you to deploy minimal container images that reduce attack surface
and exposure to bugs and vulnerabilities. Since distroless images do not include a
shell or any debugging utilities, it's difficult to troubleshoot distroless
images using `kubectl exec` alone.
-->
尤其是,[Distroless 镜像](https://github.com/GoogleContainerTools/distroless)
允许用户部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。
由于 distroless 镜像不包含 Shell 或任何的调试工具,因此很难单独使用
`kubectl exec` 命令进行故障排查。
<!--
When using ephemeral containers, it's helpful to enable [process namespace
sharing](/docs/tasks/configure-pod-container/share-process-namespace/) so
you can view processes in other containers.
-->
使用临时容器时,启用
[进程名字空间共享](/zh/docs/tasks/configure-pod-container/share-process-namespace/)
很有帮助,可以查看其他容器中的进程。
{{% heading "whatsnext" %}}
<!--
* Learn how to [debug pods using ephemeral containers](/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container).
-->
* 了解如何[使用临时调试容器来进行调试](/zh/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container)
@@ -0,0 +1,562 @@
---
title: Init 容器
content_type: concept
weight: 40
---
<!---
reviewers:
- erictune
title: Init Containers
content_type: concept
weight: 40
-->
<!-- overview -->
<!--
This page provides an overview of init containers: specialized containers that run
before app containers in a {{< glossary_tooltip text="Pod" term_id="pod" >}}.
Init containers can contain utilities or setup scripts not present in an app image.
-->
本页提供了 Init 容器的概览。Init 容器是一种特殊容器,在 {{< glossary_tooltip text="Pod" term_id="pod" >}}
内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。
<!--
You can specify init containers in the Pod specification alongside the `containers`
array (which describes app containers).
-->
你可以在 Pod 的规约中与用来描述应用容器的 `containers` 数组平行的位置指定
Init 容器。
<!-- body -->
<!--
## Understanding init containers
A {{< glossary_tooltip text="Pod" term_id="pod" >}} can have multiple containers
running apps within it, but it can also have one or more init containers, which are run
before the app containers are started.
-->
## 理解 Init 容器
每个 {{< glossary_tooltip text="Pod" term_id="pod" >}} 中可以包含多个容器,
应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
<!--
Init containers are exactly like regular containers, except:
* Init containers always run to completion.
* Each init container must complete successfully before the next one starts.
-->
Init 容器与普通的容器非常像,除了如下两点:
* 它们总是运行到完成。
* 每个都必须在下一个启动之前成功完成。
<!--
If a Pod's init container fails, the kubelet repeatedly restarts that init container until it succeeds.
However, if the Pod has a `restartPolicy` of Never, and an init container fails during startup of that Pod, Kubernetes treats the overall Pod as failed.
-->
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。
然而,如果 Pod 对应的 `restartPolicy` 值为 "Never",并且 Pod 的 Init 容器失败,
则 Kubernetes 会将整个 Pod 状态设置为失败。
<!--
To specify an init container for a Pod, add the `initContainers` field into
the [Pod specification](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec),
as an array of `container` items (similar to the app `containers` field and its contents).
See [Container](/docs/reference/kubernetes-api/workload-resources/pod-v1/#Container) in the
API reference for more details.
The status of the init containers is returned in `.status.initContainerStatuses`
field as an array of the container statuses (similar to the `.status.containerStatuses`
field).
-->
为 Pod 设置 Init 容器需要在 [Pod 规约](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec)
中添加 `initContainers` 字段,
该字段以 [Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core)
类型对象数组的形式组织,和应用的 `containers` 数组同级相邻。
参阅 API 参考的[容器](/docs/reference/kubernetes-api/workload-resources/pod-v1/#Container)章节了解详情。
Init 容器的状态在 `status.initContainerStatuses` 字段中以容器状态数组的格式返回
(类似 `status.containerStatuses` 字段)。
<!--
### Differences from regular containers
Init containers support all the fields and features of app containers,
including resource limits, volumes, and security settings. However, the
resource requests and limits for an init container are handled differently,
as documented in [Resources](#resources).
Also, init containers do not support `lifecycle`, `livenessProbe`, `readinessProbe`, or
`startupProbe` because they must run to completion before the Pod can be ready.
If you specify multiple init containers for a Pod, Kubelet runs each init
container sequentially. Each init container must succeed before the next can run.
When all of the init containers have run to completion, Kubelet initializes
the application containers for the Pod and runs them as usual.
-->
### 与普通容器的不同之处
Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。
然而,Init 容器对资源请求和限制的处理稍有不同,在下面[资源](#resources)节有说明。
同时 Init 容器不支持 `lifecycle``livenessProbe``readinessProbe``startupProbe`
因为它们必须在 Pod 就绪之前运行完成。
如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。
每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时,
Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。
<!--
## Using init containers
Because init containers have separate images from app containers, they
have some advantages for start-up related code:
* Init containers can contain utilities or custom code for setup that are not present in an app
image. For example, there is no need to make an image `FROM` another image just to use a tool like
`sed`, `awk`, `python`, or `dig` during setup.
* The application image builder and deployer roles can work independently without
the need to jointly build a single app image.
* Init containers can run with a different view of the filesystem than app containers in the
same Pod. Consequently, they can be given access to
{{< glossary_tooltip text="Secrets" term_id="secret" >}} that app containers cannot access.
* Because init containers run to completion before any app containers start, init containers offer
a mechanism to block or delay app container startup until a set of preconditions are met. Once
preconditions are met, all of the app containers in a Pod can start in parallel.
* Init containers can securely run utilities or custom code that would otherwise make an app
container image less secure. By keeping unnecessary tools separate you can limit the attack
surface of your app container image.
-->
## 使用 Init 容器
因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
* Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。
例如,没有必要仅为了在安装过程中使用类似 `sed``awk``python``dig`
这样的工具而去 `FROM` 一个镜像来生成一个新的镜像。
* Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
* 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
* Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问
应用容器不能访问的 {{< glossary_tooltip text="Secret" term_id="secret" >}} 的权限。
* 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器
提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。
一旦前置条件满足,Pod 内的所有的应用容器会并行启动。
<!--
### Examples
Here are some ideas for how to use init containers:
* Wait for a {{< glossary_tooltip text="Service" term_id="service">}} to
be created, using a shell one-line command like:
```shell
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
```
* Register this Pod with a remote server from the downward API with a command like:
```shell
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
```
* Wait for some time before starting the app container with a command like
```shell
sleep 60
```
* Clone a Git repository into a {{< glossary_tooltip text="Volume" term_id="volume" >}}
* Place values into a configuration file and run a template tool to dynamically
generate a configuration file for the main app container. For example,
place the `POD_IP` value in a configuration and generate the main app
configuration file using Jinja.
-->
### 示例 {#examples}
下面是一些如何使用 Init 容器的想法:
* 等待一个 Service 完成创建,通过类似如下 shell 命令:
```shell
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
```
* 注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下:
```shell
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register \
-d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
```
* 在启动应用容器之前等一段时间,使用类似命令:
```shell
sleep 60
```
* 克隆 Git 仓库到{{< glossary_tooltip text="卷" term_id="volume" >}}中。
* 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。
例如,在配置文件中存放 `POD_IP` 值,并使用 Jinja 生成主应用配置文件。
<!--
#### Init containers in use
This example defines a simple Pod that has two init containers.
The first waits for `myservice`, and the second waits for `mydb`. Once both
init containers complete, the Pod runs the app container from its `spec` section.
-->
### 使用 Init 容器的情况
下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 `myservice` 启动,
第二个等待 `mydb` 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动 `spec` 节中的应用容器。
```yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
```
<!--
You can start this Pod by running:
-->
你通过运行下面的命令启动 Pod
```shell
kubectl apply -f myapp.yaml
```
<!--
The output is similar to this:
-->
输出类似于:
```
pod/myapp-pod created
```
<!--
And check on its status with:
-->
使用下面的命令检查其状态:
```shell
kubectl get -f myapp.yaml
```
<!--
The output is similar to this:
-->
输出类似于:
```
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
```
<!--
or for more details:
-->
或者查看更多详细信息:
```shell
kubectl describe -f myapp.yaml
```
<!--
The output is similar to this:
-->
输出类似于:
```
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
```
<!--
To see logs for the init containers in this Pod, run:
-->
如需查看 Pod 内 Init 容器的日志,请执行:
```shell
kubectl logs myapp-pod -c init-myservice # 查看第一个 Init 容器
kubectl logs myapp-pod -c init-mydb # 查看第二个 Init 容器
```
<!--
At this point, those init containers will be waiting to discover Services named
`mydb` and `myservice`.
Here's a configuration you can use to make those Services appear:
-->
在这一刻,Init 容器将会等待至发现名称为 `mydb` 和 `myservice` 的 Service。
如下为创建这些 Service 的配置文件:
```yaml
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
```
<!--
To create the `mydb` and `myservice` services:
-->
创建 `mydb` 和 `myservice` 服务的命令:
```shell
kubectl create -f services.yaml
```
<!--
The output is similar to this:
-->
输出类似于:
```
service "myservice" created
service "mydb" created
```
<!--
You'll then see that those init containers complete, and that the `myapp-pod`
Pod moves into the Running state:
-->
这样你将能看到这些 Init 容器执行完毕,随后 `my-app` 的 Pod 进入 `Running` 状态:
```shell
kubectl get -f myapp.yaml
```
<!--
The output is similar to this:
-->
输出类似于:
```
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
```
<!--
This simple example should provide some inspiration for you to create your own
init containers. [What's next](#what-s-next) contains a link to a more detailed example.
-->
这个简单例子应该能为你创建自己的 Init 容器提供一些启发。
[接下来](#what-s-next)节提供了更详细例子的链接。
<!--
## Detailed behavior
During Pod startup, the kubelet delays running init containers until the networking
and storage are ready. Then the kubelet runs the Pod's init containers in the order
they appear in the Pod's spec.
Each init container must exit successfully before
the next container starts. If a container fails to start due to the runtime or
exits with failure, it is retried according to the Pod `restartPolicy`. However,
if the Pod `restartPolicy` is set to Always, the init containers use
`restartPolicy` OnFailure.
A Pod cannot be `Ready` until all init containers have succeeded. The ports on an
init container are not aggregated under a Service. A Pod that is initializing
is in the `Pending` state but should have a condition `Initialized` set to false.
If the Pod [restarts](#pod-restart-reasons), or is restarted, all init containers
must execute again.
-->
## 具体行为 {#detailed-behavior}
在 Pod 启动过程中,每个 Init 容器会在网络和数据卷初始化之后按顺序启动。
kubelet 运行依据 Init 容器在 Pod 规约中的出现顺序依次运行之。
每个 Init 容器成功退出后才会启动下一个 Init 容器。
如果某容器因为容器运行时的原因无法启动,或以错误状态退出,kubelet 会根据
Pod 的 `restartPolicy` 策略进行重试。
然而,如果 Pod 的 `restartPolicy` 设置为 "Always"Init 容器失败时会使用
`restartPolicy` 的 "OnFailure" 策略。
在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。
Init 容器的端口将不会在 Service 中进行聚集。正在初始化中的 Pod 处于 `Pending` 状态,
但会将状况 `Initializing` 设置为 false。
如果 Pod [重启](#pod-restart-reasons),所有 Init 容器必须重新执行。
<!--
Changes to the init container spec are limited to the container image field.
Altering an init container image field is equivalent to restarting the Pod.
Because init containers can be restarted, retried, or re-executed, init container
code should be idempotent. In particular, code that writes to files on `EmptyDirs`
should be prepared for the possibility that an output file already exists.
Init containers have all of the fields of an app container. However, Kubernetes
prohibits `readinessProbe` from being used because init containers cannot
define readiness distinct from completion. This is enforced during validation.
-->
对 Init 容器规约的修改仅限于容器的 `image` 字段。
更改 Init 容器的 `image` 字段,等同于重启该 Pod。
因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。
特别地,基于 `emptyDirs` 写文件的代码,应该对输出文件可能已经存在做好准备。
Init 容器具有应用容器的所有字段。然而 Kubernetes 禁止使用 `readinessProbe`
因为 Init 容器不能定义不同于完成态(Completion)的就绪态(Readiness)。
Kubernetes 会在校验时强制执行此检查。
<!--
Use `activeDeadlineSeconds` on the Pod to prevent init containers from failing forever.
The active deadline includes init containers.
However it is recommended to use `activeDeadlineSeconds` only if teams deploy their application
as a Job, because `activeDeadlineSeconds` has an effect even after initContainer finished.
The Pod which is already running correctly would be killed by `activeDeadlineSeconds` if you set.
The name of each app and init container in a Pod must be unique; a
validation error is thrown for any container sharing a name with another.
-->
在 Pod 上使用 `activeDeadlineSeconds` 和在容器上使用 `livenessProbe` 可以避免
Init 容器一直重复失败。
`activeDeadlineSeconds` 时间包含了 Init 容器启动的时间。
但建议仅在团队将其应用程序部署为 Job 时才使用 `activeDeadlineSeconds`
因为 `activeDeadlineSeconds` 在 Init 容器结束后仍有效果。
如果你设置了 `activeDeadlineSeconds`,已经在正常运行的 Pod 会被杀死。
在 Pod 中的每个应用容器和 Init 容器的名称必须唯一;
与任何其它容器共享同一个名称,会在校验时抛出错误。
<!--
### Resources
Given the ordering and execution for init containers, the following rules
for resource usage apply:
* The highest of any particular resource request or limit defined on all init
containers is the *effective init request/limit*. If any resource has no
resource limit specified this is considered as the highest limit.
* The Pod's *effective request/limit* for a resource is the higher of:
* the sum of all app containers request/limit for a resource
* the effective init request/limit for a resource
* Scheduling is done based on effective requests/limits, which means
init containers can reserve resources for initialization that are not used
during the life of the Pod.
* The QoS (quality of service) tier of the Pod's *effective QoS tier* is the
QoS tier for init containers and app containers alike.
-->
### 资源 {#resources}
在给定的 Init 容器执行顺序下,资源使用适用于如下规则:
* 所有 Init 容器上定义的任何特定资源的 limit 或 request 的最大值,作为 Pod *有效初始 request/limit*。
如果任何资源没有指定资源限制,这被视为最高限制。
* Pod 对资源的 *有效 limit/request* 是如下两者的较大者:
* 所有应用容器对某个资源的 limit/request 之和
* 对某个资源的有效初始 limit/request
* 基于有效 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源,
这些资源在 Pod 生命周期过程中并没有被使用。
* Pod 的 *有效 QoS 层* ,与 Init 容器和应用容器的一样。
<!--
Quota and limits are applied based on the effective Pod request and limit.
Pod level control groups (cgroups) are based on the effective Pod request and limit, the same as the scheduler.
-->
配额和限制适用于有效 Pod 的请求和限制值。
Pod 级别的 cgroups 是基于有效 Pod 的请求和限制值,和调度器相同。
<!--
### Pod restart reasons
A Pod can restart, causing re-execution of init containers, for the following
reasons:
* The Pod infrastructure container is restarted. This is uncommon and would
have to be done by someone with root access to nodes.
* All containers in a Pod are terminated while `restartPolicy` is set to Always,
forcing a restart, and the init container completion record has been lost due
to garbage collection.
-->
### Pod 重启的原因 {#pod-restart-reasons}
Pod 重启会导致 Init 容器重新执行,主要有如下几个原因:
* Pod 的基础设施容器 (译者注:如 `pause` 容器) 被重启。这种情况不多见,
必须由具备 root 权限访问节点的人员来完成。
* 当 `restartPolicy` 设置为 "`Always`"Pod 中所有容器会终止而强制重启。
由于垃圾收集机制的原因,Init 容器的完成记录将会丢失。
<!--
The Pod will not be restarted when the init container image is changed, or the
init container completion record has been lost due to garbage collection. This
applies for Kubernetes v1.20 and later. If you are using an earlier version of
Kubernetes, consult the documentation for the version you are using.
-->
当 Init 容器的镜像发生改变或者 Init 容器的完成记录因为垃圾收集等原因被丢失时,
Pod 不会被重启。这一行为适用于 Kubernetes v1.20 及更新版本。如果你在使用较早
版本的 Kubernetes,可查阅你所使用的版本对应的文档。
## {{% heading "whatsnext" %}}
<!--
* Read about [creating a Pod that has an init container](/docs/tasks/configure-pod-container/configure-pod-initialization/#create-a-pod-that-has-an-init-container)
* Learn how to [debug init containers](/docs/tasks/debug/debug-application/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/debug-application/debug-init-containers/)
@@ -0,0 +1,923 @@
---
title: Pod 的生命周期
content_type: concept
weight: 30
---
<!--
title: Pod Lifecycle
content_type: concept
weight: 30
-->
<!-- overview -->
<!--
This page describes the lifecycle of a Pod. Pods follow a defined lifecycle, starting
in the `Pending` [phase](#pod-phase), moving through `Running` if at least one
of its primary containers starts OK, and then through either the `Succeeded` or
`Failed` phases depending on whether any container in the Pod terminated in failure.
Whilst a Pod is running, the kubelet is able to restart containers to handle some
kind of faults. Within a Pod, Kubernetes tracks different container
[states](#container-states) and determines what action to take to make the Pod
healthy again.
-->
本页面讲述 Pod 的生命周期。
Pod 遵循一个预定义的生命周期,起始于 `Pending` [阶段](#pod-phase),如果至少
其中有一个主要容器正常启动,则进入 `Running`,之后取决于 Pod 中是否有容器以
失败状态结束而进入 `Succeeded` 或者 `Failed` 阶段。
在 Pod 运行期间,`kubelet` 能够重启容器以处理一些失效场景。
在 Pod 内部,Kubernetes 跟踪不同容器的[状态](#container-states)
并确定使 Pod 重新变得健康所需要采取的动作。
<!--
In the Kubernetes API, Pods have both a specification and an actual status. The
status for a Pod object consists of a set of [Pod conditions](#pod-conditions).
You can also inject [custom readiness information](#pod-readiness-gate) into the
condition data for a Pod, if that is useful to your application.
Pods are only [scheduled](/docs/concepts/scheduling-eviction/) once in their lifetime.
Once a Pod is scheduled (assigned) to a Node, the Pod runs on that Node until it stops
or is [terminated](#pod-termination).
-->
在 Kubernetes API 中,Pod 包含规约部分和实际状态部分。
Pod 对象的状态包含了一组 [Pod 状况(Conditions](#pod-conditions)。
如果应用需要的话,你也可以向其中注入[自定义的就绪性信息](#pod-readiness-gate)。
Pod 在其生命周期中只会被[调度](/zh/docs/concepts/scheduling-eviction/)一次。
一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者
被[终止](#pod-termination)。
<!-- body -->
<!--
## Pod lifetime
Like individual application containers, Pods are considered to be relatively
ephemeral (rather than durable) entities. Pods are created, assigned a unique
ID ([UID](/docs/concepts/overview/working-with-objects/names/#uids)), and scheduled
to nodes where they remain until termination (according to restart policy) or
deletion.
If a {{< glossary_tooltip term_id="node" >}} dies, the Pods scheduled to that node
are [scheduled for deletion](#pod-garbage-collection) after a timeout period.
-->
## Pod 生命期 {#pod-lifetime}
和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。
Pod 会被创建、赋予一个唯一的
ID[UID](/zh/docs/concepts/overview/working-with-objects/names/#uids)),
并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
如果一个{{< glossary_tooltip text="节点" term_id="node" >}}死掉了,调度到该节点
的 Pod 也被计划在给定超时期限结束后[删除](#pod-garbage-collection)。
<!--
Pods do not, by themselves, self-heal. If a Pod is scheduled to a
{{< glossary_tooltip text="node" term_id="node" >}} that then fails, the Pod is deleted; likewise, a Pod won't
survive an eviction due to a lack of resources or Node maintenance. Kubernetes uses a
higher-level abstraction, called a
{{< glossary_tooltip term_id="controller" text="controller" >}}, that handles the work of
managing the relatively disposable Pod instances.
-->
Pod 自身不具有自愈能力。如果 Pod 被调度到某{{< glossary_tooltip text="节点" term_id="node" >}}
而该节点之后失效,Pod 会被删除;类似地,Pod 无法在因节点资源
耗尽或者节点维护而被驱逐期间继续存活。Kubernetes 使用一种高级抽象
来管理这些相对而言可随时丢弃的 Pod 实例,称作
{{< glossary_tooltip term_id="controller" text="控制器" >}}。
<!--
A given Pod (as defined by a UID) is never "rescheduled" to a different node; instead,
that Pod can be replaced by a new, near-identical Pod, with even the same name if
desired, but with a different UID.
When something is said to have the same lifetime as a Pod, such as a
{{< glossary_tooltip term_id="volume" text="volume" >}},
that means that the thing exists as long as that specific Pod (with that exact UID)
exists. If that Pod is deleted for any reason, and even if an identical replacement
is created, the related thing (a volume, in this example) is also destroyed and
created anew.
-->
任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点;
相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。
如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
如果某物声称其生命期与某 Pod 相同,例如存储{{< glossary_tooltip term_id="volume" text="卷" >}}
这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。
如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时,
这个相关的对象(例如这里的卷)也会被删除并重建。
{{< figure src="/images/docs/pod.svg" title="Pod 结构图例" class="diagram-medium" >}}
*一个包含多个容器的 Pod 中包含一个用来拉取文件的程序和一个 Web 服务器,
均使用持久卷作为容器间共享的存储。*
<!--
## Pod phase
A Pod's `status` field is a
[PodStatus](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podstatus-v1-core)
object, which has a `phase` field.
The phase of a Pod is a simple, high-level summary of where the Pod is in its
lifecycle. The phase is not intended to be a comprehensive rollup of observations
of container or Pod state, nor is it intended to be a comprehensive state machine.
The number and meanings of Pod phase values are tightly guarded.
Other than what is documented here, nothing should be assumed about Pods that
have a given `phase` value.
Here are the possible values for `phase`:
-->
## Pod 阶段 {#pod-phase}
Pod 的 `status` 字段是一个
[PodStatus](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podstatus-v1-core)
对象,其中包含一个 `phase` 字段。
Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。
该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
Pod 阶段的数量和含义是严格定义的。
除了本文档中列举的内容外,不应该再假定 Pod 有其他的 `phase` 值。
下面是 `phase` 可能的值:
<!--
Value | Description
`Pending` | The Pod has been accepted by the Kubernetes cluster, but one or more of the containers has not been set up and made ready to run. This includes time a Pod spends waiting to bescheduled as well as the time spent downloading container images over the network.
`Running` | The Pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting.
`Succeeded` | All containers in the Pod have terminated in success, and will not be restarted.
`Failed` | All containers in the Pod have terminated, and at least one container has terminated in failure. That is, the container either exited with non-zero status or was terminated by the system.
`Unknown` | For some reason the state of the Pod could not be obtained. This phase typically occurs due to an error in communicating with the node where the Pod should be running.
-->
取值 | 描述
:-----|:-----------
`Pending`(悬决)| Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
`Running`(运行中) | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
`Succeeded`(成功) | Pod 中的所有容器都已成功终止,并且不会再重启。
`Failed`(失败) | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
`Unknown`(未知) | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。
<!--
If a node dies or is disconnected from the rest of the cluster, Kubernetes
applies a policy for setting the `phase` of all Pods on the lost node to Failed.
-->
如果某节点死掉或者与集群中其他节点失联,Kubernetes
会实施一种策略,将失去的节点上运行的所有 Pod 的 `phase` 设置为 `Failed`
<!--
## Container states
As well as the [phase](#pod-phase) of the Pod overall, Kubernetes tracks the state of
each container inside a Pod. You can use
[container lifecycle hooks](/docs/concepts/containers/container-lifecycle-hooks/) to
trigger events to run at certain points in a container's lifecycle.
Once the {{< glossary_tooltip text="scheduler" term_id="kube-scheduler" >}}
assigns a Pod to a Node, the kubelet starts creating containers for that Pod
using a {{< glossary_tooltip text="container runtime" term_id="container-runtime" >}}.
There are three possible container states: `Waiting`, `Running`, and `Terminated`.
-->
## 容器状态 {#container-states}
Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的[阶段](#pod-phase)一样。
你可以使用[容器生命周期回调](/zh/docs/concepts/containers/container-lifecycle-hooks/)
来在容器生命周期中的特定时间点触发事件。
一旦{{< glossary_tooltip text="调度器" term_id="kube-scheduler" >}}将 Pod
分派给某个节点,`kubelet` 就通过
{{< glossary_tooltip text="容器运行时" term_id="container-runtime" >}}
开始为 Pod 创建容器。
容器的状态有三种:`Waiting`(等待)、`Running`(运行中)和
`Terminated`(已终止)。
<!--
To check the state of a Pod's containers, you can use
`kubectl describe pod <name-of-pod>`. The output shows the state for each container
within that Pod.
Each state has a specific meaning:
-->
要检查 Pod 中容器的状态,你可以使用 `kubectl describe pod <pod 名称>`
其输出中包含 Pod 中每个容器的状态。
每种状态都有特定的含义:
<!--
### `Waiting` {#container-state-waiting}
If a container is not in either the `Running` or `Terminated` state, it is `Waiting`.
A container in the `Waiting` state is still running the operations it requires in
order to complete start up: for example, pulling the container image from a container
image registry, or applying {{< glossary_tooltip text="Secret" term_id="secret" >}}
data.
When you use `kubectl` to query a Pod with a container that is `Waiting`, you also see
a Reason field to summarize why the container is in that state.
-->
### `Waiting` (等待) {#container-state-waiting}
如果容器并不处在 `Running``Terminated` 状态之一,它就处在 `Waiting` 状态。
处于 `Waiting` 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像
仓库拉取容器镜像,或者向容器应用 {{< glossary_tooltip text="Secret" term_id="secret" >}}
数据等等。
当你使用 `kubectl` 来查询包含 `Waiting` 状态的容器的 Pod 时,你也会看到一个
Reason 字段,其中给出了容器处于等待状态的原因。
<!--
### `Running` {#container-state-running}
The `Running` status indicates that a container is executing without issues. If there
was a `postStart` hook configured, it has already executed and finished. When you use
`kubectl` to query a Pod with a container that is `Running`, you also see information
about when the container entered the `Running` state.
-->
### `Running`(运行中) {#container-state-running}
`Running` 状态表明容器正在执行状态并且没有问题发生。
如果配置了 `postStart` 回调,那么该回调已经执行且已完成。
如果你使用 `kubectl` 来查询包含 `Running` 状态的容器的 Pod 时,你也会看到
关于容器进入 `Running` 状态的信息。
<!--
### `Terminated` {#container-state-terminated}
A container in the `Terminated` state began execution and then either ran to
completion or failed for some reason. When you use `kubectl` to query a Pod with
a container that is `Terminated`, you see a reason, an exit code, and the start and
finish time for that container's period of execution.
If a container has a `preStop` hook configured, this hook runs before the container enters
the `Terminated` state.
-->
### `Terminated`(已终止) {#container-state-terminated}
处于 `Terminated` 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。
如果你使用 `kubectl` 来查询包含 `Terminated` 状态的容器的 Pod 时,你会看到
容器进入此状态的原因、退出代码以及容器执行期间的起止时间。
如果容器配置了 `preStop` 回调,则该回调会在容器进入 `Terminated`
状态之前执行。
<!--
## Container restart policy {#restart-policy}
The `spec` of a Pod has a `restartPolicy` field with possible values Always, OnFailure,
and Never. The default value is Always.
The `restartPolicy` applies to all containers in the Pod. `restartPolicy` only
refers to restarts of the containers by the kubelet on the same node. After containers
in a Pod exit, the kubelet restarts them with an exponential back-off delay (10s, 20s,
40s, …), that is capped at five minutes. Once a container has executed for 10 minutes
without any problems, the kubelet resets the restart backoff timer for
that container.
-->
## 容器重启策略 {#restart-policy}
Pod 的 `spec` 中包含一个 `restartPolicy` 字段,其可能取值包括
Always、OnFailure 和 Never。默认值是 Always。
`restartPolicy` 适用于 Pod 中的所有容器。`restartPolicy` 仅针对同一节点上
`kubelet` 的容器重启动作。当 Pod 中的容器退出时,`kubelet` 会按指数回退
方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。
一旦某容器执行了 10 分钟并且没有出现问题,`kubelet` 对该容器的重启回退计时器执行
重置操作。
<!--
## Pod conditions
A Pod has a PodStatus, which has an array of
[PodConditions](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podcondition-v1-core)
through which the Pod has or has not passed:
-->
## Pod 状况 {#pod-conditions}
Pod 有一个 PodStatus 对象,其中包含一个
[PodConditions](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podcondition-v1-core)
数组。Pod 可能通过也可能未通过其中的一些状况测试。
<!--
* `PodScheduled`: the Pod has been scheduled to a node.
* `ContainersReady`: all containers in the Pod are ready.
* `Initialized`: all [init containers](/docs/concepts/workloads/pods/init-containers/)
have completed successfully.
* `Ready`: the Pod is able to serve requests and should be added to the load
balancing pools of all matching Services.
-->
* `PodScheduled`Pod 已经被调度到某节点;
* `ContainersReady`Pod 中所有容器都已就绪;
* `Initialized`:所有的 [Init 容器](/zh/docs/concepts/workloads/pods/init-containers/)
都已成功完成;
* `Ready`:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。
<!--
Field name | Description
`type` | Name of this Pod condition.
`status` | Indicates whether that condition is applicable, with possible values "`True`", "`False`", or "`Unknown`".
`lastProbeTime` | Timestamp of when the Pod condition was last probed.
`lastTransitionTime` | Timestamp for when the Pod last transitioned from one status to another.
`reason` | Machine-readable, UpperCamelCase text indicating the reason for the condition's last transition.
`message` | Human-readable message indicating details about the last status transition.
-->
字段名称 | 描述
:--------------------|:-----------
`type` | Pod 状况的名称
`status` | 表明该状况是否适用,可能的取值有 "`True`", "`False`" 或 "`Unknown`"
`lastProbeTime` | 上次探测 Pod 状况时的时间戳
`lastTransitionTime` | Pod 上次从一种状态转换到另一种状态时的时间戳
`reason` | 机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因
`message` | 人类可读的消息,给出上次状态转换的详细信息
<!--
### Pod readiness {#pod-readiness-gate}
Your application can inject extra feedback or signals into PodStatus:
_Pod readiness_. To use this, set `readinessGates` in the Pod's `spec` to
specify a list of additional conditions that the kubelet evaluates for Pod readiness.
-->
### Pod 就绪态 {#pod-readiness-gate}
{{< feature-state for_k8s_version="v1.14" state="stable" >}}
你的应用可以向 PodStatus 中注入额外的反馈或者信号:_Pod ReadinessPod 就绪态)_。
要使用这一特性,可以设置 Pod 规约中的 `readinessGates` 列表,为 kubelet
提供一组额外的状况供其评估 Pod 就绪态时使用。
<!--
Readiness gates are determined by the current state of `status.condition`
fields for the Pod. If Kubernetes cannot find such a condition in the
`status.conditions` field of a Pod, the status of the condition
is defaulted to "`False`".
Here is an example:
-->
就绪态门控基于 Pod 的 `status.conditions` 字段的当前值来做决定。
如果 Kubernetes 无法在 `status.conditions` 字段中找到某状况,则该状况的
状态值默认为 "`False`"。
这里是一个例子:
```yaml
kind: Pod
...
spec:
readinessGates:
- conditionType: "www.example.com/feature-1"
status:
conditions:
- type: Ready # 内置的 Pod 状况
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
- type: "www.example.com/feature-1" # 额外的 Pod 状况
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
containerStatuses:
- containerID: docker://abcd...
ready: true
...
```
<!--
The Pod conditions you add must have names that meet the Kubernetes [label key format](/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set).
-->
你所添加的 Pod 状况名称必须满足 Kubernetes
[标签键名格式](/zh/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set)。
<!--
### Status for Pod readiness {#pod-readiness-status}
The `kubectl patch` command does not support patching object status.
To set these `status.conditions` for the pod, applications and
{{< glossary_tooltip term_id="operator-pattern" text="operators">}} should use
the `PATCH` action.
You can use a [Kubernetes client library](/docs/reference/using-api/client-libraries/) to
write code that sets custom Pod conditions for Pod readiness.
-->
### Pod 就绪态的状态 {#pod-readiness-status}
命令 `kubectl patch` 不支持修改对象的状态。
如果需要设置 Pod 的 `status.conditions`,应用或者
{{< glossary_tooltip term_id="operator-pattern" text="Operators">}}
需要使用 `PATCH` 操作。
你可以使用 [Kubernetes 客户端库](/zh/docs/reference/using-api/client-libraries/)
之一来编写代码,针对 Pod 就绪态设置定制的 Pod 状况。
<!--
For a Pod that uses custom conditions, that Pod is evaluated to be ready **only**
when both the following statements apply:
* All containers in the Pod are ready.
* All conditions specified in `readinessGates` are `True`.
When a Pod's containers are Ready but at least one custom condition is missing or
`False`, the kubelet sets the Pod's [condition](#pod-conditions) to `ContainersReady`.
-->
对于使用定制状况的 Pod 而言,只有当下面的陈述都适用时,该 Pod 才会被评估为就绪:
* Pod 中所有容器都已就绪;
* `readinessGates` 中的所有状况都为 `True` 值。
当 Pod 的容器都已就绪,但至少一个定制状况没有取值或者取值为 `False`
`kubelet` 将 Pod 的[状况](#pod-conditions)设置为 `ContainersReady`
<!--
## Container probes
A _probe_ is a diagnostic
performed periodically by the
[kubelet](/docs/reference/command-line-tools-reference/kubelet/)
on a container. To perform a diagnostic,
the kubelet either executes code within the container, or makes
a network request.
-->
## 容器探针 {#container-probes}
probe 是由 [kubelet](/zh/docs/reference/command-line-tools-reference/kubelet/) 对容器执行的定期诊断。
要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求。
<!--
### Check mechanisms {#probe-check-methods}
There are four different ways to check a container using a probe.
Each probe must define exactly one of these four mechanisms:
`exec`
: Executes a specified command inside the container. The diagnostic
is considered successful if the command exits with a status code of 0.
`grpc`
: Performs a remote procedure call using [gRPC](https://grpc.io/).
The target should implement
[gRPC health checks](https://grpc.io/grpc/core/md_doc_health-checking.html).
The diagnostic is considered successful if the `status`
of the response is `SERVING`.
gRPC probes are an alpha feature and are only available if you
enable the `GRPCContainerProbe`
[feature gate](/docs/reference/command-line-tools-reference/feature-gates/).
`httpGet`
: Performs an HTTP `GET` request against the Pod's IP
address on a specified port and path. The diagnostic is
considered successful if the response has a status code
greater than or equal to 200 and less than 400.
`tcpSocket`
: Performs a TCP check against the Pod's IP address on
a specified port. The diagnostic is considered successful if
the port is open. If the remote system (the container) closes
the connection immediately after it opens, this counts as healthy.
-->
### 检查机制 {#probe-check-methods}
使用探针来检查容器有四种不同的方法。
每个探针都必须准确定义为这四种机制中的一种:
`exec`
: 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
`grpc`
: 使用 [gRPC](https://grpc.io/) 执行一个远程过程调用。
目标应该实现
[gRPC健康检查](https://grpc.io/grpc/core/md_doc_health-checking.html)。
如果响应的状态是 "SERVING",则认为诊断成功。
gRPC 探针是一个 alpha 特性,只有在你启用了
"GRPCContainerProbe" [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gate/)时才能使用。
`httpGet`
: 对容器的 IP 地址上指定端口和路径执行 HTTP `GET` 请求。如果响应的状态码大于等于 200
且小于 400,则诊断被认为是成功的。
`tcpSocket`
: 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。
如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。
<!--
### Probe outcome
Each probe has one of three results:
`Success`
: The container passed the diagnostic.
`Failure`
: The container failed the diagnostic.
`Unknown`
: The diagnostic failed (no action should be taken, and the kubelet
will make further checks).
-->
### 探测结果 {#probe-outcome}
每次探测都将获得以下三种结果之一:
`Success`(成功)
: 容器通过了诊断。
`Failure`(失败)
: 容器未通过诊断。
`Unknown`(未知)
: 诊断失败,因此不会采取任何行动。
<!--
### Types of probe
The kubelet can optionally perform and react to three kinds of probes on running
containers:
-->
### 探测类型 {#types-of-probe}
针对运行中的容器,`kubelet` 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:
<!--
`livenessProbe`
: Indicates whether the container is running. If
the liveness probe fails, the kubelet kills the container, and the container
is subjected to its [restart policy](#restart-policy). If a container does not
provide a liveness probe, the default state is `Success`.
`readinessProbe`
: Indicates whether the container is ready to respond to requests.
If the readiness probe fails, the endpoints controller removes the Pod's IP
address from the endpoints of all Services that match the Pod. The default
state of readiness before the initial delay is `Failure`. If a container does
not provide a readiness probe, the default state is `Success`.
`startupProbe`
: Indicates whether the application within the container is started.
All other probes are disabled if a startup probe is provided, until it succeeds.
If the startup probe fails, the kubelet kills the container, and the container
is subjected to its [restart policy](#restart-policy). If a container does not
provide a startup probe, the default state is `Success`.
-->
`livenessProbe`
: 指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器,
并且容器将根据其[重启策略](#restart-policy)决定未来。如果容器不提供存活探针,
则默认状态为 `Success`
`readinessProbe`
: 指示容器是否准备好为请求提供服务。如果就绪态探测失败,
端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。
初始延迟之前的就绪态的状态值默认为 `Failure`
如果容器不提供就绪态探针,则默认状态为 `Success`
`startupProbe`
: 指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被
禁用,直到此探针成功为止。如果启动探测失败,`kubelet` 将杀死容器,而容器依其
[重启策略](#restart-policy)进行重启。
如果容器没有提供启动探测,则默认状态为 `Success`
<!--
For more information about how to set up a liveness, readiness, or startup probe,
see [Configure Liveness, Readiness and Startup Probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/).
-->
如欲了解如何设置存活态、就绪态和启动探针的进一步细节,可以参阅
[配置存活态、就绪态和启动探针](/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)。
<!--
#### When should you use a liveness probe?
-->
#### 何时该使用存活态探针? {#when-should-you-use-a-liveness-probe}
{{< feature-state for_k8s_version="v1.0" state="stable" >}}
<!--
If the process in your container is able to crash on its own whenever it
encounters an issue or becomes unhealthy, you do not necessarily need a liveness
probe; the kubelet will automatically perform the correct action in accordance
with the Pod's `restartPolicy`.
If you'd like your container to be killed and restarted if a probe fails, then
specify a liveness probe, and specify a `restartPolicy` of Always or OnFailure.
-->
如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活态探针;
`kubelet` 将根据 Pod 的`restartPolicy` 自动执行修复操作。
如果你希望容器在探测失败时被杀死并重新启动,那么请指定一个存活态探针,
并指定`restartPolicy` 为 "`Always`" 或 "`OnFailure`"。
<!--
#### When should you use a readiness probe?
-->
#### 何时该使用就绪态探针? {#when-should-you-use-a-readiness-probe}
{{< feature-state for_k8s_version="v1.0" state="stable" >}}
<!--
If you'd like to start sending traffic to a Pod only when a probe succeeds,
specify a readiness probe. In this case, the readiness probe might be the same
as the liveness probe, but the existence of the readiness probe in the spec means
that the Pod will start without receiving any traffic and only start receiving
traffic after the probe starts succeeding.
-->
如果要仅在探测成功时才开始向 Pod 发送请求流量,请指定就绪态探针。
在这种情况下,就绪态探针可能与存活态探针相同,但是规约中的就绪态探针的存在意味着
Pod 将在启动阶段不接收任何数据,并且只有在探针探测成功后才开始接收数据。
<!--
If you want your container to be able to take itself down for maintenance, you
can specify a readiness probe that checks an endpoint specific to readiness that
is different from the liveness probe.
-->
如果你希望容器能够自行进入维护状态,也可以指定一个就绪态探针,检查某个特定于
就绪态的因此不同于存活态探测的端点。
<!--
If your app has a strict dependency on back-end services, you can implement both
a liveness and a readiness probe. The liveness probe passes when the app itself
is healthy, but the readiness probe additionally checks that each required
back-end service is available. This helps you avoid directing traffic to Pods
that can only respond with error messages.
If your container needs to work on loading large data, configuration files, or
migrations during startup, you can use a
[startup probe](#when-should-you-use-a-startup-probe). However, if you want to
detect the difference between an app that has failed and an app that is still
processing its startup data, you might prefer a readiness probe.
-->
如果你的应用程序对后端服务有严格的依赖性,你可以同时实现存活态和就绪态探针。
当应用程序本身是健康的,存活态探针检测通过后,就绪态探针会额外检查每个所需的后端服务是否可用。
这可以帮助你避免将流量导向只能返回错误信息的 Pod。
如果你的容器需要在启动期间加载大型数据、配置文件或执行迁移,你可以使用
[启动探针](#when-should-you-use-a-startup-probe)。
然而,如果你想区分已经失败的应用和仍在处理其启动数据的应用,你可能更倾向于使用就绪探针。
{{< note >}}
<!--
If you want to be able to drain requests when the Pod is deleted, you do not
necessarily need a readiness probe; on deletion, the Pod automatically puts itself
into an unready state regardless of whether the readiness probe exists.
The Pod remains in the unready state while it waits for the containers in the Pod
to stop.
-->
请注意,如果你只是想在 Pod 被删除时能够排空请求,则不一定需要使用就绪态探针;
在删除 Pod 时,Pod 会自动将自身置于未就绪状态,无论就绪态探针是否存在。
等待 Pod 中的容器停止期间,Pod 会一直处于未就绪状态。
{{< /note >}}
<!--
#### When should you use a startup probe?
-->
#### 何时该使用启动探针? {#when-should-you-use-a-startup-probe}
{{< feature-state for_k8s_version="v1.18" state="beta" >}}
<!--
Startup probes are useful for Pods that have containers that take a long time to
come into service. Rather than set a long liveness interval, you can configure
a separate configuration for probing the container as it starts up, allowing
a time longer than the liveness interval would allow.
-->
对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的。
你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定,
对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。
<!--
If your container usually starts in more than
`initialDelaySeconds + failureThreshold × periodSeconds`, you should specify a
startup probe that checks the same endpoint as the liveness probe. The default for
`periodSeconds` is 10s. You should then set its `failureThreshold` high enough to
allow the container to start, without changing the default values of the liveness
probe. This helps to protect against deadlocks.
-->
如果你的容器启动时间通常超出 `initialDelaySeconds + failureThreshold × periodSeconds`
总值,你应该设置一个启动探测,对存活态探针所使用的同一端点执行检查。
`periodSeconds` 的默认值是 10 秒。你应该将其 `failureThreshold` 设置得足够高,
以便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。
这一设置有助于减少死锁状况的发生。
<!--
## Termination of Pods {#pod-termination}
Because Pods represent processes running on nodes in the cluster, it is important to
allow those processes to gracefully terminate when they are no longer needed (rather
than being abruptly stopped with a `KILL` signal and having no chance to clean up).
-->
## Pod 的终止 {#pod-termination}
由于 Pod 所代表的是在集群中节点上运行的进程,当不再需要这些进程时允许其体面地
终止是很重要的。一般不应武断地使用 `KILL` 信号终止它们,导致这些进程没有机会
完成清理操作。
<!--
The design aim is for you to be able to request deletion and know when processes
terminate, but also be able to ensure that deletes eventually complete.
When you request deletion of a Pod, the cluster records and tracks the intended grace period
before the Pod is allowed to be forcefully killed. With that forceful shutdown tracking in
place, the {< glossary_tooltip text="kubelet" term_id="kubelet" >}} attempts graceful
shutdown.
-->
设计的目标是令你能够请求删除进程,并且知道进程何时被终止,同时也能够确保删除
操作终将完成。当你请求删除某个 Pod 时,集群会记录并跟踪 Pod 的体面终止周期,
而不是直接强制地杀死 Pod。在存在强制关闭设施的前提下,
{{< glossary_tooltip text="kubelet" term_id="kubelet" >}} 会尝试体面地终止
Pod。
<!--
Typically, the container runtime sends a TERM signal to the main process in each
container. Many container runtimes respect the `STOPSIGNAL` value defined in the container
image and send this instead of TERM.
Once the grace period has expired, the KILL signal is sent to any remainig
processes, and the Pod is then deleted from the
{{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}}. If the kubelet or the
container runtime's management service is restarted while waiting for processes to terminate, the
cluster retries from the start including the full original grace period.
-->
通常情况下,容器运行时会发送一个 TERM 信号到每个容器中的主进程。
很多容器运行时都能够注意到容器镜像中 `STOPSIGNAL` 的值,并发送该信号而不是 TERM。
一旦超出了体面终止限期,容器运行时会向所有剩余进程发送 KILL 信号,之后
Pod 就会被从 {{< glossary_tooltip text="API 服务器" term_id="kube-apiserver" >}}
上移除。如果 `kubelet` 或者容器运行时的管理服务在等待进程终止期间被重启,
集群会从头开始重试,赋予 Pod 完整的体面终止限期。
<!--
An example flow:
1. You use the `kubectl` tool to manually delete a specific Pod, with the default grace period
(30 seconds).
1. The Pod in the API server is updated with the time beyond which the Pod is considered "dead"
along with the grace period.
If you use `kubectl describe` to check on the Pod you're deleting, that Pod shows up as
"Terminating".
On the node where the Pod is running: as soon as the kubelet sees that a Pod has been marked
as terminating (a graceful shutdown duration has been set), the kubelet begins the local Pod
shutdown process.
-->
下面是一个例子:
1. 你使用 `kubectl` 工具手动删除某个特定的 Pod,而该 Pod 的体面终止限期是默认值(30 秒)。
2. API 服务器中的 Pod 对象被更新,记录涵盖体面终止限期在内 Pod
的最终死期,超出所计算时间点则认为 Pod 已死(dead)。
如果你使用 `kubectl describe` 来查验你正在删除的 Pod,该 Pod 会显示为
"Terminating" (正在终止)。
在 Pod 运行所在的节点上:`kubelet` 一旦看到 Pod
被标记为正在终止(已经设置了体面终止限期),`kubelet` 即开始本地的 Pod 关闭过程。
<!--
1. If one of the Pod's containers has defined a `preStop`
[hook](/docs/concepts/containers/container-lifecycle-hooks), the kubelet
runs that hook inside of the container. If the `preStop` hook is still running after the
grace period expires, the kubelet requests a small, one-off grace period extension of 2
seconds.
If the `preStop` hook needs longer to complete than the default grace period allows,
you must modify `terminationGracePeriodSeconds` to suit this.
1. The kubelet triggers the container runtime to send a TERM signal to process 1 inside each
container.
The containers in the Pod receive the TERM signal at different times and in an arbitrary
order. If the order of shutdowns matters, consider using a `preStop` hook to synchronize.
-->
1. 如果 Pod 中的容器之一定义了 `preStop`
[回调](/zh/docs/concepts/containers/container-lifecycle-hooks)
`kubelet` 开始在容器内运行该回调逻辑。如果超出体面终止限期时,`preStop` 回调逻辑
仍在运行,`kubelet` 会请求给予该 Pod 的宽限期一次性增加 2 秒钟。
{{< note >}}
如果 `preStop` 回调所需要的时间长于默认的体面终止限期,你必须修改
`terminationGracePeriodSeconds` 属性值来使其正常工作。
{{< /note >}}
1. `kubelet` 接下来触发容器运行时发送 TERM 信号给每个容器中的进程 1。
{{< note >}}
Pod 中的容器会在不同时刻收到 TERM 信号,接收顺序也是不确定的。
如果关闭的顺序很重要,可以考虑使用 `preStop` 回调逻辑来协调。
{{< /note >}}
<!--
1. At the same time as the kubelet is starting graceful shutdown, the control plane removes that
shutting-down Pod from Endpoints (and, if enabled, EndpointSlice) objects where these represent
a {{< glossary_tooltip term_id="service" text="Service" >}} with a configured
{{< glossary_tooltip text="selector" term_id="selector" >}}.
{{< glossary_tooltip text="ReplicaSets" term_id="replica-set" >}} and other workload resources
no longer treat the shutting-down Pod as a valid, in-service replica. Pods that shut down slowly
cannot continue to serve traffic as load balancers (like the service proxy) remove the Pod from
the list of endpoints as soon as the termination grace period _begins_.
-->
3. 与此同时,`kubelet` 启动体面关闭逻辑,控制面会将 Pod 从对应的端点列表(以及端点切片列表,
如果启用了的话)中移除,过滤条件是 Pod 被对应的
{{< glossary_tooltip term_id="service" text="服务" >}}以某
{{< glossary_tooltip text="选择算符" term_id="selector" >}}选定。
{{< glossary_tooltip text="ReplicaSets" term_id="replica-set" >}}和其他工作负载资源
不再将关闭进程中的 Pod 视为合法的、能够提供服务的副本。关闭动作很慢的 Pod
也无法继续处理请求数据,因为负载均衡器(例如服务代理)已经在终止宽限期开始的时候
将其从端点列表中移除。
<!--
1. When the grace period expires, the kubelet triggers forcible shutdown. The container runtime sends
`SIGKILL` to any processes still running in any container in the Pod.
The kubelet also cleans up a hidden `pause` container if that container runtime uses one.
1. The kubelet triggers forcible removal of Pod object from the API server, by setting grace period
to 0 (immediate deletion).
1. The API server deletes the Pod's API object, which is then no longer visible from any client.
-->
4. 超出终止宽限期限时,`kubelet` 会触发强制关闭过程。容器运行时会向 Pod 中所有容器内
仍在运行的进程发送 `SIGKILL` 信号。
`kubelet` 也会清理隐藏的 `pause` 容器,如果容器运行时使用了这种容器的话。
5. `kubelet` 触发强制从 API 服务器上删除 Pod 对象的逻辑,并将体面终止限期设置为 0
(这意味着马上删除)。
6. API 服务器删除 Pod 的 API 对象,从任何客户端都无法再看到该对象。
<!--
### Forced Pod termination {#pod-termination-forced}
Forced deletions can be potentially disruptive for some workloads and their Pods.
By default, all deletes are graceful within 30 seconds. The `kubectl delete` command supports
the `-grace-period=<seconds>` option which allows you to override the default and specify your
own value.
-->
### 强制终止 Pod {#pod-termination-forced}
{{< caution >}}
对于某些工作负载及其 Pod 而言,强制删除很可能会带来某种破坏。
{{< /caution >}}
默认情况下,所有的删除操作都会附有 30 秒钟的宽限期限。
`kubectl delete` 命令支持 `--grace-period=<seconds>` 选项,允许你重载默认值,
设定自己希望的期限值。
<!--
Setting the grace period to `0` forcibly and immediately deletes the Pod from the API
server. If the pod was still running on a node, that forcible deletion triggers the kubelet to
begin immediate cleanup.
-->
将宽限期限强制设置为 `0` 意味着立即从 API 服务器删除 Pod。
如果 Pod 仍然运行于某节点上,强制删除操作会触发 `kubelet` 立即执行清理操作。
<!--
You must specify an additional flag `--force` along with `--grace-period=0` in order to perform force deletions.
-->
{{< note >}}
你必须在设置 `--grace-period=0` 的同时额外设置 `--force`
参数才能发起强制删除请求。
{{< /note >}}
<!--
When a force deletion is performed, the API server does not wait for confirmation
from the kubelet that the Pod has been terminated on the node it was running on. It
removes the Pod in the API immediately so a new Pod can be created with the same
name. On the node, Pods that are set to terminate immediately will still be given
a small grace period before being force killed.
If you need to force-delete Pods that are part of a StatefulSet, refer to the task
documentation for
[deleting Pods from a StatefulSet](/docs/tasks/run-application/force-delete-stateful-set-pod/).
-->
执行强制删除操作时,API 服务器不再等待来自 `kubelet` 的、关于 Pod
已经在原来运行的节点上终止执行的确认消息。
API 服务器直接删除 Pod 对象,这样新的与之同名的 Pod 即可以被创建。
在节点侧,被设置为立即终止的 Pod 仍然会在被强行杀死之前获得一点点的宽限时间。
如果你需要强制删除 StatefulSet 的 Pod,请参阅
[从 StatefulSet 中删除 Pod](/zh/docs/tasks/run-application/force-delete-stateful-set-pod/)
的任务文档。
<!--
### Garbage collection of failed Pods {#pod-garbage-collection}
For failed Pods, the API objects remain in the cluster's API until a human or
{{< glossary_tooltip term_id="controller" text="controller" >}} process
explicitly removes them.
The control plane cleans up terminated Pods (with a phase of `Succeeded` or
`Failed`), when the number of Pods exceeds the configured threshold
(determined by `terminated-pod-gc-threshold` in the kube-controller-manager).
This avoids a resource leak as Pods are created and terminated over time.
-->
### 失效 Pod 的垃圾收集 {#pod-garbage-collection}
对于已失败的 Pod 而言,对应的 API 对象仍然会保留在集群的 API 服务器上,直到
用户或者{{< glossary_tooltip term_id="controller" text="控制器" >}}进程显式地
将其删除。
控制面组件会在 Pod 个数超出所配置的阈值
(根据 `kube-controller-manager``terminated-pod-gc-threshold` 设置)时
删除已终止的 Pod(阶段值为 `Succeeded``Failed`)。
这一行为会避免随着时间演进不断创建和终止 Pod 而引起的资源泄露问题。
## {{% heading "whatsnext" %}}
<!--
* Get hands-on experience
[attaching handlers to container lifecycle events](/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/).
* Get hands-on experience
[configuring Liveness, Readiness and Startup Probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/).
* Learn more about [container lifecycle hooks](/docs/concepts/containers/container-lifecycle-hooks/).
* For detailed information about Pod and container status in the API, see
the API reference documentation covering
[`.status`](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodStatus) for Pod.
-->
* 动手实践[为容器生命周期时间关联处理程序](/zh/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/)。
* 动手实践[配置存活态、就绪态和启动探针](/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)。
* 进一步了解[容器生命周期回调](/zh/docs/concepts/containers/container-lifecycle-hooks/)。
* 关于 API 中定义的有关 Pod 和容器状态的详细规范信息,
可参阅 API 参考文档中 Pod 的 [`.status`](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodStatus) 字段。
@@ -0,0 +1,692 @@
---
title: Pod 拓扑分布约束
content_type: concept
weight: 40
---
<!--
title: Pod Topology Spread Constraints
content_type: concept
weight: 40
-->
<!-- overview -->
<!--
You can use _topology spread constraints_ to control how {{< glossary_tooltip text="Pods" term_id="Pod" >}} are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. This can help to achieve high availability as well as efficient resource utilization.
-->
你可以使用 _拓扑分布约束(Topology Spread Constraints_ 来控制
{{< glossary_tooltip text="Pods" term_id="Pod" >}} 在集群内故障域
之间的分布,例如区域(Region)、可用区(Zone)、节点和其他用户自定义拓扑域。
这样做有助于实现高可用并提升资源利用率。
<!-- body -->
<!--
## Prerequisites
### Node Labels
-->
## 先决条件 {#prerequisites}
### 节点标签 {#node-labels}
<!--
Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in. For example, a Node might have labels: `node=node1,zone=us-east-1a,region=us-east-1`
-->
拓扑分布约束依赖于节点标签来标识每个节点所在的拓扑域。
例如,某节点可能具有标签:`node=node1,zone=us-east-1a,region=us-east-1`
<!--
Suppose you have a 4-node cluster with the following labels:
-->
假设你拥有具有以下标签的一个 4 节点集群:
```
NAME STATUS ROLES AGE VERSION LABELS
node1 Ready <none> 4m26s v1.16.0 node=node1,zone=zoneA
node2 Ready <none> 3m58s v1.16.0 node=node2,zone=zoneA
node3 Ready <none> 3m17s v1.16.0 node=node3,zone=zoneB
node4 Ready <none> 2m43s v1.16.0 node=node4,zone=zoneB
```
<!--
Then the cluster is logically viewed as below:
-->
那么,从逻辑上看集群如下:
{{<mermaid>}}
graph TB
subgraph "zoneB"
n3(Node3)
n4(Node4)
end
subgraph "zoneA"
n1(Node1)
n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4 k8s;
class zoneA,zoneB cluster;
{{< /mermaid >}}
<!--
Instead of manually applying labels, you can also reuse the [well-known labels](/docs/reference/labels-annotations-taints/) that are created and populated automatically on most clusters.
-->
你可以复用在大多数集群上自动创建和填充的[常用标签](/zh/docs/reference/labels-annotations-taints/)
而不是手动添加标签。
<!--
## Spread Constraints for Pods
-->
## Pod 的分布约束 {#spread-constraints-for-pods}
### API
<!--
The API field `pod.spec.topologySpreadConstraints` is defined as below:
-->
`pod.spec.topologySpreadConstraints` 字段定义如下所示:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
topologySpreadConstraints:
- maxSkew: <integer>
topologyKey: <string>
whenUnsatisfiable: <string>
labelSelector: <object>
```
<!--
You can define one or multiple `topologySpreadConstraint` to instruct the kube-scheduler how to place each incoming Pod in relation to the existing Pods across your cluster. The fields are:
-->
你可以定义一个或多个 `topologySpreadConstraint` 来指示 kube-scheduler
如何根据与现有的 Pod 的关联关系将每个传入的 Pod 部署到集群中。字段包括:
<!--
- **maxSkew** describes the degree to which Pods may be unevenly distributed.
It's the maximum permitted difference between the number of matching Pods in
any two topology domains of a given topology type. It must be greater than
zero. Its semantics differs according to the value of `whenUnsatisfiable`:
- when `whenUnsatisfiable` equals to "DoNotSchedule", `maxSkew` is the maximum
permitted difference between the number of matching pods in the target
topology and the global minimum.
(the minimum number of pods that match the label selector in a topology domain.
For example, if you have 3 zones with 0, 2 and 3 matching pods respectively,
The global minimum is 0).
- when `whenUnsatisfiable` equals to "ScheduleAnyway", scheduler gives higher
precedence to topologies that would help reduce the skew.
-->
- **maxSkew** 描述 Pod 分布不均的程度。这是给定拓扑类型中任意两个拓扑域中
匹配的 pod 之间的最大允许差值。它必须大于零。取决于 `whenUnsatisfiable`
取值,其语义会有不同。
-`whenUnsatisfiable` 等于 "DoNotSchedule" 时,`maxSkew` 是目标拓扑域
中匹配的 Pod 数与全局最小值(一个拓扑域中与标签选择器匹配的 Pod 的最小数量。例如,如果你有
3 个区域,分别具有 0 个、2 个 和 3 个匹配的 Pod,则全局最小值为 0。)之间可存在的差异。
-`whenUnsatisfiable` 等于 "ScheduleAnyway" 时,调度器会更为偏向能够降低
偏差值的拓扑域。
<!--
- **minDomains** indicates a minimum number of eligible domains.
A domain is a particular instance of a topology. An eligible domain is a domain whose
nodes match the node selector.
- The value of `minDomains` must be greater than 0, when specified.
- When the number of eligible domains with match topology keys is less than `minDomains`,
Pod topology spread treats "global minimum" as 0, and then the calculation of `skew` is performed.
The "global minimum" is the minimum number of matching Pods in an eligible domain,
or zero if the number of eligible domains is less than `minDomains`.
- When the number of eligible domains with matching topology keys equals or is greater than
`minDomains`, this value has no effect on scheduling.
- When `minDomains` is nil, the constraint behaves as if `minDomains` is 1.
- When `minDomains` is not nil, the value of `whenUnsatisfiable` must be "`DoNotSchedule`".
-->
- **minDomains** 表示符合条件的域的最小数量。域是拓扑的一个特定实例。
符合条件的域是其节点与节点选择器匹配的域。
- 指定的 `minDomains` 的值必须大于 0。
- 当符合条件的、拓扑键匹配的域的数量小于 `minDomains` 时,Pod 拓扑分布将“全局最小值”(global minimum 设为
0,然后进行 `skew` 计算。“全局最小值”是一个符合条件的域中匹配 Pods 的最小数量,
如果符合条件的域的数量小于 `minDomains`,则全局最小值为零。
- 当符合条件的拓扑键匹配域的个数等于或大于 `minDomains` 时,该值对调度没有影响。
-`minDomains` 为 nil 时,约束的行为等于 `minDomains` 为 1。
-`minDomains` 不为 nil 时,`whenUnsatisfiable` 的值必须为 "`DoNotSchedule`" 。
{{< note >}}
<!--
The `minDomains` field is an alpha field added in 1.24. You have to enable the
`MinDomainsInPodToplogySpread` [feature gate](/docs/reference/command-line-tools-reference/feature-gates/)
in order to use it.
-->
`minDomains` 字段是在 1.24 版本中新增的 alpha 字段。你必须启用
`MinDomainsInPodToplogySpread` [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)才能使用它。
{{< /note >}}
<!--
- **topologyKey** is the key of node labels. If two Nodes are labelled with this key and have identical values for that label, the scheduler treats both Nodes as being in the same topology. The scheduler tries to place a balanced number of Pods into each topology domain.
- **whenUnsatisfiable** indicates how to deal with a Pod if it doesn't satisfy the spread constraint:
- `DoNotSchedule` (default) tells the scheduler not to schedule it.
- `ScheduleAnyway` tells the scheduler to still schedule it while prioritizing nodes that minimize the skew.
- **labelSelector** is used to find matching Pods. Pods that match this label selector are counted to determine the number of Pods in their corresponding topology domain. See [Label Selectors](/docs/concepts/overview/working-with-objects/labels/#label-selectors) for more details.
-->
- **topologyKey** 是节点标签的键。如果两个节点使用此键标记并且具有相同的标签值,
则调度器会将这两个节点视为处于同一拓扑域中。调度器试图在每个拓扑域中放置数量
均衡的 Pod。
- **whenUnsatisfiable** 指示如果 Pod 不满足分布约束时如何处理:
- `DoNotSchedule`(默认)告诉调度器不要调度。
- `ScheduleAnyway` 告诉调度器仍然继续调度,只是根据如何能将偏差最小化来对
节点进行排序。
- **labelSelector** 用于查找匹配的 pod。匹配此标签的 Pod 将被统计,以确定相应
拓扑域中 Pod 的数量。
有关详细信息,请参考[标签选择算符](/zh/docs/concepts/overview/working-with-objects/labels/#label-selectors)。
<!--
When a Pod defines more than one `topologySpreadConstraint`, those constraints are ANDed: The kube-scheduler looks for a node for the incoming Pod that satisfies all the constraints.
-->
当 Pod 定义了不止一个 `topologySpreadConstraint`,这些约束之间是逻辑与的关系。
kube-scheduler 会为新的 Pod 寻找一个能够满足所有约束的节点。
<!--
You can read more about this field by running `kubectl explain Pod.spec.topologySpreadConstraints`.
-->
你可以执行 `kubectl explain Pod.spec.topologySpreadConstraints` 命令以
了解关于 topologySpreadConstraints 的更多信息。
<!--
### Example: One TopologySpreadConstraint
Suppose you have a 4-node cluster where 3 Pods labeled `foo:bar` are located in node1, node2 and node3 respectively:
-->
### 例子:单个 TopologySpreadConstraint
假设你拥有一个 4 节点集群,其中标记为 `foo:bar` 的 3 个 Pod 分别位于
node1、node2 和 node3 中:
{{<mermaid>}}
graph BT
subgraph "zoneB"
p3(Pod) --> n3(Node3)
n4(Node4)
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3 k8s;
class zoneA,zoneB cluster;
{{< /mermaid >}}
<!--
If we want an incoming Pod to be evenly spread with existing Pods across zones, the spec can be given as:
-->
如果希望新来的 Pod 均匀分布在现有的可用区域,则可以按如下设置其规约:
{{< codenew file="pods/topology-spread-constraints/one-constraint.yaml" >}}
<!--
`topologyKey: zone` implies the even distribution will only be applied to the nodes which have label pair "zone:&lt;any value&gt;" present. `whenUnsatisfiable: DoNotSchedule` tells the scheduler to let it stay pending if the incoming Pod cant satisfy the constraint.
-->
`topologyKey: zone` 意味着均匀分布将只应用于存在标签键值对为
"zone:&lt;any value&gt;" 的节点。
`whenUnsatisfiable: DoNotSchedule` 告诉调度器如果新的 Pod 不满足约束,
则让它保持悬决状态。
<!--
If the scheduler placed this incoming Pod into "zoneA", the Pods distribution would become [3, 1],
hence the actual skew is 2 (3 - 1) - which violates `maxSkew: 1`. In this example, the incoming Pod can only be placed onto "zoneB":
-->
如果调度器将新的 Pod 放入 "zoneA"Pods 分布将变为 [3, 1],因此实际的偏差
为 23 - 1)。这违反了 `maxSkew: 1` 的约定。此示例中,新 Pod 只能放置在
"zoneB" 上:
{{<mermaid>}}
graph BT
subgraph "zoneB"
p3(Pod) --> n3(Node3)
p4(mypod) --> n4(Node4)
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3 k8s;
class p4 plain;
class zoneA,zoneB cluster;
{{< /mermaid >}}
或者
{{<mermaid>}}
graph BT
subgraph "zoneB"
p3(Pod) --> n3(Node3)
p4(mypod) --> n3
n4(Node4)
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3 k8s;
class p4 plain;
class zoneA,zoneB cluster;
{{< /mermaid >}}
<!--
You can tweak the Pod spec to meet various kinds of requirements:
-->
你可以调整 Pod 规约以满足各种要求:
<!--
- Change `maxSkew` to a bigger value like "2" so that the incoming Pod can be placed onto "zoneA" as well.
- Change `topologyKey` to "node" so as to distribute the Pods evenly across nodes instead of zones. In the above example, if `maxSkew` remains "1", the incoming Pod can only be placed onto "node4".
- Change `whenUnsatisfiable: DoNotSchedule` to `whenUnsatisfiable: ScheduleAnyway` to ensure the incoming Pod to be always schedulable (suppose other scheduling APIs are satisfied). However, its preferred to be placed onto the topology domain which has fewer matching Pods. (Be aware that this preferability is jointly normalized with other internal scheduling priorities like resource usage ratio, etc.)
-->
-`maxSkew` 更改为更大的值,比如 "2",这样新的 Pod 也可以放在 "zoneA" 上。
-`topologyKey` 更改为 "node",以便将 Pod 均匀分布在节点上而不是区域中。
在上面的例子中,如果 `maxSkew` 保持为 "1",那么传入的 Pod 只能放在 "node4" 上。
-`whenUnsatisfiable: DoNotSchedule` 更改为 `whenUnsatisfiable: ScheduleAnyway`
以确保新的 Pod 始终可以被调度(假设满足其他的调度 API)。
但是,最好将其放置在匹配 Pod 数量较少的拓扑域中。
(请注意,这一优先判定会与其他内部调度优先级(如资源使用率等)排序准则一起进行标准化。)
<!--
### Example: Multiple TopologySpreadConstraints
-->
### 例子:多个 TopologySpreadConstraints
<!--
This builds upon the previous example. Suppose you have a 4-node cluster where 3 Pods labeled `foo:bar` are located in node1, node2 and node3 respectively (`P` represents Pod):
-->
下面的例子建立在前面例子的基础上。假设你拥有一个 4 节点集群,其中 3 个标记为 `foo:bar`
Pod 分别位于 node1、node2 和 node3 上:
{{<mermaid>}}
graph BT
subgraph "zoneB"
p3(Pod) --> n3(Node3)
n4(Node4)
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3 k8s;
class p4 plain;
class zoneA,zoneB cluster;
{{< /mermaid >}}
<!--
You can use 2 TopologySpreadConstraints to control the Pods spreading on both zone and node:
-->
可以使用 2 个 TopologySpreadConstraint 来控制 Pod 在 区域和节点两个维度上的分布:
{{< codenew file="pods/topology-spread-constraints/two-constraints.yaml" >}}
<!--
In this case, to match the first constraint, the incoming Pod can only be placed onto "zoneB"; while in terms of the second constraint, the incoming Pod can only be placed onto "node4". Then the results of 2 constraints are ANDed, so the only viable option is to place on "node4".
-->
在这种情况下,为了匹配第一个约束,新的 Pod 只能放置在 "zoneB" 中;而在第二个约束中,
新的 Pod 只能放置在 "node4" 上。最后两个约束的结果加在一起,唯一可行的选择是放置
在 "node4" 上。
<!--
Multiple constraints can lead to conflicts. Suppose you have a 3-node cluster across 2 zones:
-->
多个约束之间可能存在冲突。假设有一个跨越 2 个区域的 3 节点集群:
{{<mermaid>}}
graph BT
subgraph "zoneB"
p4(Pod) --> n3(Node3)
p5(Pod) --> n3
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n1
p3(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3,p4,p5 k8s;
class zoneA,zoneB cluster;
{{< /mermaid >}}
<!--
If you apply "two-constraints.yaml" to this cluster, you will notice "mypod" stays in `Pending` state. This is because: to satisfy the first constraint, "mypod" can only be put to "zoneB"; while in terms of the second constraint, "mypod" can only put to "node2". Then a joint result of "zoneB" and "node2" returns nothing.
-->
如果对集群应用 "two-constraints.yaml",会发现 "mypod" 处于 `Pending` 状态。
这是因为:为了满足第一个约束,"mypod" 只能放在 "zoneB" 中,而第二个约束要求
"mypod" 只能放在 "node2" 上。Pod 调度无法满足两种约束。
<!--
To overcome this situation, you can either increase the `maxSkew` or modify one of the constraints to use `whenUnsatisfiable: ScheduleAnyway`.
-->
为了克服这种情况,你可以增加 `maxSkew` 或修改其中一个约束,让其使用
`whenUnsatisfiable: ScheduleAnyway`
<!--
### Interaction With Node Affinity and Node Selectors
The scheduler will skip the non-matching nodes from the skew calculations if the incoming Pod has `spec.nodeSelector` or `spec.affinity.nodeAffinity` defined.
-->
### 节点亲和性与节点选择器的相互作用 {#interaction-with-node-affinity-and-node-selectors}
如果 Pod 定义了 `spec.nodeSelector``spec.affinity.nodeAffinity`
调度器将在偏差计算中跳过不匹配的节点。
<!--
### Example: TopologySpreadConstraints with NodeAffinity
Suppose you have a 5-node cluster ranging from zoneA to zoneC:
-->
### 示例:TopologySpreadConstraints 与 NodeAffinity
假设你有一个跨越 zoneA 到 zoneC 的 5 节点集群:
{{<mermaid>}}
graph BT
subgraph "zoneB"
p3(Pod) --> n3(Node3)
n4(Node4)
end
subgraph "zoneA"
p1(Pod) --> n1(Node1)
p2(Pod) --> n2(Node2)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n1,n2,n3,n4,p1,p2,p3 k8s;
class p4 plain;
class zoneA,zoneB cluster;
{{< /mermaid >}}
{{<mermaid>}}
graph BT
subgraph "zoneC"
n5(Node5)
end
classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
class n5 k8s;
class zoneC cluster;
{{< /mermaid >}}
<!--
and you know that "zoneC" must be excluded. In this case, you can compose the yaml as below, so that "mypod" will be placed onto "zoneB" instead of "zoneC". Similarly `spec.nodeSelector` is also respected.
-->
而且你知道 "zoneC" 必须被排除在外。在这种情况下,可以按如下方式编写 YAML,
以便将 "mypod" 放置在 "zoneB" 上,而不是 "zoneC" 上。同样,`spec.nodeSelector`
也要一样处理。
{{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}}
<!--
The scheduler doesn't have prior knowledge of all the zones or other topology domains that a cluster has. They are determined from the existing nodes in the cluster. This could lead to a problem in autoscaled clusters, when a node pool (or node group) is scaled to zero nodes and the user is expecting them to scale up, because, in this case, those topology domains won't be considered until there is at least one node in them.
-->
调度器不会预先知道集群拥有的所有区域和其他拓扑域。拓扑域由集群中存在的节点确定。
在自动伸缩的集群中,如果一个节点池(或节点组)的节点数量为零,
而用户正期望其扩容时,可能会导致调度出现问题。
因为在这种情况下,调度器不会考虑这些拓扑域信息,因为它们是空的,没有节点。
<!--
### Other Noticeable Semantics
There are some implicit conventions worth noting here:
-->
### 其他值得注意的语义 {#other-noticeable-semantics}
这里有一些值得注意的隐式约定:
<!--
- Only the Pods holding the same namespace as the incoming Pod can be matching candidates.
- The scheduler will bypass the nodes without `topologySpreadConstraints[*].topologyKey` present. This implies that:
1. the Pods located on those nodes do not impact `maxSkew` calculation - in the above example, suppose "node1" does not have label "zone", then the 2 Pods will be disregarded, hence the incoming Pod will be scheduled into "zoneA".
2. the incoming Pod has no chances to be scheduled onto this kind of nodes - in the above example, suppose a "node5" carrying label `{zone-typo: zoneC}` joins the cluster, it will be bypassed due to the absence of label key "zone".
-->
- 只有与新的 Pod 具有相同命名空间的 Pod 才能作为匹配候选者。
- 调度器会忽略没有 `topologySpreadConstraints[*].topologyKey` 的节点。这意味着:
1. 位于这些节点上的 Pod 不影响 `maxSkew` 的计算。
在上面的例子中,假设 "node1" 没有标签 "zone",那么 2 个 Pod 将被忽略,
因此传入的 Pod 将被调度到 "zoneA" 中。
2. 新的 Pod 没有机会被调度到这类节点上。
在上面的例子中,假设一个带有标签 `{zone-typo: zoneC}` 的 "node5" 加入到集群,
它将由于没有标签键 "zone" 而被忽略。
<!--
- Be aware of what will happen if the incomingPods `topologySpreadConstraints[*].labelSelector` doesnt match its own labels. In the above example, if we remove the incoming Pods labels, it can still be placed onto "zoneB" since the constraints are still satisfied. However, after the placement, the degree of imbalance of the cluster remains unchanged - its still zoneA having 2 Pods which hold label {foo:bar}, and zoneB having 1 Pod which holds label {foo:bar}. So if this is not what you expect, we recommend the workloads `topologySpreadConstraints[*].labelSelector` to match its own labels.
-->
- 注意,如果新 Pod 的 `topologySpreadConstraints[*].labelSelector` 与自身的
标签不匹配,将会发生什么。
在上面的例子中,如果移除新 Pod 上的标签,Pod 仍然可以调度到 "zoneB",因为约束仍然满足。
然而,在调度之后,集群的不平衡程度保持不变。zoneA 仍然有 2 个带有 {foo:bar} 标签的 Pod
zoneB 有 1 个带有 {foo:bar} 标签的 Pod。
因此,如果这不是你所期望的,建议工作负载的 `topologySpreadConstraints[*].labelSelector`
与其自身的标签匹配。
<!--
### Cluster-level default constraints
It is possible to set default topology spread constraints for a cluster. Default
topology spread constraints are applied to a Pod if, and only if:
- It doesn't define any constraints in its `.spec.topologySpreadConstraints`.
- It belongs to a service, replication controller, replica set or stateful set.
-->
### 集群级别的默认约束 {#cluster-level-default-constraints}
为集群设置默认的拓扑分布约束也是可能的。默认拓扑分布约束在且仅在以下条件满足
时才会应用到 Pod 上:
- Pod 没有在其 `.spec.topologySpreadConstraints` 设置任何约束;
- Pod 隶属于某个服务、副本控制器、ReplicaSet 或 StatefulSet。
<!--
Default constraints can be set as part of the `PodTopologySpread` plugin args
in a [scheduling profile](/docs/reference/scheduling/config/#profiles).
The constraints are specified with the same [API above](#api), except that
`labelSelector` must be empty. The selectors are calculated from the services,
replication controllers, replica sets or stateful sets that the Pod belongs to.
An example configuration might look like follows:
-->
你可以在 [调度方案(Scheduling Profile](/zh/docs/reference/scheduling/config/#profiles)
中将默认约束作为 `PodTopologySpread` 插件参数的一部分来设置。
约束的设置采用[如前所述的 API](#api),只是 `labelSelector` 必须为空。
选择算符是根据 Pod 所属的服务、副本控制器、ReplicaSet 或 StatefulSet 来设置的。
配置的示例可能看起来像下面这个样子:
```yaml
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
defaultingType: List
```
{{< note >}}
<!--
[`SelectorSpread` plugin](/docs/reference/scheduling/config/#scheduling-plugins)
is disabled by default. It's recommended to use `PodTopologySpread` to achieve similar
behavior.
-->
[`SelectorSpread` 插件](/zh/docs/reference/scheduling/config/#scheduling-plugins)默认是被禁用的。
建议使用 `PodTopologySpread` 来实现类似的行为。
{{< /note >}}
<!--
#### Internal default constraints
-->
#### 内部默认约束 {#internal-default-constraints}
{{< feature-state for_k8s_version="v1.24" state="stable" >}}
<!--
If you don't configure any cluster-level default constraints for pod topology spreading,
then kube-scheduler acts as if you specified the following default topology constraints:
-->
如果你没有为 Pod 拓扑分布配置任何集群级别的默认约束,
kube-scheduler 的行为就像你指定了以下默认拓扑约束一样:
```yaml
defaultConstraints:
- maxSkew: 3
topologyKey: "kubernetes.io/hostname"
whenUnsatisfiable: ScheduleAnyway
- maxSkew: 5
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: ScheduleAnyway
```
<!--
Also, the legacy `SelectorSpread` plugin, which provides an equivalent behavior,
is disabled by default.
-->
此外,原来用于提供等同行为的 `SelectorSpread` 插件默认被禁用。
{{< note >}}
<!--
The `PodTopologySpread` plugin does not score the nodes that don't have
the topology keys specified in the spreading constraints. This might result
in a different default behavior compared to the legacy `SelectorSpread` plugin when
using the default topology constraints.
-->
对于分布约束中所指定的拓扑键而言,`PodTopologySpread` 插件不会为不包含这些主键的节点评分。
这可能导致在使用默认拓扑约束时,其行为与原来的 `SelectorSpread` 插件的默认行为不同,
<!--
If your nodes are not expected to have **both** `kubernetes.io/hostname` and
`topology.kubernetes.io/zone` labels set, define your own constraints
instead of using the Kubernetes defaults.
-->
如果你的节点不会 **同时** 设置 `kubernetes.io/hostname`
`topology.kubernetes.io/zone` 标签,你应该定义自己的约束而不是使用
Kubernetes 的默认约束。
{{< /note >}}
<!--
If you don't want to use the default Pod spreading constraints for your cluster,
you can disable those defaults by setting `defaultingType` to `List` and leaving
empty `defaultConstraints` in the `PodTopologySpread` plugin configuration:
-->
如果你不想为集群使用默认的 Pod 分布约束,你可以通过设置 `defaultingType` 参数为 `List`
并将 `PodTopologySpread` 插件配置中的 `defaultConstraints` 参数置空来禁用默认 Pod 分布约束。
```yaml
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints: []
defaultingType: List
```
<!--
## Comparison with PodAffinity/PodAntiAffinity
In Kubernetes, directives related to "Affinity" control how Pods are
scheduled - more packed or more scattered.
-->
## 与 PodAffinity/PodAntiAffinity 相比较
在 Kubernetes 中,与“亲和性”相关的指令控制 Pod 的调度方式(更密集或更分散)。
<!--
- For `PodAffinity`, you can try to pack any number of Pods into qualifying
topology domain(s)
- For `PodAntiAffinity`, only one Pod can be scheduled into a
single topology domain.
-->
- 对于 `PodAffinity`,你可以尝试将任意数量的 Pod 集中到符合条件的拓扑域中。
- 对于 `PodAntiAffinity`,只能将一个 Pod 调度到某个拓扑域中。
<!--
For finer control, you can specify topology spread constraints to distribute
Pods across different topology domains - to achieve either high availability or
cost-saving. This can also help on rolling update workloads and scaling out
replicas smoothly. See
[Motivation](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/895-pod-topology-spread#motivation)
for more details.
-->
要实现更细粒度的控制,你可以设置拓扑分布约束来将 Pod 分布到不同的拓扑域下,
从而实现高可用性或节省成本。这也有助于工作负载的滚动更新和平稳地扩展副本规模。
有关详细信息,请参考
[动机](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-pod-topology-spread.md#motivation)文档。
<!--
## Known Limitations
- There's no guarantee that the constraints remain satisfied when Pods are removed. For example, scaling down a Deployment may result in imbalanced Pods distribution.
You can use [Descheduler](https://github.com/kubernetes-sigs/descheduler) to rebalance the Pods distribution.
- Pods matched on tainted nodes are respected. See [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)
-->
## 已知局限性
- 当 Pod 被移除时,无法保证约束仍被满足。例如,缩减某 Deployment 的规模时,
Pod 的分布可能不再均衡。
你可以使用 [Descheduler](https://github.com/kubernetes-sigs/descheduler)
来重新实现 Pod 分布的均衡。
- 具有污点的节点上匹配的 Pods 也会被统计。
参考 [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)。
## {{% heading "whatsnext" %}}
<!--
- [Blog: Introducing PodTopologySpread](https://kubernetes.io/blog/2020/05/introducing-podtopologyspread/)
explains `maxSkew` in details, as well as bringing up some advanced usage examples.
-->
- [博客: PodTopologySpread介绍](https://kubernetes.io/blog/2020/05/introducing-podtopologyspread/)
详细解释了 `maxSkew`,并给出了一些高级的使用示例。