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:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "运行应用"
|
||||
weight: 40
|
||||
description: 运行和管理无状态和有状态的应用程序。
|
||||
---
|
||||
@@ -0,0 +1,189 @@
|
||||
---
|
||||
title: 从 Pod 中访问 Kubernetes API
|
||||
content_type: task
|
||||
weight: 120
|
||||
---
|
||||
|
||||
<!--
|
||||
title: Accessing the Kubernetes API from a Pod
|
||||
content_type: task
|
||||
weight: 120
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
This guide demonstrates how to access the Kubernetes API from within a pod.
|
||||
-->
|
||||
本指南演示了如何从 Pod 中访问 Kubernetes API。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}}
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
<!--
|
||||
## Accessing the API from within a Pod
|
||||
|
||||
When accessing the API from within a Pod, locating and authenticating
|
||||
to the API server are slightly different to the external client case.
|
||||
-->
|
||||
### 从 Pod 中访问 API {#accessing-the-api-from-within-a-pod}
|
||||
|
||||
从 Pod 内部访问 API 时,定位 API 服务器和向服务器认证身份的操作
|
||||
与外部客户端场景不同。
|
||||
|
||||
<!--
|
||||
The easiest way to use the Kubernetes API from a Pod is to use
|
||||
one of the official [client libraries](/docs/reference/using-api/client-libraries/). These
|
||||
libraries can automatically discover the API server and authenticate.
|
||||
-->
|
||||
从 Pod 使用 Kubernetes API 的最简单的方法就是使用官方的
|
||||
[客户端库](/zh/docs/reference/using-api/client-libraries/)。
|
||||
这些库可以自动发现 API 服务器并进行身份验证。
|
||||
|
||||
<!--
|
||||
### Using Official Client Libraries
|
||||
|
||||
From within a Pod, the recommended ways to connect to the Kubernetes API are:
|
||||
|
||||
- For a Go client, use the official [Go client library](https://github.com/kubernetes/client-go/).
|
||||
The `rest.InClusterConfig()` function handles API host discovery and authentication automatically.
|
||||
See [an example here](https://git.k8s.io/client-go/examples/in-cluster-client-configuration/main.go).
|
||||
|
||||
- For a Python client, use the official [Python client library](https://github.com/kubernetes-client/python/).
|
||||
The `config.load_incluster_config()` function handles API host discovery and authentication automatically.
|
||||
See [an example here](https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py).
|
||||
|
||||
- There are a number of other libraries available, please refer to the [Client Libraries](/docs/reference/using-api/client-libraries/) page.
|
||||
|
||||
In each case, the service account credentials of the Pod are used to communicate
|
||||
securely with the API server.
|
||||
-->
|
||||
#### 使用官方客户端库 {#using-official-client-libraries}
|
||||
|
||||
从一个 Pod 内部连接到 Kubernetes API 的推荐方式为:
|
||||
|
||||
- 对于 Go 语言客户端,使用官方的 [Go 客户端库](https://github.com/kubernetes/client-go/)。
|
||||
函数 `rest.InClusterConfig()` 自动处理 API 主机发现和身份认证。
|
||||
参见[这里的一个例子](https://git.k8s.io/client-go/examples/in-cluster-client-configuration/main.go)。
|
||||
|
||||
- 对于 Python 客户端,使用官方的 [Python 客户端库](https://github.com/kubernetes-client/python/)。
|
||||
函数 `config.load_incluster_config()` 自动处理 API 主机的发现和身份认证。
|
||||
参见[这里的一个例子](https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py)。
|
||||
|
||||
- 还有一些其他可用的客户端库,请参阅[客户端库](/zh/docs/reference/using-api/client-libraries/)页面。
|
||||
|
||||
在以上场景中,客户端库都使用 Pod 的服务账号凭据来与 API 服务器安全地通信。
|
||||
|
||||
<!--
|
||||
### Directly accessing the REST API
|
||||
|
||||
While running in a Pod, the Kubernetes apiserver is accessible via a Service named
|
||||
`kubernetes` in the `default` namespace. Therefore, Pods can use the
|
||||
`kubernetes.default.svc` hostname to query the API server. Official client libraries
|
||||
do this automatically.
|
||||
-->
|
||||
#### 直接访问 REST API {#directly-accessing-the-rest-api}
|
||||
|
||||
在运行在 Pod 中时,可以通过 `default` 命名空间中的名为 `kubernetes` 的服务访问
|
||||
Kubernetes API 服务器。也就是说,Pod 可以使用 `kubernetes.default.svc` 主机名
|
||||
来查询 API 服务器。官方客户端库自动完成这个工作。
|
||||
|
||||
<!--
|
||||
The recommended way to authenticate to the API server is with a
|
||||
[service account](/docs/tasks/configure-pod-container/configure-service-account/)
|
||||
credential. By default, a Pod
|
||||
is associated with a service account, and a credential (token) for that
|
||||
service account is placed into the filesystem tree of each container in that Pod,
|
||||
at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
|
||||
-->
|
||||
向 API 服务器进行身份认证的推荐做法是使用
|
||||
[服务账号](/zh/docs/tasks/configure-pod-container/configure-service-account/)凭据。
|
||||
默认情况下,每个 Pod 与一个服务账号关联,该服务账户的凭证(令牌)放置在此 Pod 中
|
||||
每个容器的文件系统树中的 `/var/run/secrets/kubernetes.io/serviceaccount/token` 处。
|
||||
|
||||
<!--
|
||||
If available, a certificate bundle is placed into the filesystem tree of each
|
||||
container at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`, and should be
|
||||
used to verify the serving certificate of the API server.
|
||||
-->
|
||||
如果证书包可用,则凭证包被放入每个容器的文件系统树中的
|
||||
`/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` 处,
|
||||
且将被用于验证 API 服务器的服务证书。
|
||||
|
||||
<!--
|
||||
Finally, the default namespace to be used for namespaced API operations is placed in a file
|
||||
at `/var/run/secrets/kubernetes.io/serviceaccount/namespace` in each container.
|
||||
-->
|
||||
最后,用于命名空间域 API 操作的默认命名空间放置在每个容器中的
|
||||
`/var/run/secrets/kubernetes.io/serviceaccount/namespace` 文件中。
|
||||
|
||||
<!--
|
||||
### Using kubectl proxy
|
||||
|
||||
If you would like to query the API without an official client library, you can run `kubectl proxy`
|
||||
as the [command](/docs/tasks/inject-data-application/define-command-argument-container/)
|
||||
of a new sidecar container in the Pod. This way, `kubectl proxy` will authenticate
|
||||
to the API and expose it on the `localhost` interface of the Pod, so that other containers
|
||||
in the Pod can use it directly.
|
||||
-->
|
||||
#### 使用 kubectl proxy {#use-kubectl-proxy}
|
||||
|
||||
如果你希望不使用官方客户端库就完成 API 查询,可以将 `kubectl proxy` 作为
|
||||
[command](/zh/docs/tasks/inject-data-application/define-command-argument-container/)
|
||||
在 Pod 中启动一个边车(Sidecar)容器。这样,`kubectl proxy` 自动完成对 API
|
||||
的身份认证,并将其暴露到 Pod 的 `localhost` 接口,从而 Pod 中的其他容器可以
|
||||
直接使用 API。
|
||||
|
||||
<!--
|
||||
### Without using a proxy
|
||||
|
||||
It is possible to avoid using the kubectl proxy by passing the authentication token
|
||||
directly to the API server. The internal certificate secures the connection.
|
||||
-->
|
||||
### 不使用代理 {#without-using-a-proxy}
|
||||
|
||||
通过将认证令牌直接发送到 API 服务器,也可以避免运行 kubectl proxy 命令。
|
||||
内部的证书机制能够为链接提供保护。
|
||||
|
||||
```shell
|
||||
# 指向内部 API 服务器的主机名
|
||||
APISERVER=https://kubernetes.default.svc
|
||||
|
||||
# 服务账号令牌的路径
|
||||
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
|
||||
|
||||
# 读取 Pod 的名字空间
|
||||
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
|
||||
|
||||
# 读取服务账号的持有者令牌
|
||||
TOKEN=$(cat ${SERVICEACCOUNT}/token)
|
||||
|
||||
# 引用内部证书机构(CA)
|
||||
CACERT=${SERVICEACCOUNT}/ca.crt
|
||||
|
||||
# 使用令牌访问 API
|
||||
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api
|
||||
```
|
||||
|
||||
<!--
|
||||
The output will be similar to this:
|
||||
-->
|
||||
输出类似于:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "APIVersions",
|
||||
"versions": [
|
||||
"v1"
|
||||
],
|
||||
"serverAddressByClientCIDRs": [
|
||||
{
|
||||
"clientCIDR": "0.0.0.0/0",
|
||||
"serverAddress": "10.0.1.149:443"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,439 @@
|
||||
---
|
||||
title: 为应用程序设置干扰预算(Disruption Budget)
|
||||
content_type: task
|
||||
weight: 110
|
||||
min-kubernetes-server-version: v1.21
|
||||
---
|
||||
|
||||
<!--
|
||||
title: Specifying a Disruption Budget for your Application
|
||||
content_type: task
|
||||
weight: 110
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
{{< feature-state for_k8s_version="v1.21" state="stable" >}}
|
||||
|
||||
<!--
|
||||
This page shows how to limit the number of concurrent disruptions
|
||||
that your application experiences, allowing for higher availability
|
||||
while permitting the cluster administrator to manage the clusters
|
||||
nodes.
|
||||
-->
|
||||
本文展示如何限制应用程序的并发干扰数量,在允许集群管理员管理集群节点的同时保证高可用。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< version-check >}}
|
||||
|
||||
<!--
|
||||
* You are the owner of an application running on a Kubernetes cluster that requires
|
||||
high availability.
|
||||
* You should know how to deploy [Replicated Stateless Applications](/docs/tasks/run-application/run-stateless-application-deployment/)
|
||||
and/or [Replicated Stateful Applications](/docs/tasks/run-application/run-replicated-stateful-application/).
|
||||
* You should have read about [Pod Disruptions](/docs/concepts/workloads/pods/disruptions/).
|
||||
* You should confirm with your cluster owner or service provider that they respect
|
||||
Pod Disruption Budgets.
|
||||
-->
|
||||
* 你是 Kubernetes 集群中某应用的所有者,该应用有高可用要求。
|
||||
* 你应了解如何部署[无状态应用](/zh/docs/tasks/run-application/run-stateless-application-deployment/)
|
||||
和/或[有状态应用](/zh/docs/tasks/run-application/run-replicated-stateful-application/)。
|
||||
* 你应当已经阅读过关于 [Pod 干扰](/zh/docs/concepts/workloads/pods/disruptions/) 的文档。
|
||||
* 用户应当与集群所有者或服务提供者确认其遵从 Pod 干扰预算(Pod Disruption Budgets)的规则。
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
<!--
|
||||
## Protecting an Application with a PodDisruptionBudget
|
||||
|
||||
1. Identify what application you want to protect with a PodDisruptionBudget (PDB).
|
||||
1. Think about how your application reacts to disruptions.
|
||||
1. Create a PDB definition as a YAML file.
|
||||
1. Create the PDB object from the YAML file.
|
||||
-->
|
||||
## 用 PodDisruptionBudget 来保护应用
|
||||
|
||||
1. 确定想要使用 PodDisruptionBudget (PDB) 来保护的应用。
|
||||
1. 考虑应用对干扰的反应。
|
||||
1. 以 YAML 文件形式定义 PDB 。
|
||||
1. 通过 YAML 文件创建 PDB 对象。
|
||||
|
||||
<!-- discussion -->
|
||||
|
||||
<!--
|
||||
## Identify an Application to Protect
|
||||
|
||||
The most common use case when you want to protect an application
|
||||
specified by one of the built-in Kubernetes controllers:
|
||||
-->
|
||||
## 确定要保护的应用
|
||||
|
||||
用户想要保护通过内置的 Kubernetes 控制器指定的应用,这是最常见的使用场景:
|
||||
|
||||
- Deployment
|
||||
- ReplicationController
|
||||
- ReplicaSet
|
||||
- StatefulSet
|
||||
|
||||
<!--
|
||||
In this case, make a note of the controller's `.spec.selector`; the same
|
||||
selector goes into the PDBs `.spec.selector`.
|
||||
-->
|
||||
在这种情况下,在控制器的 `.spec.selector` 字段中做记录,并在 PDB 的
|
||||
`.spec.selector` 字段中加入同样的选择算符。
|
||||
|
||||
<!--
|
||||
From version 1.15 PDBs support custom controllers where the [scale subresource](/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource) is enabled.
|
||||
-->
|
||||
从 1.15 版本开始,PDB 支持启用
|
||||
[scale 子资源](/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource)
|
||||
的自定义控制器。
|
||||
|
||||
<!--
|
||||
You can also use PDBs with pods which are not controlled by one of the above
|
||||
controllers, or arbitrary groups of pods, but there are some restrictions,
|
||||
described in [Arbitrary Controllers and Selectors](#arbitrary-controllers-and-selectors).
|
||||
-->
|
||||
用户也可以用 PDB 来保护不受上述控制器控制的 Pod,或任意的 Pod 集合,但是正如
|
||||
[任意控制器和选择算符](#arbitrary-controllers-and-selectors)中描述的,这里存在一些限制。
|
||||
|
||||
<!--
|
||||
## Think about how your application reacts to disruptions
|
||||
|
||||
Decide how many instances can be down at the same time for a short period
|
||||
due to a voluntary disruption.
|
||||
-->
|
||||
## 考虑应用对干扰的反应
|
||||
|
||||
确定在自发干扰时,多少实例可以在短时间内同时关闭。
|
||||
|
||||
<!--
|
||||
- Stateless frontends:
|
||||
- Concern: don't reduce serving capacity by more than 10%.
|
||||
- Solution: use PDB with minAvailable 90% for example.
|
||||
- Single-instance Stateful Application:
|
||||
- Concern: do not terminate this application without talking to me.
|
||||
- Possible Solution 1: Do not use a PDB and tolerate occasional downtime.
|
||||
- Possible Solution 2: Set PDB with maxUnavailable=0. Have an understanding
|
||||
(outside of Kubernetes) that the cluster operator needs to consult you before
|
||||
termination. When the cluster operator contacts you, prepare for downtime,
|
||||
and then delete the PDB to indicate readiness for disruption. Recreate afterwards.
|
||||
- Multiple-instance Stateful application such as Consul, ZooKeeper, or etcd:
|
||||
- Concern: Do not reduce number of instances below quorum, otherwise writes fail.
|
||||
- Possible Solution 1: set maxUnavailable to 1 (works with varying scale of application).
|
||||
- Possible Solution 2: set minAvailable to quorum-size (e.g. 3 when scale is 5). (Allows more disruptions at once).
|
||||
- Restartable Batch Job:
|
||||
- Concern: Job needs to complete in case of voluntary disruption.
|
||||
- Possible solution: Do not create a PDB. The Job controller will create a replacement pod.
|
||||
-->
|
||||
- 无状态的前端:
|
||||
- 关注:不能降低服务能力 10% 以上。
|
||||
- 解决方案:例如,使用 PDB,指定其 minAvailable 值为 90%。
|
||||
- 单实例有状态应用:
|
||||
- 关注:不要在不通知的情况下终止该应用。
|
||||
- 可能的解决方案 1:不使用 PDB,并忍受偶尔的停机。
|
||||
- 可能的解决方案 2:设置 maxUnavailable=0 的 PDB。
|
||||
意为(Kubernetes 范畴之外的)集群操作人员需要在终止应用前与用户协商,
|
||||
协商后准备停机,然后删除 PDB 表示准备接受干扰,后续再重新创建。
|
||||
- 多实例有状态应用,如 Consul、ZooKeeper 或 etcd:
|
||||
- 关注:不要将实例数量减少至低于仲裁规模,否则将出现写入失败。
|
||||
- 可能的解决方案 1:设置 maxUnavailable 值为 1 (适用于不同规模的应用)。
|
||||
- 可能的解决方案 2:设置 minAvailable 值为仲裁规模(例如规模为 5 时设置为 3)。
|
||||
(允许同时出现更多的干扰)。
|
||||
- 可重新启动的批处理任务:
|
||||
- 关注:自发干扰的情况下,需要确保任务完成。
|
||||
- 可能的解决方案:不创建 PDB。 任务控制器会创建一个替换 Pod。
|
||||
|
||||
<!--
|
||||
### Rounding logic when specifying percentages
|
||||
|
||||
Values for `minAvailable` or `maxUnavailable` can be expressed as integers or as a percentage.
|
||||
-->
|
||||
### 指定百分比时的舍入逻辑
|
||||
|
||||
`minAvailable` 或 `maxUnavailable` 的值可以表示为整数或百分比。
|
||||
|
||||
<!--
|
||||
- When you specify an integer, it represents a number of Pods. For instance, if you set `minAvailable` to 10, then 10
|
||||
Pods must always be available, even during a disruption.
|
||||
- When you specify a percentage by setting the value to a string representation of a percentage (eg. `"50%"`), it represents a percentage of
|
||||
total Pods. For instance, if you set `minUnavailable` to `"50%"`, then only 50% of the Pods can be unavailable during a
|
||||
disruption.
|
||||
-->
|
||||
- 指定整数值时,它表示 Pod 个数。例如,如果将 minAvailable 设置为 10,
|
||||
那么即使在干扰期间,也必须始终有 10 个Pod可用。
|
||||
- 通过将值设置为百分比的字符串表示形式(例如 “50%”)来指定百分比时,它表示占总 Pod 数的百分比。
|
||||
例如,如果将 "minUnavailable" 设置为 “50%”,则干扰期间只允许 50% 的 Pod 不可用。
|
||||
|
||||
<!--
|
||||
When you specify the value as a percentage, it may not map to an exact number
|
||||
of Pods. For example, if you have 7 Pods and you set `minAvailable` to
|
||||
`"50%"`, it's not immediately obvious whether that means 3 Pods or 4 Pods must
|
||||
be available. Kubernetes rounds up to the nearest integer, so in this case, 4
|
||||
Pods must be available. You can examine the
|
||||
[code](https://github.com/kubernetes/kubernetes/blob/23be9587a0f8677eb8091464098881df939c44a9/pkg/controller/disruption/disruption.go#L539)
|
||||
that controls this behavior.
|
||||
-->
|
||||
如果将值指定为百分比,则可能无法映射到确切数量的 Pod。例如,如果你有 7 个 Pod,
|
||||
并且你将 `minAvailable` 设置为 `"50%"`,具体是 3 个 Pod 或 4 个 Pod 必须可用
|
||||
并非显而易见。
|
||||
Kubernetes 采用向上取整到最接近的整数的办法,因此在这种情况下,必须有 4 个 Pod。
|
||||
你可以检查控制此行为的
|
||||
[代码](https://github.com/kubernetes/kubernetes/blob/23be9587a0f8677eb8091464098881df939c44a9/pkg/controller/disruption/disruption.go#L539)。
|
||||
|
||||
<!--
|
||||
## Specifying a PodDisruptionBudget
|
||||
|
||||
A `PodDisruptionBudget` has three fields:
|
||||
-->
|
||||
## 指定 PodDisruptionBudget
|
||||
|
||||
一个 `PodDisruptionBudget` 有 3 个字段:
|
||||
|
||||
<!--
|
||||
* A label selector `.spec.selector` to specify the set of
|
||||
pods to which it applies. This field is required.
|
||||
* `.spec.minAvailable` which is a description of the number of pods from that
|
||||
set that must still be available after the eviction, even in the absence
|
||||
of the evicted pod. `minAvailable` can be either an absolute number or a percentage.
|
||||
* `.spec.maxUnavailable` (available in Kubernetes 1.7 and higher) which is a description
|
||||
of the number of pods from that set that can be unavailable after the eviction.
|
||||
It can be either an absolute number or a percentage.
|
||||
-->
|
||||
* 标签选择算符 `.spec.selector` 用于指定其所作用的 Pod 集合,该字段为必需字段。
|
||||
* `.spec.minAvailable` 表示驱逐后仍须保证可用的 Pod 数量。即使因此影响到 Pod 驱逐
|
||||
(即该条件在和 Pod 驱逐发生冲突时优先保证)。
|
||||
`minAvailable` 值可以是绝对值,也可以是百分比。
|
||||
* `.spec.maxUnavailable` (Kubernetes 1.7 及更高的版本中可用)表示驱逐后允许不可用的
|
||||
Pod 的最大数量。其值可以是绝对值或是百分比。
|
||||
|
||||
{{< note >}}
|
||||
<!--
|
||||
The behavior for an empty selector differs between the policy/v1beta1 and policy/v1 APIs for
|
||||
PodDisruptionBudgets. For policy/v1beta1 an empty selector matches zero pods, while
|
||||
for policy/v1 an empty selector matches every pod in the namespace.
|
||||
-->
|
||||
`policy/v1beta1` 和 `policy/v1` API 中 PodDisruptionBudget 的空选择算符的行为
|
||||
略有不同。在 `policy/v1beta1` 中,空的选择算符不会匹配任何 Pods,而
|
||||
`policy/v1` 中,空的选择算符会匹配名字空间中所有 Pods。
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
You can specify only one of `maxUnavailable` and `minAvailable` in a single `PodDisruptionBudget`.
|
||||
`maxUnavailable` can only be used to control the eviction of pods
|
||||
that have an associated controller managing them. In the examples below, "desired replicas"
|
||||
is the `scale` of the controller managing the pods being selected by the
|
||||
`PodDisruptionBudget`.
|
||||
-->
|
||||
用户在同一个 `PodDisruptionBudget` 中只能够指定 `maxUnavailable` 和 `minAvailable` 中的一个。
|
||||
`maxUnavailable` 只能够用于控制存在相应控制器的 Pod 的驱逐(即不受控制器控制的 Pod 不在
|
||||
`maxUnavailable` 控制范围内)。在下面的示例中,
|
||||
“所需副本” 指的是相应控制器的 `scale`,控制器对 `PodDisruptionBudget` 所选择的 Pod 进行管理。
|
||||
|
||||
<!--
|
||||
Example 1: With a `minAvailable` of 5, evictions are allowed as long as they leave behind
|
||||
5 or more healthy pods among those selected by the PodDisruptionBudget's `selector`.
|
||||
-->
|
||||
示例 1:设置 `minAvailable` 值为 5 的情况下,驱逐时需保证 PodDisruptionBudget 的 `selector`
|
||||
选中的 Pod 中 5 个或 5 个以上处于健康状态。
|
||||
|
||||
<!--
|
||||
Example 2: With a `minAvailable` of 30%, evictions are allowed as long as at least 30%
|
||||
of the number of desired replicas are healthy.
|
||||
-->
|
||||
示例 2:设置 `minAvailable` 值为 30% 的情况下,驱逐时需保证 Pod 所需副本的至少 30% 处于健康状态。
|
||||
|
||||
<!--
|
||||
Example 3: With a `maxUnavailable` of 5, evictions are allowed as long as there are at most 5
|
||||
unhealthy replicas among the total number of desired replicas.
|
||||
-->
|
||||
示例 3:设置 `maxUnavailable` 值为 5 的情况下,驱逐时需保证所需副本中最多 5 个处于不可用状态。
|
||||
|
||||
<!--
|
||||
Example 4: With a `maxUnavailable` of 30%, evictions are allowed as long as no more than 30%
|
||||
of the desired replicas are unhealthy.
|
||||
-->
|
||||
示例 4:设置 `maxUnavailable` 值为 30% 的情况下,驱逐时需保证所需副本中最多 30% 处于不可用状态。
|
||||
|
||||
<!--
|
||||
In typical usage, a single budget would be used for a collection of pods managed by
|
||||
a controller—for example, the pods in a single ReplicaSet or StatefulSet.
|
||||
-->
|
||||
在典型用法中,干扰预算会被用于一个控制器管理的一组 Pod 中 —— 例如:一个 ReplicaSet 或 StatefulSet
|
||||
中的 Pod。
|
||||
|
||||
<!--
|
||||
A disruption budget does not truly guarantee that the specified
|
||||
number/percentage of pods will always be up. For example, a node that hosts a
|
||||
pod from the collection may fail when the collection is at the minimum size
|
||||
specified in the budget, thus bringing the number of available pods from the
|
||||
collection below the specified size. The budget can only protect against
|
||||
voluntary evictions, not all causes of unavailability.
|
||||
-->
|
||||
{{< note >}}
|
||||
干扰预算并不能真正保证指定数量/百分比的 Pod 一直处于运行状态。例如: 当 Pod 集合的
|
||||
规模处于预算指定的最小值时,承载集合中某个 Pod 的节点发生了故障,这样就导致集合中可用 Pod 的
|
||||
数量低于预算指定值。预算只能够针对自发的驱逐提供保护,而不能针对所有 Pod 不可用的诱因。
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
A `maxUnavailable` of 0% (or 0) or a `minAvailable` of 100% (or equal to the
|
||||
number of replicas) may block node drains entirely. This is permitted as per the
|
||||
semantics of `PodDisruptionBudget`.
|
||||
-->
|
||||
设置 `maxUnavailable` 值为 0%(或 0)或设置 `minAvailable` 值为 100%(或等于副本数)
|
||||
可能会阻塞节点,导致资源耗尽。按照 `PodDisruptionBudget` 的语义,这是允许的。
|
||||
|
||||
<!--
|
||||
You can find examples of pod disruption budgets defined below. They match pods with the label
|
||||
`app: zookeeper`.
|
||||
-->
|
||||
用户可以在下面看到 pod 干扰预算定义的示例,它们与带有 `app: zookeeper` 标签的 pod 相匹配:
|
||||
|
||||
<!--
|
||||
Example PDB Using minAvailable:
|
||||
-->
|
||||
使用 minAvailable 的PDB 示例:
|
||||
|
||||
{{< codenew file="policy/zookeeper-pod-disruption-budget-minavailable.yaml" >}}
|
||||
|
||||
<!--
|
||||
Example PDB Using maxUnavailable:
|
||||
-->
|
||||
使用 maxUnavailable 的 PDB 示例:
|
||||
|
||||
{{< codenew file="policy/zookeeper-pod-disruption-budget-maxunavailable.yaml" >}}
|
||||
|
||||
<!--
|
||||
For example, if the above `zk-pdb` object selects the pods of a StatefulSet of size 3, both
|
||||
specifications have the exact same meaning. The use of `maxUnavailable` is recommended as it
|
||||
automatically responds to changes in the number of replicas of the corresponding controller.
|
||||
-->
|
||||
例如,如果上述 `zk-pdb` 选择的是一个规格为 3 的 StatefulSet 对应的 Pod,
|
||||
那么上面两种规范的含义完全相同。
|
||||
推荐使用 `maxUnavailable` ,因为它自动响应控制器副本数量的变化。
|
||||
|
||||
<!--
|
||||
## Create the PDB object
|
||||
|
||||
You can create or update the PDB object using kubectl.
|
||||
```shell
|
||||
kubectl apply -f mypdb.yaml
|
||||
```
|
||||
-->
|
||||
## 创建 PDB 对象
|
||||
|
||||
你可以使用 kubectl 创建或更新 PDB 对象。
|
||||
```shell
|
||||
kubectl apply -f mypdb.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
You cannot update PDB objects. They must be deleted and re-created.
|
||||
-->
|
||||
PDB 对象无法更新,必须删除后重新创建。
|
||||
|
||||
<!--
|
||||
## Check the status of the PDB
|
||||
|
||||
Use kubectl to check that your PDB is created.
|
||||
-->
|
||||
## 检查 PDB 的状态
|
||||
|
||||
使用 kubectl 来确认 PDB 被创建。
|
||||
|
||||
<!--
|
||||
Assuming you don't actually have pods matching `app: zookeeper` in your namespace,
|
||||
then you'll see something like this:
|
||||
-->
|
||||
假设用户的名字空间下没有匹配 `app: zookeeper` 的 Pod,用户会看到类似下面的信息:
|
||||
|
||||
```shell
|
||||
kubectl get poddisruptionbudgets
|
||||
```
|
||||
```
|
||||
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
|
||||
zk-pdb 2 N/A 0 7s
|
||||
```
|
||||
|
||||
<!--
|
||||
If there are matching pods (say, 3), then you would see something like this:
|
||||
-->
|
||||
假设有匹配的 Pod (比如说 3 个), 那么用户会看到类似下面的信息:
|
||||
|
||||
```shell
|
||||
kubectl get poddisruptionbudgets
|
||||
```
|
||||
```
|
||||
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
|
||||
zk-pdb 2 N/A 1 7s
|
||||
|
||||
```
|
||||
|
||||
<!--
|
||||
The non-zero value for `ALLOWED-DISRUPTIONS` means that the disruption controller has seen the pods,
|
||||
counted the matching pods, and updated the status of the PDB.
|
||||
|
||||
You can get more information about the status of a PDB with this command:
|
||||
-->
|
||||
`ALLOWED-DISRUPTIONS` 值非 0 意味着干扰控制器已经感知到相应的 Pod,对匹配的 Pod 进行统计,
|
||||
并更新了 PDB 的状态。
|
||||
|
||||
用户可以通过以下命令获取更多 PDB 状态相关信息:
|
||||
|
||||
```shell
|
||||
kubectl get poddisruptionbudgets zk-pdb -o yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
anntation: {}
|
||||
creationTimestamp: "2020-03-04T04:22:56Z"
|
||||
generation: 1
|
||||
name: zk-pdb
|
||||
…
|
||||
status:
|
||||
currentHealthy: 3
|
||||
desiredHealthy: 2
|
||||
disruptionsAllowed: 1
|
||||
expectedPods: 3
|
||||
observedGeneration: 1
|
||||
```
|
||||
|
||||
<!--
|
||||
## Arbitrary Controllers and Selectors
|
||||
|
||||
You can skip this section if you only use PDBs with the built-in
|
||||
application controllers (Deployment, ReplicationController, ReplicaSet, and StatefulSet),
|
||||
with the PDB selector matching the controller's selector.
|
||||
-->
|
||||
## 任意控制器和选择算符 {#arbitrary-controllers-and-selectors}
|
||||
|
||||
如果你只使用与内置的应用控制器(Deployment、ReplicationController、ReplicaSet 和 StatefulSet)
|
||||
对应的 PDB,也就是 PDB 的选择算符与 控制器的选择算符相匹配,那么可以跳过这一节。
|
||||
|
||||
<!--
|
||||
You can use a PDB with pods controlled by another type of controller, by an
|
||||
"operator", or bare pods, but with these restrictions:
|
||||
-->
|
||||
你可以使用这样的 PDB:它对应的 Pod 可能由其他类型的控制器控制,可能由 "operator" 控制,
|
||||
也可能为“裸的(不受控制器控制)” Pod,但该类 PDB 存在以下限制:
|
||||
|
||||
<!--
|
||||
- only `.spec.minAvailable` can be used, not `.spec.maxUnavailable`.
|
||||
- only an integer value can be used with `.spec.minAvailable`, not a percentage.
|
||||
-->
|
||||
- 只能够使用 `.spec.minAvailable` ,而不能够使用 `.spec.maxUnavailable。`
|
||||
- 只能够使用整数作为 `.spec.minAvailable` 的值,而不能使用百分比。
|
||||
|
||||
<!--
|
||||
You can use a selector which selects a subset or superset of the pods belonging to a built-in
|
||||
controller. However, when there are multiple PDBs in a namespace, you must be careful not
|
||||
to create PDBs whose selectors overlap.
|
||||
-->
|
||||
你可以令选择算符选择一个内置控制器所控制 Pod 的子集或父集。
|
||||
然而,当名字空间下存在多个 PDB 时,用户必须小心,保证 PDB 的选择算符之间不重叠。
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
---
|
||||
title: 删除 StatefulSet
|
||||
content_type: task
|
||||
weight: 60
|
||||
---
|
||||
|
||||
<!--
|
||||
reviewers:
|
||||
- bprashanth
|
||||
- erictune
|
||||
- foxish
|
||||
- janetkuo
|
||||
- smarterclayton
|
||||
title: Delete a StatefulSet
|
||||
content_type: task
|
||||
weight: 60
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
This task shows you how to delete a StatefulSet.
|
||||
-->
|
||||
本任务展示如何删除 StatefulSet。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
<!--
|
||||
* This task assumes you have an application running on your cluster represented by a StatefulSet.
|
||||
-->
|
||||
* 本任务假设在你的集群上已经运行了由 StatefulSet 创建的应用。
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## 删除 StatefulSet {#deleting-a-statefulset}
|
||||
|
||||
<!--
|
||||
You can delete a StatefulSet in the same way you delete other resources in Kubernetes: use the `kubectl delete` command, and specify the StatefulSet either by file or by name.
|
||||
-->
|
||||
你可以像删除 Kubernetes 中的其他资源一样删除 StatefulSet:使用 `kubectl delete` 命令,并按文件或者名字指定 StatefulSet。
|
||||
|
||||
```shell
|
||||
kubectl delete -f <file.yaml>
|
||||
```
|
||||
|
||||
<!--
|
||||
```shell
|
||||
kubectl delete statefulsets <statefulset-name>
|
||||
```
|
||||
-->
|
||||
```shell
|
||||
kubectl delete statefulsets <statefulset 名称>
|
||||
```
|
||||
|
||||
<!--
|
||||
You may need to delete the associated headless service separately after the StatefulSet itself is deleted.
|
||||
|
||||
```shell
|
||||
kubectl delete service <service-name>
|
||||
```
|
||||
-->
|
||||
删除 StatefulSet 之后,你可能需要单独删除关联的无头服务。
|
||||
|
||||
```shell
|
||||
kubectl delete service <服务名称>
|
||||
```
|
||||
|
||||
<!--
|
||||
When deleting a StatefulSet through `kubectl`, the StatefulSet scales down to 0. All Pods that are part of this workload are also deleted. If you want to delete only the StatefulSet and not the Pods, use `--cascade=orphan`.
|
||||
For example:
|
||||
--->
|
||||
当通过 `kubectl` 删除 StatefulSet 时,StatefulSet 会被缩容为 0。
|
||||
属于该 StatefulSet 的所有 Pod 也被删除。
|
||||
如果你只想删除 StatefulSet 而不删除 Pod,使用 `--cascade=orphan`。
|
||||
|
||||
```shell
|
||||
kubectl delete -f <file.yaml> --cascade=orphan
|
||||
```
|
||||
|
||||
<!--
|
||||
By passing `--cascade=orphan` to `kubectl delete`, the Pods managed by the StatefulSet are left behind even after the StatefulSet object itself is deleted. If the pods have a label `app=myapp`, you can then delete them as follows:
|
||||
--->
|
||||
通过将 `--cascade=orphan` 传递给 `kubectl delete`,在删除 StatefulSet 对象之后,
|
||||
StatefulSet 管理的 Pod 会被保留下来。如果 Pod 具有标签 `app=myapp`,则可以按照
|
||||
如下方式删除它们:
|
||||
|
||||
```shell
|
||||
kubectl delete pods -l app=myapp
|
||||
```
|
||||
|
||||
|
||||
<!--
|
||||
### Persistent Volumes
|
||||
|
||||
Deleting the Pods in a StatefulSet will not delete the associated volumes. This is to ensure that you have the chance to copy data off the volume before deleting it. Deleting the PVC after the pods have left the [terminating state](/docs/concepts/workloads/pods/pod/#termination-of-pods) might trigger deletion of the backing Persistent Volumes depending on the storage class and reclaim policy. You should never assume ability to access a volume after claim deletion.
|
||||
-->
|
||||
### 持久卷 {#persistent-volumes}
|
||||
|
||||
删除 StatefulSet 管理的 Pod 并不会删除关联的卷。这是为了确保你有机会在删除卷之前从卷中复制数据。
|
||||
在 Pod 离开[终止状态](/zh/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)
|
||||
后删除 PVC 可能会触发删除背后的 PV 持久卷,具体取决于存储类和回收策略。
|
||||
永远不要假定在 PVC 删除后仍然能够访问卷。
|
||||
|
||||
<!--
|
||||
Use caution when deleting a PVC, as it may lead to data loss.
|
||||
-->
|
||||
{{< note >}}
|
||||
删除 PVC 时要谨慎,因为这可能会导致数据丢失。
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
### Complete deletion of a StatefulSet
|
||||
|
||||
To simply delete everything in a StatefulSet, including the associated pods, you can run a series of commands similar to the following:
|
||||
-->
|
||||
### 完全删除 StatefulSet {#complete-deletion-of-a-statefulset}
|
||||
|
||||
要删除 StatefulSet 中的所有内容,包括关联的 pods,你可以运行
|
||||
一系列如下所示的命令:
|
||||
|
||||
```shell
|
||||
grace=$(kubectl get pods <stateful-set-pod> --template '{{.spec.terminationGracePeriodSeconds}}')
|
||||
kubectl delete statefulset -l app=myapp
|
||||
sleep $grace
|
||||
kubectl delete pvc -l app=myapp
|
||||
```
|
||||
|
||||
<!--
|
||||
In the example above, the Pods have the label `app=myapp`; substitute your own label as appropriate.
|
||||
-->
|
||||
在上面的例子中,Pod 的标签为 `app=myapp`;适当地替换你自己的标签。
|
||||
|
||||
<!--
|
||||
### Force deletion of StatefulSet pods
|
||||
|
||||
If you find that some pods in your StatefulSet are stuck in the 'Terminating' or 'Unknown' states for an extended period of time, you may need to manually intervene to forcefully delete the pods from the apiserver. This is a potentially dangerous task. Refer to [Deleting StatefulSet Pods](/docs/tasks/manage-stateful-set/delete-pods/) for details.
|
||||
-->
|
||||
### 强制删除 StatefulSet 的 Pod
|
||||
|
||||
如果你发现 StatefulSet 的某些 Pod 长时间处于 'Terminating' 或者 'Unknown' 状态,
|
||||
则可能需要手动干预以强制从 API 服务器中删除这些 Pod。
|
||||
这是一项有点危险的任务。详细信息请阅读
|
||||
[删除 StatefulSet 类型的 Pods](/zh/docs/tasks/run-application/force-delete-stateful-set-pod/)。
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
Learn more about [force deleting StatefulSet Pods](/docs/tasks/run-application/force-delete-stateful-set-pod/).
|
||||
-->
|
||||
进一步了解[强制删除 StatefulSet 的 Pods](/zh/docs/tasks/run-application/force-delete-stateful-set-pod/)。
|
||||
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: 强制删除 StatefulSet 中的 Pods
|
||||
content_type: task
|
||||
weight: 70
|
||||
---
|
||||
|
||||
<!--
|
||||
reviewers:
|
||||
- bprashanth
|
||||
- erictune
|
||||
- foxish
|
||||
- smarterclayton
|
||||
title: Force Delete StatefulSet Pods
|
||||
content_type: task
|
||||
weight: 70
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
<!--
|
||||
This page shows how to delete Pods which are part of a {{< glossary_tooltip text="stateful set" term_id="StatefulSet" >}}, and explains the considerations to keep in mind when doing so.
|
||||
-->
|
||||
本文介绍如何删除 {{< glossary_tooltip text="StatefulSet" term_id="StatefulSet" >}}
|
||||
管理的 Pods,并解释这样操作时需要记住的注意事项。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
<!--
|
||||
* This is a fairly advanced task and has the potential to violate some of the properties inherent to StatefulSet.
|
||||
* Before proceeding, make yourself familiar with the considerations enumerated below.
|
||||
-->
|
||||
* 这是一项相当高级的任务,并且可能会违反 StatefulSet 固有的某些属性。
|
||||
* 继续任务之前,请熟悉下面列举的注意事项。
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
<!--
|
||||
## StatefulSet considerations
|
||||
|
||||
In normal operation of a StatefulSet, there is **never** a need to force delete a StatefulSet Pod. The [StatefulSet controller](/docs/concepts/workloads/controllers/statefulset/) is responsible for creating, scaling and deleting members of the StatefulSet. It tries to ensure that the specified number of Pods from ordinal 0 through N-1 are alive and ready. StatefulSet ensures that, at any time, there is at most one Pod with a given identity running in a cluster. This is referred to as *at most one* semantics provided by a StatefulSet.
|
||||
-->
|
||||
## StatefulSet 注意事项
|
||||
|
||||
在 StatefulSet 的正常操作中,**永远不**需要强制删除 StatefulSet 管理的 Pod。
|
||||
[StatefulSet 控制器](/zh/docs/concepts/workloads/controllers/statefulset/)负责创建、
|
||||
扩缩和删除 StatefulSet 管理的 Pods。它尝试确保指定数量的从序数 0 到 N-1 的 Pod
|
||||
处于活跃状态并准备就绪。StatefulSet 确保在任何时候,集群中最多只有一个具有给定标识的 Pod。
|
||||
这就是所谓的由 StatefulSet 提供的*最多一个(At Most One)*的语义。
|
||||
|
||||
<!--
|
||||
Manual force deletion should be undertaken with caution, as it has the potential to violate the at most one semantics inherent to StatefulSet. StatefulSets may be used to run distributed and clustered applications which have a need for a stable network identity and stable storage. These applications often have configuration which relies on an ensemble of a fixed number of members with fixed identities. Having multiple members with the same identity can be disastrous and may lead to data loss (e.g. split brain scenario in quorum-based systems).
|
||||
-->
|
||||
应谨慎进行手动强制删除操作,因为它可能会违反 StatefulSet 固有的至多一个的语义。
|
||||
StatefulSets 可用于运行分布式和集群级的应用,这些应用需要稳定的网络标识和可靠的存储。
|
||||
这些应用通常配置为具有固定标识固定数量的成员集合。
|
||||
具有相同身份的多个成员可能是灾难性的,并且可能导致数据丢失 (例如:票选系统中的脑裂场景)。
|
||||
|
||||
<!--
|
||||
## Delete Pods
|
||||
|
||||
You can perform a graceful pod deletion with the following command:
|
||||
-->
|
||||
## 删除 Pods {#delete-pods}
|
||||
|
||||
你可以使用下面的命令执行体面地删除 Pod:
|
||||
|
||||
```shell
|
||||
kubectl delete pods <pod>
|
||||
```
|
||||
|
||||
<!--
|
||||
For the above to lead to graceful termination, the Pod **must not** specify a `pod.Spec.TerminationGracePeriodSeconds` of 0. The practice of setting a `pod.Spec.TerminationGracePeriodSeconds` of 0 seconds is unsafe and strongly discouraged for StatefulSet Pods. Graceful deletion is safe and will ensure that the [Pod shuts down gracefully](/docs/user-guide/pods/#termination-of-pods) before the kubelet deletes the name from the apiserver.
|
||||
-->
|
||||
为了让上面操作能够体面地终止 Pod,Pod **一定不能** 设置 `pod.Spec.TerminationGracePeriodSeconds` 为 0。
|
||||
将 `pod.Spec.TerminationGracePeriodSeconds` 设置为 0s 的做法是不安全的,强烈建议 StatefulSet 类型的
|
||||
Pod 不要使用。体面删除是安全的,并且会在 kubelet 从 API 服务器中删除资源名称之前确保
|
||||
[体面地结束 pod ](/zh/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)。
|
||||
|
||||
<!--
|
||||
A Pod is not deleted automatically when a Node is unreachable.
|
||||
The Pods running on an unreachable Node enter the 'Terminating' or 'Unknown' state after a
|
||||
[timeout](/docs/concepts/architecture/nodes/#condition).
|
||||
Pods may also enter these states when the user attempts graceful deletion of a Pod
|
||||
on an unreachable Node.
|
||||
The only ways in which a Pod in such a state can be removed from the apiserver are as follows:
|
||||
-->
|
||||
当某个节点不可达时,不会引发自动删除 Pod。
|
||||
在无法访问的节点上运行的 Pod 在
|
||||
[超时](/zh/docs/concepts/architecture/nodes/#condition)
|
||||
后会进入'Terminating' 或者 'Unknown' 状态。
|
||||
当用户尝试体面地删除无法访问的节点上的 Pod 时 Pod 也可能会进入这些状态。
|
||||
从 API 服务器上删除处于这些状态 Pod 的仅有可行方法如下:
|
||||
|
||||
<!--
|
||||
* The Node object is deleted (either by you, or by the [Node Controller](/docs/admin/node)).<br/>
|
||||
* The kubelet on the unresponsive Node starts responding, kills the Pod and removes the entry from the apiserver.<br/>
|
||||
* Force deletion of the Pod by the user.
|
||||
-->
|
||||
* 删除 Node 对象(要么你来删除, 要么[节点控制器](/zh/docs/concepts/architecture/nodes/#node-controller)
|
||||
来删除)
|
||||
* 无响应节点上的 kubelet 开始响应,杀死 Pod 并从 API 服务器上移除 Pod 对象
|
||||
* 用户强制删除 pod
|
||||
|
||||
<!--
|
||||
The recommended best practice is to use the first or second approach. If a Node is confirmed to be dead (e.g. permanently disconnected from the network, powered down, etc), then delete the Node object. If the Node is suffering from a network partition, then try to resolve this or wait for it to resolve. When the partition heals, the kubelet will complete the deletion of the Pod and free up its name in the apiserver.
|
||||
-->
|
||||
推荐使用第一种或者第二种方法。如果确认节点已经不可用了 (比如,永久断开网络、断电等),
|
||||
则应删除 Node 对象。
|
||||
如果节点遇到网裂问题,请尝试解决该问题或者等待其解决。
|
||||
当网裂愈合时,kubelet 将完成 Pod 的删除并从 API 服务器上释放其名字。
|
||||
|
||||
<!--
|
||||
Normally, the system completes the deletion once the Pod is no longer running on a Node, or the Node is deleted by an administrator. You may override this by force deleting the Pod.
|
||||
-->
|
||||
通常,Pod 一旦不在节点上运行,或者管理员删除了节点,系统就会完成其删除动作。
|
||||
你也可以通过强制删除 Pod 来绕过这一机制。
|
||||
|
||||
<!--
|
||||
### Force Deletion
|
||||
|
||||
Force deletions **do not** wait for confirmation from the kubelet that the Pod has been terminated. Irrespective of whether a force deletion is successful in killing a Pod, it will immediately free up the name from the apiserver. This would let the StatefulSet controller create a replacement Pod with that same identity; this can lead to the duplication of a still-running Pod, and if said Pod can still communicate with the other members of the StatefulSet, will violate the at most one semantics that StatefulSet is designed to guarantee.
|
||||
-->
|
||||
### 强制删除 {#force-deletion}
|
||||
|
||||
强制删除**不会**等待来自 kubelet 对 Pod 已终止的确认消息。
|
||||
无论强制删除是否成功杀死了 Pod,它都会立即从 API 服务器中释放该名字。
|
||||
这将让 StatefulSet 控制器创建一个具有相同标识的替身 Pod;因而可能导致正在运行 Pod 的重复,
|
||||
并且如果所述 Pod 仍然可以与 StatefulSet 的成员通信,则将违反 StatefulSet 所要保证的
|
||||
最多一个的语义。
|
||||
|
||||
<!--
|
||||
When you force delete a StatefulSet pod, you are asserting that the Pod in question will never again make contact with other Pods in the StatefulSet and its name can be safely freed up for a replacement to be created.
|
||||
-->
|
||||
当你强制删除 StatefulSet 类型的 Pod 时,你要确保有问题的 Pod 不会再和 StatefulSet 管理的其他
|
||||
Pod 通信并且可以安全地释放其名字以便创建替代 Pod。
|
||||
|
||||
<!--
|
||||
If you want to delete a Pod forcibly using kubectl version >= 1.5, do the following:
|
||||
-->
|
||||
如果要使用 kubectl 1.5 以上版本强制删除 Pod,请执行下面命令:
|
||||
|
||||
```shell
|
||||
kubectl delete pods <pod> --grace-period=0 --force
|
||||
```
|
||||
|
||||
<!--
|
||||
If you're using any version of kubectl <= 1.4, you should omit the `--force` option and use:
|
||||
-->
|
||||
如果你使用 kubectl 的 1.4 以下版本,则应省略 `--force` 选项:
|
||||
|
||||
```shell
|
||||
kubectl delete pods <pod> --grace-period=0
|
||||
```
|
||||
|
||||
<!--
|
||||
If even after these commands the pod is stuck on `Unknown` state, use the following command to remove the pod from the cluster:
|
||||
-->
|
||||
如果在这些命令后 Pod 仍处于 `Unknown` 状态,请使用以下命令从集群中删除 Pod:
|
||||
|
||||
```shell
|
||||
kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
|
||||
```
|
||||
|
||||
<!--
|
||||
Always perform force deletion of StatefulSet Pods carefully and with complete knowledge of the risks involved.
|
||||
-->
|
||||
请始终谨慎地执行强制删除 StatefulSet 类型的 pods,并完全了解所涉及地风险。
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
Learn more about [debugging a StatefulSet](/docs/tasks/debug/debug-application/debug-statefulset/).
|
||||
-->
|
||||
进一步了解[调试 StatefulSet](/zh/docs/tasks/debug/debug-application/debug-statefulset/)。
|
||||
|
||||
|
||||
@@ -0,0 +1,820 @@
|
||||
---
|
||||
title: HorizontalPodAutoscaler 演练
|
||||
content_type: task
|
||||
weight: 100
|
||||
min-kubernetes-server-version: 1.23
|
||||
---
|
||||
|
||||
<!--
|
||||
reviewers:
|
||||
- fgrzadkowski
|
||||
- jszczepkowski
|
||||
- justinsb
|
||||
- directxman12
|
||||
title: Horizontal Pod Autoscaler Walkthrough
|
||||
content_type: task
|
||||
weight: 100
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
A [HorizontalPodAutoscaler](/docs/tasks/run-application/horizontal-pod-autoscale/)
|
||||
(HPA for short)
|
||||
automatically updates a workload resource (such as
|
||||
a {{< glossary_tooltip text="Deployment" term_id="deployment" >}} or
|
||||
{{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}}), with the
|
||||
aim of automatically scaling the workload to match demand.
|
||||
|
||||
Horizontal scaling means that the response to increased load is to deploy more
|
||||
{{< glossary_tooltip text="Pods" term_id="pod" >}}.
|
||||
This is different from _vertical_ scaling, which for Kubernetes would mean
|
||||
assigning more resources (for example: memory or CPU) to the Pods that are already
|
||||
running for the workload.
|
||||
-->
|
||||
[HorizontalPodAutoscaler](/zh/docs/tasks/run-application/horizontal-pod-autoscale/) (简称 HPA )
|
||||
自动更新工作负载资源(例如 {{< glossary_tooltip text="Deployment" term_id="deployment" >}} 或者
|
||||
{{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}}),
|
||||
目的是自动扩缩工作负载以满足需求。
|
||||
|
||||
水平扩缩意味着对增加的负载的响应是部署更多的 {{< glossary_tooltip text="Pods" term_id="pod" >}}。
|
||||
这与 “垂直(Vertical)” 扩缩不同,对于 Kubernetes,
|
||||
垂直扩缩意味着将更多资源(例如:内存或 CPU)分配给已经为工作负载运行的 Pod。
|
||||
|
||||
<!--
|
||||
If the load decreases, and the number of Pods is above the configured minimum,
|
||||
the HorizontalPodAutoscaler instructs the workload resource (the Deployment, StatefulSet,
|
||||
or other similar resource) to scale back down.
|
||||
|
||||
This document walks you through an example of enabling HorizontalPodAutoscaler to
|
||||
automatically manage scale for an example web app. This example workload is Apache
|
||||
httpd running some PHP code.
|
||||
-->
|
||||
如果负载减少,并且 Pod 的数量高于配置的最小值,
|
||||
HorizontalPodAutoscaler 会指示工作负载资源( Deployment、StatefulSet 或其他类似资源)缩减。
|
||||
|
||||
本文档将引导你完成启用 HorizontalPodAutoscaler 以自动管理示例 Web 应用程序的扩缩的示例。
|
||||
此示例工作负载是运行一些 PHP 代码的 Apache httpd。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
<!--
|
||||
If you're running an older
|
||||
release of Kubernetes, refer to the version of the documentation for that release (see
|
||||
[available documentation versions](/docs/home/supported-doc-versions/)).
|
||||
-->
|
||||
如果你运行的是旧版本的 Kubernetes,请参阅该版本的文档版本
|
||||
([可用的文档版本](/zh/docs/home/supported-doc-versions/))。
|
||||
|
||||
<!--
|
||||
To follow this walkthrough, you also need to use a cluster that has a
|
||||
[Metrics Server](https://github.com/kubernetes-sigs/metrics-server#readme) deployed and configured.
|
||||
The Kubernetes Metrics Server collects resource metrics from
|
||||
the {{<glossary_tooltip term_id="kubelet" text="kubelets">}} in your cluster, and exposes those metrics
|
||||
through the [Kubernetes API](/docs/concepts/overview/kubernetes-api/),
|
||||
using an [APIService](/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) to add
|
||||
new kinds of resource that represent metric readings.
|
||||
|
||||
To learn how to deploy the Metrics Server, see the
|
||||
[metrics-server documentation](https://github.com/kubernetes-sigs/metrics-server#deployment).
|
||||
-->
|
||||
按照本演练进行操作,你需要一个部署并配置了
|
||||
[Metrics Server](https://github.com/kubernetes-sigs/metrics-server#readme) 的集群。
|
||||
Kubernetes Metrics Server 从集群中的 {{<glossary_tooltip term_id="kubelet" text="kubelets">}} 收集资源指标,
|
||||
并通过 [Kubernetes API](/zh/docs/concepts/overview/kubernetes-api/) 公开这些指标,
|
||||
使用 [APIService](/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) 添加代表指标读数的新资源。
|
||||
|
||||
要了解如何部署 Metrics Server,请参阅
|
||||
[metrics-server 文档](https://github.com/kubernetes-sigs/metrics-server#deployment)。
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
<!--
|
||||
## Run and expose php-apache server
|
||||
-->
|
||||
## 运行 php-apache 服务器并暴露服务 {#run-and-expose-php-apache-server}
|
||||
|
||||
<!--
|
||||
To demonstrate a HorizontalPodAutoscaler, you will first make a custom container image that uses
|
||||
the `php-apache` image from Docker Hub as its starting point. The `Dockerfile` is ready-made for you,
|
||||
and has the following content:
|
||||
-->
|
||||
为了演示 HorizontalPodAutoscaler,你将首先制作一个自定义容器镜像,
|
||||
该镜像使用来自 Docker Hub 的 `php-apache` 镜像作为其起点。
|
||||
`Dockerfile` 已经为你准备好了,内容如下:
|
||||
|
||||
```dockerfile
|
||||
FROM php:5-apache
|
||||
COPY index.php /var/www/html/index.php
|
||||
RUN chmod a+rx index.php
|
||||
```
|
||||
|
||||
<!--
|
||||
This code defines a simple `index.php` page that performs some CPU intensive computations,
|
||||
in order to simulate load in your cluster.
|
||||
-->
|
||||
代码定义了一个简单的 `index.php` 页面,该页面执行一些 CPU 密集型计算,
|
||||
以模拟集群中的负载。
|
||||
|
||||
```php
|
||||
<?php
|
||||
$x = 0.0001;
|
||||
for ($i = 0; $i <= 1000000; $i++) {
|
||||
$x += sqrt($x);
|
||||
}
|
||||
echo "OK!";
|
||||
?>
|
||||
```
|
||||
|
||||
<!--
|
||||
Once you have made that container image, start a Deployment that runs a container using the
|
||||
image you made, and expose it as a {{< glossary_tooltip term_id="service">}}
|
||||
using the following manifest:
|
||||
-->
|
||||
制作完该容器镜像后,使用你制作的镜像启动运行一个容器的 Deployment,
|
||||
并使用以下清单将其公开为{{< glossary_tooltip term_id="service" text="服务" >}}:
|
||||
|
||||
{{< codenew file="application/php-apache.yaml" >}}
|
||||
|
||||
<!--
|
||||
To do so, run the following command:
|
||||
-->
|
||||
为此,运行下面的命令:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
|
||||
```
|
||||
|
||||
```
|
||||
deployment.apps/php-apache created
|
||||
service/php-apache created
|
||||
```
|
||||
|
||||
<!--
|
||||
## Create the HorizontalPodAutoscaler {#create-horizontal-pod-autoscaler}
|
||||
|
||||
Now that the server is running, create the autoscaler using `kubectl`. There is
|
||||
[`kubectl autoscale`](/docs/reference/generated/kubectl/kubectl-commands#autoscale) subcommand,
|
||||
part of `kubectl`, that helps you do this.
|
||||
|
||||
You will shortly run a command that creates a HorizontalPodAutoscaler that maintains
|
||||
between 1 and 10 replicas of the Pods controlled by the php-apache Deployment that
|
||||
you created in the first step of these instructions.
|
||||
|
||||
Roughly speaking, the HPA {{<glossary_tooltip text="controller" term_id="controller">}} will increase and decrease
|
||||
the number of replicas (by updating the Deployment) to maintain an average CPU utilization across all Pods of 50%.
|
||||
The Deployment then updates the ReplicaSet - this is part of how all Deployments work in Kubernetes -
|
||||
and then the ReplicaSet either adds or removes Pods based on the change to its `.spec`.
|
||||
|
||||
Since each pod requests 200 milli-cores by `kubectl run`, this means an average CPU usage of 100 milli-cores.
|
||||
See [Algorithm details](/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details) for more details
|
||||
on the algorithm.
|
||||
-->
|
||||
## 创建 HorizontalPodAutoscaler {#create-horizontal-pod-autoscaler}
|
||||
|
||||
现在服务器正在运行,使用 `kubectl` 创建自动扩缩器。
|
||||
[`kubectl autoscale`](/zh/docs/reference/generated/kubectl/kubectl-commands#autoscale) 子命令是 `kubectl` 的一部分,
|
||||
可以帮助你执行此操作。
|
||||
|
||||
你将很快运行一个创建 HorizontalPodAutoscaler 的命令,
|
||||
该 HorizontalPodAutoscaler 维护由你在这些说明的第一步中创建的 php-apache Deployment 控制的 Pod 存在 1 到 10 个副本。
|
||||
|
||||
粗略地说,HPA {{<glossary_tooltip text="控制器" term_id="controller">}}将增加和减少副本的数量
|
||||
(通过更新 Deployment)以保持所有 Pod 的平均 CPU 利用率为 50%。
|
||||
Deployment 然后更新 ReplicaSet —— 这是所有 Deployment 在 Kubernetes 中工作方式的一部分 ——
|
||||
然后 ReplicaSet 根据其 `.spec` 的更改添加或删除 Pod。
|
||||
|
||||
由于每个 Pod 通过 `kubectl run` 请求 200 milli-cores,这意味着平均 CPU 使用率为 100 milli-cores。
|
||||
有关算法的更多详细信息,
|
||||
请参阅[算法详细信息](/zh/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details)。
|
||||
|
||||
|
||||
<!-- Create the HorizontalPodAutoscaler: -->
|
||||
创建 HorizontalPodAutoscaler:
|
||||
|
||||
```shell
|
||||
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
|
||||
```
|
||||
|
||||
```
|
||||
horizontalpodautoscaler.autoscaling/php-apache autoscaled
|
||||
```
|
||||
|
||||
<!--
|
||||
You can check the current status of the newly-made HorizontalPodAutoscaler, by running:
|
||||
-->
|
||||
你可以通过运行以下命令检查新制作的 HorizontalPodAutoscaler 的当前状态:
|
||||
|
||||
<!--# You can use "hpa" or "horizontalpodautoscaler"; either name works OK. -->
|
||||
```shell
|
||||
# 你可以使用 “hap” 或 “horizontalpodautoscaler”;任何一个名字都可以。
|
||||
kubectl get hpa
|
||||
```
|
||||
|
||||
<!-- The output is similar to: -->
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
|
||||
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 18s
|
||||
|
||||
```
|
||||
|
||||
<!--
|
||||
(if you see other HorizontalPodAutoscalers with different names, that means they already existed,
|
||||
and isn't usually a problem).
|
||||
-->
|
||||
(如果你看到其他具有不同名称的 HorizontalPodAutoscalers,这意味着它们已经存在,这通常不是问题)。
|
||||
|
||||
<!--
|
||||
Please note that the current CPU consumption is 0% as there are no clients sending requests to the server
|
||||
(the ``TARGET`` column shows the average across all the Pods controlled by the corresponding deployment).
|
||||
-->
|
||||
请注意当前的 CPU 利用率是 0%,这是由于我们尚未发送任何请求到服务器
|
||||
(``TARGET`` 列显示了相应 Deployment 所控制的所有 Pod 的平均 CPU 利用率)。
|
||||
|
||||
<!--
|
||||
## Increase the load {#increase-load}
|
||||
|
||||
Next, see how the autoscaler reacts to increased load.
|
||||
To do this, you'll start a different Pod to act as a client. The container within the client Pod
|
||||
runs in an infinite loop, sending queries to the php-apache service.
|
||||
-->
|
||||
## 增加负载 {#increase-load}
|
||||
|
||||
接下来,看看自动扩缩器如何对增加的负载做出反应。
|
||||
为此,你将启动一个不同的 Pod 作为客户端。
|
||||
客户端 Pod 中的容器在无限循环中运行,向 php-apache 服务发送查询。
|
||||
|
||||
<!--
|
||||
# Run this in a separate terminal
|
||||
# so that the load generation continues and you can carry on with the rest of the steps
|
||||
-->
|
||||
```shell
|
||||
# 在单独的终端中运行它
|
||||
# 以便负载生成继续,你可以继续执行其余步骤
|
||||
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
|
||||
```
|
||||
|
||||
<!--
|
||||
Now run:
|
||||
|
||||
Within a minute or so, you should see the higher CPU load; for example:
|
||||
-->
|
||||
现在执行:
|
||||
|
||||
<!-- # type Ctrl+C to end the watch when you're ready -->
|
||||
```shell
|
||||
# 准备好后按 Ctrl+C 结束观察
|
||||
kubectl get hpa php-apache --watch
|
||||
```
|
||||
|
||||
一分钟时间左右之后,通过以下命令,我们可以看到 CPU 负载升高了;例如:
|
||||
|
||||
```
|
||||
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
|
||||
php-apache Deployment/php-apache/scale 305% / 50% 1 10 1 3m
|
||||
```
|
||||
|
||||
<!--
|
||||
and then, more replicas. For example:
|
||||
-->
|
||||
然后,更多的副本被创建。例如:
|
||||
|
||||
```
|
||||
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
|
||||
php-apache Deployment/php-apache/scale 305% / 50% 1 10 7 3m
|
||||
```
|
||||
|
||||
<!--
|
||||
Here, CPU consumption has increased to 305% of the request.
|
||||
As a result, the deployment was resized to 7 replicas:
|
||||
-->
|
||||
这时,由于请求增多,CPU 利用率已经升至请求值的 305%。
|
||||
可以看到,Deployment 的副本数量已经增长到了 7:
|
||||
|
||||
```shell
|
||||
kubectl get deployment php-apache
|
||||
```
|
||||
|
||||
<!--
|
||||
You should see the replica count matching the figure from the HorizontalPodAutoscaler
|
||||
-->
|
||||
你应该会看到与 HorizontalPodAutoscaler 中的数字与副本数匹配
|
||||
|
||||
```
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
php-apache 7/7 7 7 19m
|
||||
```
|
||||
|
||||
<!--
|
||||
It may take a few minutes to stabilize the number of replicas. Since the amount
|
||||
of load is not controlled in any way it may happen that the final number of replicas
|
||||
will differ from this example.
|
||||
-->
|
||||
{{< note >}}
|
||||
有时最终副本的数量可能需要几分钟才能稳定下来。由于环境的差异,
|
||||
不同环境中最终的副本数量可能与本示例中的数量不同。
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
## Stop generating load {#stop-load}
|
||||
|
||||
To finish the example, stop sending the load.
|
||||
|
||||
In the terminal where you created the Pod that runs a `busybox` image, terminate
|
||||
the load generation by typing `<Ctrl> + C`.
|
||||
|
||||
Then verify the result state (after a minute or so):
|
||||
-->
|
||||
## 停止产生负载 {#stop-load}
|
||||
|
||||
要完成该示例,请停止发送负载。
|
||||
|
||||
在我们创建 `busybox` 容器的终端中,输入 `<Ctrl> + C` 来终止负载的产生。
|
||||
|
||||
然后验证结果状态(大约一分钟后):
|
||||
|
||||
<!-- # type Ctrl+C to end the watch when you're ready -->
|
||||
```shell
|
||||
# 准备好后按 Ctrl+C 结束观察
|
||||
kubectl get hpa php-apache --watch
|
||||
```
|
||||
|
||||
<!-- The output is similar to: -->
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
|
||||
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 11m
|
||||
```
|
||||
|
||||
<!-- and the Deployment also shows that it has scaled down: -->
|
||||
Deployment 也显示它已经缩小了:
|
||||
|
||||
```shell
|
||||
kubectl get deployment php-apache
|
||||
```
|
||||
|
||||
```
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
php-apache 1/1 1 1 27m
|
||||
```
|
||||
|
||||
<!--
|
||||
Once CPU utilization dropped to 0, the HPA automatically scaled the number of replicas back down to 1.
|
||||
-->
|
||||
一旦 CPU 利用率降至 0,HPA 会自动将副本数缩减为 1。
|
||||
|
||||
<!--
|
||||
Autoscaling the replicas may take a few minutes.
|
||||
-->
|
||||
自动扩缩完成副本数量的改变可能需要几分钟的时间。
|
||||
|
||||
<!-- discussion -->
|
||||
|
||||
<!--
|
||||
## Autoscaling on multiple metrics and custom metrics
|
||||
|
||||
You can introduce additional metrics to use when autoscaling the `php-apache` Deployment
|
||||
by making use of the `autoscaling/v2` API version.
|
||||
-->
|
||||
## 基于多项度量指标和自定义度量指标自动扩缩 {#autoscaling-on-multiple-metrics-and-custom-metrics}
|
||||
|
||||
利用 `autoscaling/v2` API 版本,你可以在自动扩缩 php-apache 这个
|
||||
Deployment 时使用其他度量指标。
|
||||
|
||||
<!--
|
||||
First, get the YAML of your HorizontalPodAutoscaler in the `autoscaling/v2` form:
|
||||
-->
|
||||
首先,将 HorizontalPodAutoscaler 的 YAML 文件改为 `autoscaling/v2` 格式:
|
||||
|
||||
```shell
|
||||
kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
Open the `/tmp/hpa-v2.yaml` file in an editor, and you should see YAML which looks like this:
|
||||
-->
|
||||
在编辑器中打开 `/tmp/hpa-v2.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: php-apache
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: php-apache
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 50
|
||||
status:
|
||||
observedGeneration: 1
|
||||
lastScaleTime: <some-time>
|
||||
currentReplicas: 1
|
||||
desiredReplicas: 1
|
||||
currentMetrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
current:
|
||||
averageUtilization: 0
|
||||
averageValue: 0
|
||||
```
|
||||
|
||||
<!--
|
||||
Notice that the `targetCPUUtilizationPercentage` field has been replaced with an array called `metrics`.
|
||||
The CPU utilization metric is a *resource metric*, since it is represented as a percentage of a resource
|
||||
specified on pod containers. Notice that you can specify other resource metrics besides CPU. By default,
|
||||
the only other supported resource metric is memory. These resources do not change names from cluster
|
||||
to cluster, and should always be available, as long as the `metrics.k8s.io` API is available.
|
||||
-->
|
||||
需要注意的是,`targetCPUUtilizationPercentage` 字段已经被名为 `metrics` 的数组所取代。
|
||||
CPU 利用率这个度量指标是一个 *resource metric*(资源度量指标),因为它表示容器上指定资源的百分比。
|
||||
除 CPU 外,你还可以指定其他资源度量指标。默认情况下,目前唯一支持的其他资源度量指标为内存。
|
||||
只要 `metrics.k8s.io` API 存在,这些资源度量指标就是可用的,并且他们不会在不同的 Kubernetes 集群中改变名称。
|
||||
|
||||
<!--
|
||||
You can also specify resource metrics in terms of direct values, instead of as percentages of the
|
||||
requested value, by using a `target.type` of `AverageValue` instead of `Utilization`, and
|
||||
setting the corresponding `target.averageValue` field instead of the `target.averageUtilization`.
|
||||
-->
|
||||
你还可以指定资源度量指标使用绝对数值,而不是百分比,你需要将 `target.type` 从
|
||||
`Utilization` 替换成 `AverageValue`,同时设置 `target.averageValue`
|
||||
而非 `target.averageUtilization` 的值。
|
||||
|
||||
<!--
|
||||
There are two other types of metrics, both of which are considered *custom metrics*: pod metrics and
|
||||
object metrics. These metrics may have names which are cluster specific, and require a more
|
||||
advanced cluster monitoring setup.
|
||||
-->
|
||||
还有两种其他类型的度量指标,他们被认为是 *custom metrics*(自定义度量指标):
|
||||
即 Pod 度量指标和 Object 度量指标。
|
||||
这些度量指标可能具有特定于集群的名称,并且需要更高级的集群监控设置。
|
||||
|
||||
<!--
|
||||
The first of these alternative metric types is *pod metrics*. These metrics describe Pods, and
|
||||
are averaged together across Pods and compared with a target value to determine the replica count.
|
||||
They work much like resource metrics, except that they *only* support a `target` type of `AverageValue`.
|
||||
-->
|
||||
第一种可选的度量指标类型是 **Pod 度量指标**。这些指标从某一方面描述了 Pod,
|
||||
在不同 Pod 之间进行平均,并通过与一个目标值比对来确定副本的数量。
|
||||
它们的工作方式与资源度量指标非常相像,只是它们 **仅** 支持 `target` 类型为 `AverageValue`。
|
||||
|
||||
<!--
|
||||
Pod metrics are specified using a metric block like this:
|
||||
-->
|
||||
pod 度量指标通过如下代码块定义:
|
||||
|
||||
```yaml
|
||||
type: Pods
|
||||
pods:
|
||||
metric:
|
||||
name: packets-per-second
|
||||
target:
|
||||
type: AverageValue
|
||||
averageValue: 1k
|
||||
```
|
||||
|
||||
<!--
|
||||
The second alternative metric type is *object metrics*. These metrics describe a different
|
||||
object in the same namespace, instead of describing Pods. The metrics are not necessarily
|
||||
fetched from the object; they only describe it. Object metrics support `target` types of
|
||||
both `Value` and `AverageValue`. With `Value`, the target is compared directly to the returned
|
||||
metric from the API. With `AverageValue`, the value returned from the custom metrics API is divided
|
||||
by the number of Pods before being compared to the target. The following example is the YAML
|
||||
representation of the `requests-per-second` metric.
|
||||
-->
|
||||
第二种可选的度量指标类型是对象 **(Object)度量指标**。这些度量指标用于描述
|
||||
在相同名字空间中的别的对象,而非 Pods。
|
||||
请注意这些度量指标不一定来自某对象,它们仅用于描述这些对象。
|
||||
对象度量指标支持的 `target` 类型包括 `Value` 和 `AverageValue`。
|
||||
如果是 `Value` 类型,`target` 值将直接与 API 返回的度量指标比较,
|
||||
而对于 `AverageValue` 类型,API 返回的度量值将按照 Pod 数量拆分,
|
||||
然后再与 `target` 值比较。
|
||||
下面的 YAML 文件展示了一个表示 `requests-per-second` 的度量指标。
|
||||
|
||||
```yaml
|
||||
type: Object
|
||||
object:
|
||||
metric:
|
||||
name: requests-per-second
|
||||
describedObject:
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
name: main-route
|
||||
target:
|
||||
type: Value
|
||||
value: 2k
|
||||
```
|
||||
|
||||
<!--
|
||||
If you provide multiple such metric blocks, the HorizontalPodAutoscaler will consider each metric in turn.
|
||||
The HorizontalPodAutoscaler will calculate proposed replica counts for each metric, and then choose the
|
||||
one with the highest replica count.
|
||||
-->
|
||||
如果你指定了多个上述类型的度量指标,HorizontalPodAutoscaler 将会依次考量各个指标。
|
||||
HorizontalPodAutoscaler 将会计算每一个指标所提议的副本数量,然后最终选择一个最高值。
|
||||
|
||||
<!--
|
||||
For example, if you had your monitoring system collecting metrics about network traffic,
|
||||
you could update the definition above using `kubectl edit` to look like this:
|
||||
-->
|
||||
比如,如果你的监控系统能够提供网络流量数据,你可以通过 `kubectl edit` 命令
|
||||
将上述 Horizontal Pod Autoscaler 的定义更改为:
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: php-apache
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: php-apache
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 50
|
||||
- type: Pods
|
||||
pods:
|
||||
metric:
|
||||
name: packets-per-second
|
||||
target:
|
||||
type: AverageValue
|
||||
averageValue: 1k
|
||||
- type: Object
|
||||
object:
|
||||
metric:
|
||||
name: requests-per-second
|
||||
describedObject:
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
name: main-route
|
||||
target:
|
||||
type: Value
|
||||
value: 10k
|
||||
status:
|
||||
observedGeneration: 1
|
||||
lastScaleTime: <some-time>
|
||||
currentReplicas: 1
|
||||
desiredReplicas: 1
|
||||
currentMetrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
current:
|
||||
averageUtilization: 0
|
||||
averageValue: 0
|
||||
- type: Object
|
||||
object:
|
||||
metric:
|
||||
name: requests-per-second
|
||||
describedObject:
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
name: main-route
|
||||
current:
|
||||
value: 10k
|
||||
```
|
||||
|
||||
<!--
|
||||
Then, your HorizontalPodAutoscaler would attempt to ensure that each pod was consuming roughly
|
||||
50% of its requested CPU, serving 1000 packets per second, and that all pods behind the main-route
|
||||
Ingress were serving a total of 10000 requests per second.
|
||||
-->
|
||||
这样,你的 HorizontalPodAutoscaler 将会尝试确保每个 Pod 的 CPU 利用率在 50% 以内,
|
||||
每秒能够服务 1000 个数据包请求,
|
||||
并确保所有在 Ingress 后的 Pod 每秒能够服务的请求总数达到 10000 个。
|
||||
|
||||
<!--
|
||||
### Autoscaling on more specific metrics
|
||||
|
||||
Many metrics pipelines allow you to describe metrics either by name or by a set of additional
|
||||
descriptors called _labels_. For all non-resource metric types (pod, object, and external,
|
||||
described below), you can specify an additional label selector which is passed to your metric
|
||||
pipeline. For instance, if you collect a metric `http_requests` with the `verb`
|
||||
label, you can specify the following metric block to scale only on GET requests:
|
||||
-->
|
||||
### 基于更特别的度量值来扩缩 {#autoscaing-on-more-specific-metrics}
|
||||
|
||||
许多度量流水线允许你通过名称或附加的 _标签_ 来描述度量指标。
|
||||
对于所有非资源类型度量指标(Pod、Object 和后面将介绍的 External),
|
||||
可以额外指定一个标签选择算符。例如,如果你希望收集包含 `verb` 标签的
|
||||
`http_requests` 度量指标,可以按如下所示设置度量指标块,使得扩缩操作仅针对
|
||||
GET 请求执行:
|
||||
|
||||
```yaml
|
||||
type: Object
|
||||
object:
|
||||
metric:
|
||||
name: http_requests
|
||||
selector: {matchLabels: {verb: GET}}
|
||||
```
|
||||
|
||||
<!--
|
||||
This selector uses the same syntax as the full Kubernetes label selectors. The monitoring pipeline
|
||||
determines how to collapse multiple series into a single value, if the name and selector
|
||||
match multiple series. The selector is additive, and cannot select metrics
|
||||
that describe objects that are **not** the target object (the target pods in the case of the `Pods`
|
||||
type, and the described object in the case of the `Object` type).
|
||||
-->
|
||||
这个选择算符使用与 Kubernetes 标签选择算符相同的语法。
|
||||
如果名称和标签选择算符匹配到多个系列,监测管道会决定如何将多个系列合并成单个值。
|
||||
选择算符是可以累加的,它不会选择目标以外的对象(类型为 `Pods` 的目标 Pods 或者
|
||||
类型为 `Object` 的目标对象)。
|
||||
|
||||
<!--
|
||||
### Autoscaling on metrics not related to Kubernetes objects
|
||||
|
||||
Applications running on Kubernetes may need to autoscale based on metrics that don't have an obvious
|
||||
relationship to any object in the Kubernetes cluster, such as metrics describing a hosted service with
|
||||
no direct correlation to Kubernetes namespaces. In Kubernetes 1.10 and later, you can address this use case
|
||||
with *external metrics*.
|
||||
-->
|
||||
### 基于与 Kubernetes 对象无关的度量指标执行扩缩
|
||||
|
||||
运行在 Kubernetes 上的应用程序可能需要基于与 Kubernetes 集群中的任何对象
|
||||
没有明显关系的度量指标进行自动扩缩,
|
||||
例如那些描述与任何 Kubernetes 名字空间中的服务都无直接关联的度量指标。
|
||||
在 Kubernetes 1.10 及之后版本中,你可以使用外部度量指标(external metrics)。
|
||||
|
||||
<!--
|
||||
Using external metrics requires knowledge of your monitoring system; the setup is
|
||||
similar to that required when using custom metrics. External metrics allow you to autoscale your cluster
|
||||
based on any metric available in your monitoring system. Provide a `metric` block with a
|
||||
`name` and `selector`, as above, and use the `External` metric type instead of `Object`.
|
||||
If multiple time series are matched by the `metricSelector`,
|
||||
the sum of their values is used by the HorizontalPodAutoscaler.
|
||||
External metrics support both the `Value` and `AverageValue` target types, which function exactly the same
|
||||
as when you use the `Object` type.
|
||||
-->
|
||||
使用外部度量指标时,需要了解你所使用的监控系统,相关的设置与使用自定义指标时类似。
|
||||
外部度量指标使得你可以使用你的监控系统的任何指标来自动扩缩你的集群。
|
||||
你需要在 `metric` 块中提供 `name` 和 `selector`,同时将类型由 `Object` 改为 `External`。
|
||||
如果 `metricSelector` 匹配到多个度量指标,HorizontalPodAutoscaler 将会把它们加和。
|
||||
外部度量指标同时支持 `Value` 和 `AverageValue` 类型,这与 `Object` 类型的度量指标相同。
|
||||
|
||||
<!--
|
||||
For example if your application processes tasks from a hosted queue service, you could add the following
|
||||
section to your HorizontalPodAutoscaler manifest to specify that you need one worker per 30 outstanding tasks.
|
||||
-->
|
||||
例如,如果你的应用程序处理来自主机上消息队列的任务,
|
||||
为了让每 30 个任务有 1 个工作者实例,你可以将下面的内容添加到
|
||||
HorizontalPodAutoscaler 的配置中。
|
||||
|
||||
```yaml
|
||||
- type: External
|
||||
external:
|
||||
metric:
|
||||
name: queue_messages_ready
|
||||
selector:
|
||||
matchLabels:
|
||||
queue: "worker_tasks"
|
||||
target:
|
||||
type: AverageValue
|
||||
averageValue: 30
|
||||
```
|
||||
|
||||
<!--
|
||||
When possible, it's preferable to use the custom metric target types instead of external metrics, since it's
|
||||
easier for cluster administrators to secure the custom metrics API. The external metrics API potentially allows
|
||||
access to any metric, so cluster administrators should take care when exposing it.
|
||||
-->
|
||||
如果可能,还是推荐定制度量指标而不是外部度量指标,因为这便于让系统管理员加固定制度量指标 API。
|
||||
而外部度量指标 API 可以允许访问所有的度量指标。
|
||||
当暴露这些服务时,系统管理员需要仔细考虑这个问题。
|
||||
|
||||
<!--
|
||||
## Appendix: Horizontal Pod Autoscaler Status Conditions
|
||||
|
||||
When using the `autoscaling/v2` form of the HorizontalPodAutoscaler, you will be able to see
|
||||
*status conditions* set by Kubernetes on the HorizontalPodAutoscaler. These status conditions indicate
|
||||
whether or not the HorizontalPodAutoscaler is able to scale, and whether or not it is currently restricted
|
||||
in any way.
|
||||
-->
|
||||
## 附录:Horizontal Pod Autoscaler 状态条件
|
||||
|
||||
使用 `autoscaling/v2` 格式的 HorizontalPodAutoscaler 时,你将可以看到
|
||||
Kubernetes 为 HorizongtalPodAutoscaler 设置的状态条件(Status Conditions)。
|
||||
这些状态条件可以显示当前 HorizontalPodAutoscaler 是否能够执行扩缩以及是否受到一定的限制。
|
||||
|
||||
<!--
|
||||
The conditions appear in the `status.conditions` field. To see the conditions affecting a HorizontalPodAutoscaler,
|
||||
we can use `kubectl describe hpa`:
|
||||
-->
|
||||
`status.conditions` 字段展示了这些状态条件。
|
||||
可以通过 `kubectl describe hpa` 命令查看当前影响 HorizontalPodAutoscaler
|
||||
的各种状态条件信息:
|
||||
|
||||
```shell
|
||||
kubectl describe hpa cm-test
|
||||
```
|
||||
|
||||
```
|
||||
Name: cm-test
|
||||
Namespace: prom
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
CreationTimestamp: Fri, 16 Jun 2017 18:09:22 +0000
|
||||
Reference: ReplicationController/cm-test
|
||||
Metrics: ( current / target )
|
||||
"http_requests" on pods: 66m / 500m
|
||||
Min replicas: 1
|
||||
Max replicas: 4
|
||||
ReplicationController pods: 1 current / 1 desired
|
||||
Conditions:
|
||||
Type Status Reason Message
|
||||
---- ------ ------ -------
|
||||
AbleToScale True ReadyForNewScale the last scale time was sufficiently old as to warrant a new scale
|
||||
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests
|
||||
ScalingLimited False DesiredWithinRange the desired replica count is within the acceptable range
|
||||
Events:
|
||||
```
|
||||
|
||||
<!--
|
||||
For this HorizontalPodAutoscaler, you can see several conditions in a healthy state. The first,
|
||||
`AbleToScale`, indicates whether or not the HPA is able to fetch and update scales, as well as
|
||||
whether or not any backoff-related conditions would prevent scaling. The second, `ScalingActive`,
|
||||
indicates whether or not the HPA is enabled (i.e. the replica count of the target is not zero) and
|
||||
is able to calculate desired scales. When it is `False`, it generally indicates problems with
|
||||
fetching metrics. Finally, the last condition, `ScalingLimited`, indicates that the desired scale
|
||||
was capped by the maximum or minimum of the HorizontalPodAutoscaler. This is an indication that
|
||||
you may wish to raise or lower the minimum or maximum replica count constraints on your
|
||||
HorizontalPodAutoscaler.
|
||||
-->
|
||||
对于上面展示的这个 HorizontalPodAutoscaler,我们可以看出有若干状态条件处于健康状态。
|
||||
首先,`AbleToScale` 表明 HPA 是否可以获取和更新扩缩信息,以及是否存在阻止扩缩的各种回退条件。
|
||||
其次,`ScalingActive` 表明 HPA 是否被启用(即目标的副本数量不为零) 以及是否能够完成扩缩计算。
|
||||
当这一状态为 `False` 时,通常表明获取度量指标存在问题。
|
||||
最后一个条件 `ScalingLimitted` 表明所需扩缩的值被 HorizontalPodAutoscaler
|
||||
所定义的最大或者最小值所限制(即已经达到最大或者最小扩缩值)。
|
||||
这通常表明你可能需要调整 HorizontalPodAutoscaler 所定义的最大或者最小副本数量的限制了。
|
||||
|
||||
<!--
|
||||
## Quantities
|
||||
|
||||
All metrics in the HorizontalPodAutoscaler and metrics APIs are specified using
|
||||
a special whole-number notation known in Kubernetes as a
|
||||
{{< glossary_tooltip term_id="quantity" text="quantity">}}. For example,
|
||||
the quantity `10500m` would be written as `10.5` in decimal notation. The metrics APIs
|
||||
will return whole numbers without a suffix when possible, and will generally return
|
||||
quantities in milli-units otherwise. This means you might see your metric value fluctuate
|
||||
between `1` and `1500m`, or `1` and `1.5` when written in decimal notation.
|
||||
-->
|
||||
## 量纲 {#quantities}
|
||||
|
||||
HorizontalPodAutoscaler 和 度量指标 API 中的所有的度量指标使用 Kubernetes 中称为
|
||||
{{< glossary_tooltip term_id="quantity" text="量纲(Quantity)">}}
|
||||
的特殊整数表示。
|
||||
例如,数量 `10500m` 用十进制表示为 `10.5`。
|
||||
如果可能的话,度量指标 API 将返回没有后缀的整数,否则返回以千分单位的数量。
|
||||
这意味着你可能会看到你的度量指标在 `1` 和 `1500m` (也就是在十进制记数法中的 `1` 和 `1.5`)之间波动。
|
||||
|
||||
<!--
|
||||
## Other possible scenarios
|
||||
|
||||
### Creating the autoscaler declaratively
|
||||
-->
|
||||
## 其他可能的情况 {#other-possible-scenarios}
|
||||
|
||||
### 以声明式方式创建 Autoscaler {#creating-the-autoscaler-declaratively}
|
||||
|
||||
<!--
|
||||
Instead of using `kubectl autoscale` command to create a HorizontalPodAutoscaler imperatively we
|
||||
can use the following manifest to create it declaratively:
|
||||
-->
|
||||
除了使用 `kubectl autoscale` 命令,也可以使用以下清单以声明方式创建 HorizontalPodAutoscaler:
|
||||
|
||||
{{< codenew file="application/hpa/php-apache.yaml" >}}
|
||||
|
||||
<!--
|
||||
Then, create the autoscaler by executing the following command:
|
||||
-->
|
||||
使用如下命令创建 autoscaler:
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
|
||||
```
|
||||
|
||||
```
|
||||
horizontalpodautoscaler.autoscaling/php-apache created
|
||||
```
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,863 @@
|
||||
---
|
||||
title: 运行一个有状态的应用程序
|
||||
content_type: tutorial
|
||||
weight: 30
|
||||
---
|
||||
<!--
|
||||
reviewers:
|
||||
- enisoc
|
||||
- erictune
|
||||
- foxish
|
||||
- janetkuo
|
||||
- kow3ns
|
||||
- smarterclayton
|
||||
title: Run a Replicated Stateful Application
|
||||
content_type: tutorial
|
||||
weight: 30
|
||||
-->
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
This page shows how to run a replicated stateful application using a
|
||||
[StatefulSet](/docs/concepts/workloads/controllers/statefulset/) controller.
|
||||
This application is a replicated MySQL database. The example topology has a
|
||||
single primary server and multiple replicas, using asynchronous row-based
|
||||
replication.
|
||||
-->
|
||||
本页展示如何使用 [StatefulSet](/zh/docs/concepts/workloads/controllers/statefulset/)
|
||||
控制器运行一个有状态的应用程序。此例是多副本的 MySQL 数据库。
|
||||
示例应用的拓扑结构有一个主服务器和多个副本,使用异步的基于行(Row-Based)
|
||||
的数据复制。
|
||||
|
||||
<!--
|
||||
**this is not a production configuration**.
|
||||
In particular, MySQL settings remain on insecure defaults to keep the focus
|
||||
on general patterns for running stateful applications in Kubernetes.
|
||||
-->
|
||||
{{< note >}}
|
||||
**这不是生产环境下配置**。
|
||||
尤其注意,MySQL 设置都使用的是不安全的默认值,这是因为我们想把重点放在 Kubernetes
|
||||
中运行有状态应用程序的一般模式上。
|
||||
{{< /note >}}
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
* {{< include "default-storage-class-prereqs.md" >}}
|
||||
|
||||
<!--
|
||||
* This tutorial assumes you are familiar with
|
||||
[PersistentVolumes](/docs/concepts/storage/persistent-volumes/)
|
||||
and [StatefulSets](/docs/concepts/workloads/controllers/statefulset/),
|
||||
as well as other core concepts like [Pods](/docs/concepts/workloads/pods/),
|
||||
[Services](/docs/concepts/services-networking/service/), and
|
||||
[ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/).
|
||||
* Some familiarity with MySQL helps, but this tutorial aims to present
|
||||
general patterns that should be useful for other systems.
|
||||
* You are using the default namespace or another namespace that does not contain any conflicting objects.
|
||||
-->
|
||||
* 本教程假定你熟悉
|
||||
[PersistentVolumes](/zh/docs/concepts/storage/persistent-volumes/)
|
||||
与 [StatefulSet](/zh/docs/concepts/workloads/controllers/statefulset/),
|
||||
以及其他核心概念,例如 [Pod](/zh/docs/concepts/workloads/pods/)、
|
||||
[服务](/zh/docs/concepts/services-networking/service/) 与
|
||||
[ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/).
|
||||
* 熟悉 MySQL 会有所帮助,但是本教程旨在介绍对其他系统应该有用的常规模式。
|
||||
* 你正在使用默认命名空间或不包含任何冲突对象的另一个命名空间。
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
<!--
|
||||
* Deploy a replicated MySQL topology with a StatefulSet controller.
|
||||
* Send MySQL client traffic.
|
||||
* Observe resistance to downtime.
|
||||
* Scale the StatefulSet up and down.
|
||||
-->
|
||||
* 使用 StatefulSet 控制器部署多副本 MySQL 拓扑架构。
|
||||
* 发送 MySQL 客户端请求
|
||||
* 观察对宕机的抵抗力
|
||||
* 扩缩 StatefulSet 的规模
|
||||
|
||||
<!-- lessoncontent -->
|
||||
|
||||
<!--
|
||||
## Deploy MySQL
|
||||
|
||||
The example MySQL deployment consists of a ConfigMap, two Services,
|
||||
and a StatefulSet.
|
||||
-->
|
||||
## 部署 MySQL {#deploy-mysql}
|
||||
|
||||
MySQL 示例部署包含一个 ConfigMap、两个 Service 与一个 StatefulSet。
|
||||
|
||||
### ConfigMap
|
||||
|
||||
<!--
|
||||
Create the ConfigMap from the following YAML configuration file:
|
||||
-->
|
||||
使用以下的 YAML 配置文件创建 ConfigMap :
|
||||
|
||||
{{< codenew file="application/mysql/mysql-configmap.yaml" >}}
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
This ConfigMap provides `my.cnf` overrides that let you independently control
|
||||
configuration on the primary MySQL server and replicas.
|
||||
In this case, you want the primary server to be able to serve replication logs to replicas
|
||||
and you want repicas to reject any writes that don't come via replication.
|
||||
-->
|
||||
这个 ConfigMap 提供 `my.cnf` 覆盖设置,使你可以独立控制 MySQL 主服务器和从服务器的配置。
|
||||
在这里,你希望主服务器能够将复制日志提供给副本服务器,并且希望副本服务器拒绝任何不是通过
|
||||
复制进行的写操作。
|
||||
|
||||
<!--
|
||||
There's nothing special about the ConfigMap itself that causes different
|
||||
portions to apply to different Pods.
|
||||
Each Pod decides which portion to look at as it's initializing,
|
||||
based on information provided by the StatefulSet controller.
|
||||
-->
|
||||
ConfigMap 本身没有什么特别之处,因而也不会出现不同部分应用于不同的 Pod 的情况。
|
||||
每个 Pod 都会在初始化时基于 StatefulSet 控制器提供的信息决定要查看的部分。
|
||||
|
||||
<!--
|
||||
### Services
|
||||
|
||||
Create the Services from the following YAML configuration file:
|
||||
-->
|
||||
### 服务 {#services}
|
||||
|
||||
使用以下 YAML 配置文件创建服务:
|
||||
|
||||
{{< codenew file="application/mysql/mysql-services.yaml" >}}
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
The Headless Service provides a home for the DNS entries that the StatefulSet
|
||||
controller creates for each Pod that's part of the set.
|
||||
Because the Headless Service is named `mysql`, the Pods are accessible by
|
||||
resolving `<pod-name>.mysql` from within any other Pod in the same Kubernetes
|
||||
cluster and namespace.
|
||||
-->
|
||||
这个无头服务给 StatefulSet 控制器为集合中每个 Pod 创建的 DNS 条目提供了一个宿主。
|
||||
因为无头服务名为 `mysql`,所以可以通过在同一 Kubernetes 集群和命名空间中的任何其他 Pod
|
||||
内解析 `<Pod 名称>.mysql` 来访问 Pod。
|
||||
|
||||
<!--
|
||||
The Client Service, called `mysql-read`, is a normal Service with its own
|
||||
cluster IP that distributes connections across all MySQL Pods that report
|
||||
being Ready. The set of potential endpoints includes the primary MySQL server and all
|
||||
replicas.
|
||||
-->
|
||||
客户端服务称为 `mysql-read`,是一种常规服务,具有其自己的集群 IP。
|
||||
该集群 IP 在报告就绪的所有MySQL Pod 之间分配连接。
|
||||
可能的端点集合包括 MySQL 主节点和所有副本节点。
|
||||
|
||||
<!--
|
||||
Note that only read queries can use the load-balanced Client Service.
|
||||
Because there is only one primary MySQL server, clients should connect directly to the
|
||||
primary MySQL Pod (through its DNS entry within the Headless Service) to execute
|
||||
writes.
|
||||
-->
|
||||
请注意,只有读查询才能使用负载平衡的客户端服务。
|
||||
因为只有一个 MySQL 主服务器,所以客户端应直接连接到 MySQL 主服务器 Pod
|
||||
(通过其在无头服务中的 DNS 条目)以执行写入操作。
|
||||
|
||||
### StatefulSet
|
||||
|
||||
<!--
|
||||
Finally, create the StatefulSet from the following YAML configuration file:
|
||||
-->
|
||||
最后,使用以下 YAML 配置文件创建 StatefulSet:
|
||||
|
||||
{{< codenew file="application/mysql/mysql-statefulset.yaml" >}}
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
You can watch the startup progress by running:
|
||||
-->
|
||||
你可以通过运行以下命令查看启动进度:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=mysql --watch
|
||||
```
|
||||
|
||||
<!--
|
||||
After a while, you should see all 3 Pods become Running:
|
||||
-->
|
||||
一段时间后,你应该看到所有 3 个 Pod 进入 Running 状态:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
mysql-0 2/2 Running 0 2m
|
||||
mysql-1 2/2 Running 0 1m
|
||||
mysql-2 2/2 Running 0 1m
|
||||
```
|
||||
|
||||
<!--
|
||||
Press **Ctrl+C** to cancel the watch.
|
||||
If you don't see any progress, make sure you have a dynamic PersistentVolume
|
||||
provisioner enabled as mentioned in the [prerequisites](#before-you-begin).
|
||||
-->
|
||||
输入 **Ctrl+C** 结束 watch 操作。
|
||||
如果你看不到任何进度,确保已启用[前提条件](#准备开始)
|
||||
中提到的动态 PersistentVolume 预配器。
|
||||
|
||||
<!--
|
||||
This manifest uses a variety of techniques for managing stateful Pods as part of
|
||||
a StatefulSet. The next section highlights some of these techniques to explain
|
||||
what happens as the StatefulSet creates Pods.
|
||||
-->
|
||||
此清单使用多种技术来管理作为 StatefulSet 的一部分的有状态 Pod。
|
||||
下一节重点介绍其中的一些技巧,以解释 StatefulSet 创建 Pod 时发生的状况。
|
||||
|
||||
<!--
|
||||
## Understanding stateful Pod initialization
|
||||
|
||||
The StatefulSet controller starts Pods one at a time, in order by their
|
||||
ordinal index.
|
||||
It waits until each Pod reports being Ready before starting the next one.
|
||||
-->
|
||||
## 了解有状态的 Pod 初始化
|
||||
|
||||
StatefulSet 控制器按序数索引顺序地每次启动一个 Pod。
|
||||
它一直等到每个 Pod 报告就绪才再启动下一个 Pod。
|
||||
|
||||
<!--
|
||||
In addition, the controller assigns each Pod a unique, stable name of the form
|
||||
`<statefulset-name>-<ordinal-index>`, which results in Pods named `mysql-0`,
|
||||
`mysql-1`, and `mysql-2`.
|
||||
-->
|
||||
此外,控制器为每个 Pod 分配一个唯一、稳定的名称,形如 `<statefulset 名称>-<序数索引>`,
|
||||
其结果是 Pods 名为 `mysql-0`、`mysql-1` 和 `mysql-2`。
|
||||
|
||||
<!--
|
||||
The Pod template in the above StatefulSet manifest takes advantage of these
|
||||
properties to perform orderly startup of MySQL replication.
|
||||
-->
|
||||
上述 StatefulSet 清单中的 Pod 模板利用这些属性来执行 MySQL 副本的有序启动。
|
||||
|
||||
<!--
|
||||
### Generating configuration
|
||||
|
||||
Before starting any of the containers in the Pod spec, the Pod first runs any
|
||||
[Init Containers](/docs/concepts/workloads/pods/init-containers/)
|
||||
in the order defined.
|
||||
-->
|
||||
### 生成配置
|
||||
|
||||
在启动 Pod 规约中的任何容器之前,Pod 首先按顺序运行所有的
|
||||
[Init 容器](/zh/docs/concepts/workloads/pods/init-containers/)。
|
||||
|
||||
<!--
|
||||
The first Init Container, named `init-mysql`, generates special MySQL config
|
||||
files based on the ordinal index.
|
||||
-->
|
||||
第一个名为 `init-mysql` 的 Init 容器根据序号索引生成特殊的 MySQL 配置文件。
|
||||
|
||||
<!--
|
||||
The script determines its own ordinal index by extracting it from the end of
|
||||
the Pod name, which is returned by the `hostname` command.
|
||||
Then it saves the ordinal (with a numeric offset to avoid reserved values)
|
||||
into a file called `server-id.cnf` in the MySQL `conf.d` directory.
|
||||
This translates the unique, stable identity provided by the StatefulSet
|
||||
controller into the domain of MySQL server IDs, which require the same
|
||||
properties.
|
||||
-->
|
||||
该脚本通过从 Pod 名称的末尾提取索引来确定自己的序号索引,而 Pod 名称由 `hostname` 命令返回。
|
||||
然后将序数(带有数字偏移量以避免保留值)保存到 MySQL `conf.d` 目录中的文件 `server-id.cnf`。
|
||||
这一操作将 StatefulSet 所提供的唯一、稳定的标识转换为 MySQL 服务器的 ID,
|
||||
而这些 ID 也是需要唯一性、稳定性保证的。
|
||||
|
||||
<!--
|
||||
The script in the `init-mysql` container also applies either `primary.cnf` or
|
||||
`replica.cnf` from the ConfigMap by copying the contents into `conf.d`.
|
||||
Because the example topology consists of a single primary MySQL server and any number of
|
||||
replicas, the script assigns ordinal `0` to be the primary server, and everyone
|
||||
else to be replicas.
|
||||
|
||||
Combined with the StatefulSet controller's
|
||||
[deployment order guarantee](/docs/concepts/workloads/controllers/statefulset/#deployment-and-scaling-guarantees),
|
||||
this ensures the primary MySQL server is Ready before creating replicas, so they can begin
|
||||
replicating.
|
||||
-->
|
||||
通过将内容复制到 `conf.d` 中,`init-mysql` 容器中的脚本也可以应用 ConfigMap 中的
|
||||
`primary.cnf` 或 `replica.cnf`。
|
||||
由于示例部署结构由单个 MySQL 主节点和任意数量的副本节点组成,
|
||||
因此脚本仅将序数 `0` 指定为主节点,而将其他所有节点指定为副本节点。
|
||||
|
||||
与 StatefulSet 控制器的
|
||||
[部署顺序保证](/zh/docs/concepts/workloads/controllers/statefulset/#deployment-and-scaling-guarantees)
|
||||
相结合,
|
||||
可以确保 MySQL 主服务器在创建副本服务器之前已准备就绪,以便它们可以开始复制。
|
||||
|
||||
<!--
|
||||
### Cloning existing data
|
||||
|
||||
In general, when a new Pod joins the set as a replica, it must assume the primary MySQL
|
||||
server might already have data on it. It also must assume that the replication
|
||||
logs might not go all the way back to the beginning of time.
|
||||
-->
|
||||
### 克隆现有数据
|
||||
|
||||
通常,当新 Pod 作为副本节点加入集合时,必须假定 MySQL 主节点可能已经有数据。
|
||||
还必须假设复制日志可能不会一直追溯到时间的开始。
|
||||
|
||||
<!--
|
||||
These conservative assumptions are the key to allow a running StatefulSet
|
||||
to scale up and down over time, rather than being fixed at its initial size.
|
||||
-->
|
||||
这些保守的假设是允许正在运行的 StatefulSet 随时间扩大和缩小而不是固定在其初始大小的关键。
|
||||
|
||||
<!--
|
||||
The second Init Container, named `clone-mysql`, performs a clone operation on
|
||||
a replica Pod the first time it starts up on an empty PersistentVolume.
|
||||
That means it copies all existing data from another running Pod,
|
||||
so its local state is consistent enough to begin replicating from the primary server.
|
||||
-->
|
||||
第二个名为 `clone-mysql` 的 Init 容器,第一次在带有空 PersistentVolume 的副本 Pod
|
||||
上启动时,会在从属 Pod 上执行克隆操作。
|
||||
这意味着它将从另一个运行中的 Pod 复制所有现有数据,使此其本地状态足够一致,
|
||||
从而可以开始从主服务器复制。
|
||||
|
||||
<!--
|
||||
MySQL itself does not provide a mechanism to do this, so the example uses a
|
||||
popular open-source tool called Percona XtraBackup.
|
||||
During the clone, the source MySQL server might suffer reduced performance.
|
||||
To minimize impact on the primary MySQL server, the script instructs each Pod to clone
|
||||
from the Pod whose ordinal index is one lower.
|
||||
This works because the StatefulSet controller always ensures Pod `N` is
|
||||
Ready before starting Pod `N+1`.
|
||||
-->
|
||||
MySQL 本身不提供执行此操作的机制,因此本示例使用了一种流行的开源工具 Percona XtraBackup。
|
||||
在克隆期间,源 MySQL 服务器性能可能会受到影响。
|
||||
为了最大程度地减少对 MySQL 主服务器的影响,该脚本指示每个 Pod 从序号较低的 Pod 中克隆。
|
||||
可以这样做的原因是 StatefulSet 控制器始终确保在启动 Pod `N + 1` 之前 Pod `N` 已准备就绪。
|
||||
|
||||
<!--
|
||||
### Starting replication
|
||||
|
||||
After the Init Containers complete successfully, the regular containers run.
|
||||
The MySQL Pods consist of a `mysql` container that runs the actual `mysqld`
|
||||
server, and an `xtrabackup` container that acts as a
|
||||
[sidecar](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns).
|
||||
-->
|
||||
### 开始复制
|
||||
|
||||
Init 容器成功完成后,应用容器将运行。
|
||||
MySQL Pod 由运行实际 `mysqld` 服务的 `mysql` 容器和充当
|
||||
[辅助工具](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns)
|
||||
的 xtrabackup 容器组成。
|
||||
|
||||
<!--
|
||||
The `xtrabackup` sidecar looks at the cloned data files and determines if
|
||||
it's necessary to initialize MySQL replication on the replica.
|
||||
If so, it waits for `mysqld` to be ready and then executes the
|
||||
`CHANGE MASTER TO` and `START SLAVE` commands with replication parameters
|
||||
extracted from the XtraBackup clone files.
|
||||
-->
|
||||
`xtrabackup` sidecar 容器查看克隆的数据文件,并确定是否有必要在副本服务器上初始化 MySQL 复制。
|
||||
如果是这样,它将等待 `mysqld` 准备就绪,然后使用从 XtraBackup 克隆文件中提取的复制参数
|
||||
执行 `CHANGE MASTER TO` 和 `START SLAVE` 命令。
|
||||
|
||||
<!--
|
||||
Once a replica begins replication, it remembers its primary MySQL server and
|
||||
reconnects automatically if the server restarts or the connection dies.
|
||||
Also, because replicas look for the primary server at its stable DNS name
|
||||
(`mysql-0.mysql`), they automatically find the primary server even if it gets a new
|
||||
Pod IP due to being rescheduled.
|
||||
-->
|
||||
一旦副本服务器开始复制后,它会记住其 MySQL 主服务器,并且如果服务器重新启动或
|
||||
连接中断也会自动重新连接。
|
||||
另外,因为副本服务器会以其稳定的 DNS 名称查找主服务器(`mysql-0.mysql`),
|
||||
即使由于重新调度而获得新的 Pod IP,它们也会自动找到主服务器。
|
||||
|
||||
<!--
|
||||
Lastly, after starting replication, the `xtrabackup` container listens for
|
||||
connections from other Pods requesting a data clone.
|
||||
This server remains up indefinitely in case the StatefulSet scales up, or in
|
||||
case the next Pod loses its PersistentVolumeClaim and needs to redo the clone.
|
||||
-->
|
||||
最后,开始复制后,`xtrabackup` 容器监听来自其他 Pod 的连接,处理其数据克隆请求。
|
||||
如果 StatefulSet 扩大规模,或者下一个 Pod 失去其 PersistentVolumeClaim 并需要重新克隆,
|
||||
则此服务器将无限期保持运行。
|
||||
|
||||
<!--
|
||||
## Sending client traffic
|
||||
|
||||
You can send test queries to the primary MySQL server (hostname `mysql-0.mysql`)
|
||||
by running a temporary container with the `mysql:5.7` image and running the
|
||||
`mysql` client binary.
|
||||
-->
|
||||
## 发送客户端请求
|
||||
|
||||
你可以通过运行带有 `mysql:5.7` 镜像的临时容器并运行 `mysql` 客户端二进制文件,
|
||||
将测试查询发送到 MySQL 主服务器(主机名 `mysql-0.mysql`)。
|
||||
|
||||
```shell
|
||||
kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\
|
||||
mysql -h mysql-0.mysql <<EOF
|
||||
CREATE DATABASE test;
|
||||
CREATE TABLE test.messages (message VARCHAR(250));
|
||||
INSERT INTO test.messages VALUES ('hello');
|
||||
EOF
|
||||
```
|
||||
|
||||
<!--
|
||||
Use the hostname `mysql-read` to send test queries to any server that reports
|
||||
being Ready:
|
||||
-->
|
||||
使用主机名 `mysql-read` 将测试查询发送到任何报告为就绪的服务器:
|
||||
|
||||
```shell
|
||||
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
|
||||
mysql -h mysql-read -e "SELECT * FROM test.messages"
|
||||
```
|
||||
|
||||
<!--
|
||||
You should get output like this:
|
||||
-->
|
||||
你应该获得如下输出:
|
||||
|
||||
```
|
||||
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
|
||||
+---------+
|
||||
| message |
|
||||
+---------+
|
||||
| hello |
|
||||
+---------+
|
||||
pod "mysql-client" deleted
|
||||
```
|
||||
|
||||
<!--
|
||||
To demonstrate that the `mysql-read` Service distributes connections across
|
||||
servers, you can run `SELECT @@server_id` in a loop:
|
||||
-->
|
||||
为了演示 `mysql-read` 服务在服务器之间分配连接,你可以在循环中运行 `SELECT @@server_id`:
|
||||
|
||||
```shell
|
||||
kubectl run mysql-client-loop --image=mysql:5.7 -i -t --rm --restart=Never --\
|
||||
bash -ic "while sleep 1; do mysql -h mysql-read -e 'SELECT @@server_id,NOW()'; done"
|
||||
```
|
||||
|
||||
<!--
|
||||
You should see the reported `@@server_id` change randomly, because a different
|
||||
endpoint might be selected upon each connection attempt:
|
||||
-->
|
||||
你应该看到报告的 `@@server_id` 发生随机变化,因为每次尝试连接时都可能选择了不同的端点:
|
||||
|
||||
```
|
||||
+-------------+---------------------+
|
||||
| @@server_id | NOW() |
|
||||
+-------------+---------------------+
|
||||
| 100 | 2006-01-02 15:04:05 |
|
||||
+-------------+---------------------+
|
||||
+-------------+---------------------+
|
||||
| @@server_id | NOW() |
|
||||
+-------------+---------------------+
|
||||
| 102 | 2006-01-02 15:04:06 |
|
||||
+-------------+---------------------+
|
||||
+-------------+---------------------+
|
||||
| @@server_id | NOW() |
|
||||
+-------------+---------------------+
|
||||
| 101 | 2006-01-02 15:04:07 |
|
||||
+-------------+---------------------+
|
||||
```
|
||||
|
||||
<!--
|
||||
You can press **Ctrl+C** when you want to stop the loop, but it's useful to keep
|
||||
it running in another window so you can see the effects of the following steps.
|
||||
-->
|
||||
要停止循环时可以按 **Ctrl+C** ,但是让它在另一个窗口中运行非常有用,
|
||||
这样你就可以看到以下步骤的效果。
|
||||
|
||||
<!--
|
||||
## Simulating Pod and Node downtime
|
||||
|
||||
To demonstrate the increased availability of reading from the pool of replicas
|
||||
instead of a single server, keep the `SELECT @@server_id` loop from above
|
||||
running while you force a Pod out of the Ready state.
|
||||
-->
|
||||
## 模拟 Pod 和 Node 的宕机时间
|
||||
|
||||
为了证明从副本节点缓存而不是单个服务器读取数据的可用性提高,请在使 Pod 退出 Ready
|
||||
状态时,保持上述 `SELECT @@server_id` 循环一直运行。
|
||||
|
||||
<!--
|
||||
### Break the Readiness Probe
|
||||
|
||||
The [readiness probe](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes)
|
||||
for the `mysql` container runs the command `mysql -h 127.0.0.1 -e 'SELECT 1'`
|
||||
to make sure the server is up and able to execute queries.
|
||||
-->
|
||||
### 破坏就绪态探测
|
||||
|
||||
`mysql` 容器的
|
||||
[就绪态探测](/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes)
|
||||
运行命令 `mysql -h 127.0.0.1 -e 'SELECT 1'`,以确保服务器已启动并能够执行查询。
|
||||
|
||||
<!--
|
||||
One way to force this readiness probe to fail is to break that command:
|
||||
-->
|
||||
迫使就绪态探测失败的一种方法就是中止该命令:
|
||||
|
||||
```shell
|
||||
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql /usr/bin/mysql.off
|
||||
```
|
||||
|
||||
<!--
|
||||
This reaches into the actual container's filesystem for Pod `mysql-2` and
|
||||
renames the `mysql` command so the readiness probe can't find it.
|
||||
After a few seconds, the Pod should report one of its containers as not Ready,
|
||||
which you can check by running:
|
||||
-->
|
||||
此命令会进入 Pod `mysql-2` 的实际容器文件系统,重命名 `mysql` 命令,导致就绪态探测无法找到它。
|
||||
几秒钟后, Pod 会报告其中一个容器未就绪。你可以通过运行以下命令进行检查:
|
||||
|
||||
```shell
|
||||
kubectl get pod mysql-2
|
||||
```
|
||||
|
||||
<!--
|
||||
Look for `1/2` in the `READY` column:
|
||||
-->
|
||||
在 `READY` 列中查找 `1/2`:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
mysql-2 1/2 Running 0 3m
|
||||
```
|
||||
|
||||
<!--
|
||||
At this point, you should see your `SELECT @@server_id` loop continue to run,
|
||||
although it never reports `102` anymore.
|
||||
Recall that the `init-mysql` script defined `server-id` as `100 + $ordinal`,
|
||||
so server ID `102` corresponds to Pod `mysql-2`.
|
||||
-->
|
||||
此时,你应该会看到 `SELECT @@server_id` 循环继续运行,尽管它不再报告 `102`。
|
||||
回想一下,`init-mysql` 脚本将 `server-id` 定义为 `100 + $ordinal`,
|
||||
因此服务器 ID `102` 对应于 Pod `mysql-2`。
|
||||
|
||||
<!--
|
||||
Now repair the Pod and it should reappear in the loop output
|
||||
after a few seconds:
|
||||
-->
|
||||
现在修复 Pod,几秒钟后它应该重新出现在循环输出中:
|
||||
|
||||
```shell
|
||||
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql.off /usr/bin/mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
### Delete Pods
|
||||
|
||||
The StatefulSet also recreates Pods if they're deleted, similar to what a
|
||||
ReplicaSet does for stateless Pods.
|
||||
-->
|
||||
### 删除 Pods
|
||||
|
||||
如果删除了 Pod,则 StatefulSet 还会重新创建 Pod,类似于 ReplicaSet 对无状态 Pod 所做的操作。
|
||||
|
||||
```shell
|
||||
kubectl delete pod mysql-2
|
||||
```
|
||||
|
||||
<!--
|
||||
The StatefulSet controller notices that no `mysql-2` Pod exists anymore,
|
||||
and creates a new one with the same name and linked to the same
|
||||
PersistentVolumeClaim.
|
||||
You should see server ID `102` disappear from the loop output for a while
|
||||
and then return on its own.
|
||||
-->
|
||||
StatefulSet 控制器注意到不再存在 `mysql-2` Pod,于是创建一个具有相同名称并链接到相同
|
||||
PersistentVolumeClaim 的新 Pod。
|
||||
你应该看到服务器 ID `102` 从循环输出中消失了一段时间,然后又自行出现。
|
||||
|
||||
<!--
|
||||
### Drain a Node
|
||||
|
||||
If your Kubernetes cluster has multiple Nodes, you can simulate Node downtime
|
||||
(such as when Nodes are upgraded) by issuing a
|
||||
[drain](/docs/reference/generated/kubectl/kubectl-commands/#drain).
|
||||
-->
|
||||
### 腾空节点 {#drain-a-node}
|
||||
|
||||
如果你的 Kubernetes 集群具有多个节点,则可以通过发出以下
|
||||
[drain](/docs/reference/generated/kubectl/kubectl-commands/#drain)
|
||||
命令来模拟节点停机(就好像节点在被升级)。
|
||||
|
||||
<!--
|
||||
First determine which Node one of the MySQL Pods is on:
|
||||
-->
|
||||
首先确定 MySQL Pod 之一在哪个节点上:
|
||||
|
||||
```shell
|
||||
kubectl get pod mysql-2 -o wide
|
||||
```
|
||||
|
||||
<!--
|
||||
The Node name should show up in the last column:
|
||||
-->
|
||||
节点名称应显示在最后一列中:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
mysql-2 2/2 Running 0 15m 10.244.5.27 kubernetes-node-9l2t
|
||||
```
|
||||
|
||||
<!--
|
||||
Then drain the Node by running the following command, which cordons it so
|
||||
no new Pods may schedule there, and then evicts any existing Pods.
|
||||
Replace `<node-name>` with the name of the Node you found in the last step.
|
||||
-->
|
||||
然后通过运行以下命令腾空节点,该命令将其保护起来,以使新的 Pod 不能调度到该节点,
|
||||
然后逐出所有现有的 Pod。将 `<节点名称>` 替换为在上一步中找到的节点名称。
|
||||
|
||||
|
||||
<!--
|
||||
This might impact other applications on the Node, so it's best to
|
||||
**only do this in a test cluster**.
|
||||
|
||||
```shell
|
||||
kubectl drain <node-name> --force --delete-local-data --ignore-daemonsets
|
||||
```
|
||||
-->
|
||||
这可能会影响节点上的其他应用程序,因此最好 **仅在测试集群中执行此操作**。
|
||||
|
||||
```shell
|
||||
kubectl drain <节点名称> --force --delete-local-data --ignore-daemonsets
|
||||
```
|
||||
|
||||
<!--
|
||||
Now you can watch as the Pod reschedules on a different Node:
|
||||
-->
|
||||
现在,你可以看到 Pod 被重新调度到其他节点上:
|
||||
|
||||
```shell
|
||||
kubectl get pod mysql-2 -o wide --watch
|
||||
```
|
||||
|
||||
<!--
|
||||
It should look something like this:
|
||||
-->
|
||||
它看起来应该像这样:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-node-9l2t
|
||||
[...]
|
||||
mysql-2 0/2 Pending 0 0s <none> kubernetes-node-fjlm
|
||||
mysql-2 0/2 Init:0/2 0 0s <none> kubernetes-node-fjlm
|
||||
mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-node-fjlm
|
||||
mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-node-fjlm
|
||||
mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-node-fjlm
|
||||
mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-node-fjlm
|
||||
```
|
||||
|
||||
<!--
|
||||
And again, you should see server ID `102` disappear from the
|
||||
`SELECT @@server_id` loop output for a while and then return.
|
||||
-->
|
||||
再次,你应该看到服务器 ID `102` 从 `SELECT @@server_id` 循环输出
|
||||
中消失一段时间,然后自行出现。
|
||||
|
||||
<!--
|
||||
Now uncordon the Node to return it to a normal state:
|
||||
|
||||
```shell
|
||||
kubectl uncordon <node-name>
|
||||
```
|
||||
-->
|
||||
现在去掉节点保护(Uncordon),使其恢复为正常模式:
|
||||
|
||||
```shell
|
||||
kubectl uncordon <节点名称>
|
||||
```
|
||||
|
||||
<!--
|
||||
## Scaling the number of replicas
|
||||
|
||||
With MySQL replication, you can scale your read query capacity by adding replicas.
|
||||
With StatefulSet, you can do this with a single command:
|
||||
-->
|
||||
## 扩展副本节点数量
|
||||
|
||||
使用 MySQL 复制,你可以通过添加副本节点来扩展读取查询的能力。
|
||||
使用 StatefulSet,你可以使用单个命令执行此操作:
|
||||
|
||||
```shell
|
||||
kubectl scale statefulset mysql --replicas=5
|
||||
```
|
||||
|
||||
<!--
|
||||
Watch the new Pods come up by running:
|
||||
-->
|
||||
查看新的 Pod 的运行情况:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=mysql --watch
|
||||
```
|
||||
|
||||
<!--
|
||||
Once they're up, you should see server IDs `103` and `104` start appearing in
|
||||
the `SELECT @@server_id` loop output.
|
||||
|
||||
You can also verify that these new servers have the data you added before they
|
||||
existed:
|
||||
-->
|
||||
一旦 Pod 启动,你应该看到服务器 IDs `103` 和 `104` 开始出现在 `SELECT @@server_id` 循环输出中。
|
||||
|
||||
你还可以验证这些新服务器在存在之前已添加了数据:
|
||||
|
||||
```shell
|
||||
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
|
||||
mysql -h mysql-3.mysql -e "SELECT * FROM test.messages"
|
||||
```
|
||||
|
||||
```
|
||||
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
|
||||
+---------+
|
||||
| message |
|
||||
+---------+
|
||||
| hello |
|
||||
+---------+
|
||||
pod "mysql-client" deleted
|
||||
```
|
||||
|
||||
<!--
|
||||
Scaling back down is also seamless:
|
||||
-->
|
||||
向下缩容操作也是很平滑的:
|
||||
|
||||
```shell
|
||||
kubectl scale statefulset mysql --replicas=3
|
||||
```
|
||||
|
||||
<!--
|
||||
Note, however, that while scaling up creates new PersistentVolumeClaims
|
||||
automatically, scaling down does not automatically delete these PVCs.
|
||||
This gives you the choice to keep those initialized PVCs around to make
|
||||
scaling back up quicker, or to extract data before deleting them.
|
||||
-->
|
||||
但是请注意,按比例扩大会自动创建新的 PersistentVolumeClaims,而按比例缩小不会自动删除这些 PVC。
|
||||
这使你可以选择保留那些初始化的 PVC,以更快地进行缩放,或者在删除它们之前提取数据。
|
||||
|
||||
<!--
|
||||
You can see this by running:
|
||||
-->
|
||||
你可以通过运行以下命令查看此信息:
|
||||
|
||||
```shell
|
||||
kubectl get pvc -l app=mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
Which shows that all 5 PVCs still exist, despite having scaled the
|
||||
StatefulSet down to 3:
|
||||
-->
|
||||
这表明,尽管将 StatefulSet 缩小为3,所有5个 PVC 仍然存在:
|
||||
|
||||
```
|
||||
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
||||
data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m
|
||||
data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m
|
||||
data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m
|
||||
data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
|
||||
data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
|
||||
```
|
||||
|
||||
<!--
|
||||
If you don't intend to reuse the extra PVCs, you can delete them:
|
||||
-->
|
||||
如果你不打算重复使用多余的 PVC,则可以删除它们:
|
||||
|
||||
```shell
|
||||
kubectl delete pvc data-mysql-3
|
||||
kubectl delete pvc data-mysql-4
|
||||
```
|
||||
|
||||
## {{% heading "cleanup" %}}
|
||||
|
||||
|
||||
<!--
|
||||
1. Cancel the `SELECT @@server_id` loop by pressing **Ctrl+C** in its terminal,
|
||||
or running the following from another terminal:
|
||||
-->
|
||||
1. 通过在终端上按 **Ctrl+C** 取消 `SELECT @@server_id` 循环,或从另一个终端运行以下命令:
|
||||
|
||||
```shell
|
||||
kubectl delete pod mysql-client-loop --now
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Delete the StatefulSet. This also begins terminating the Pods.
|
||||
-->
|
||||
2. 删除 StatefulSet。这也会开始终止 Pod。
|
||||
|
||||
```shell
|
||||
kubectl delete statefulset mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Verify that the Pods disappear.
|
||||
They might take some time to finish terminating.
|
||||
-->
|
||||
3. 验证 Pod 消失。他们可能需要一些时间才能完成终止。
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=mysql
|
||||
```
|
||||
|
||||
<!-- You'll know the Pods have terminated when the above returns: -->
|
||||
当上述命令返回如下内容时,你就知道 Pod 已终止:
|
||||
|
||||
```
|
||||
No resources found.
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Delete the ConfigMap, Services, and PersistentVolumeClaims.
|
||||
-->
|
||||
4. 删除 ConfigMap、Services 和 PersistentVolumeClaims。
|
||||
|
||||
```shell
|
||||
kubectl delete configmap,service,pvc -l app=mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
1. If you manually provisioned PersistentVolumes, you also need to manually
|
||||
delete them, as well as release the underlying resources.
|
||||
If you used a dynamic provisioner, it automatically deletes the
|
||||
PersistentVolumes when it sees that you deleted the PersistentVolumeClaims.
|
||||
Some dynamic provisioners (such as those for EBS and PD) also release the
|
||||
underlying resources upon deleting the PersistentVolumes.
|
||||
-->
|
||||
5. 如果你手动供应 PersistentVolume,则还需要手动删除它们,并释放下层资源。
|
||||
如果你使用了动态预配器,当得知你删除 PersistentVolumeClaims 时,它将自动删除 PersistentVolumes。
|
||||
一些动态预配器(例如用于 EBS 和 PD 的预配器)也会在删除 PersistentVolumes 时释放下层资源。
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
* Learn more about [scaling a StatefulSet](/docs/tasks/run-application/scale-stateful-set/).
|
||||
* Learn more about [debugging a StatefulSet](/docs/tasks/debug/debug-application/debug-statefulset/).
|
||||
* Learn more about [deleting a StatefulSet](/docs/tasks/run-application/delete-stateful-set/).
|
||||
* Learn more about [force deleting StatefulSet Pods](/docs/tasks/run-application/force-delete-stateful-set-pod/).
|
||||
* Look in the [Helm Charts repository](https://artifacthub.io/)
|
||||
for other stateful application examples.
|
||||
-->
|
||||
* 进一步了解[为 StatefulSet 扩缩容](/zh/docs/tasks/run-application/scale-stateful-set/).
|
||||
* 进一步了解[调试 StatefulSet](/zh/docs/tasks/debug/debug-application/debug-statefulset/).
|
||||
* 进一步了解[删除 StatefulSet](/zh/docs/tasks/run-application/delete-stateful-set/).
|
||||
* 进一步了解[强制删除 StatefulSet Pods](/zh/docs/tasks/run-application/force-delete-stateful-set-pod/).
|
||||
* 在 [Helm Charts 仓库](https://artifacthub.io/)中查找其他有状态的应用程序示例。
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
---
|
||||
title: 运行一个单实例有状态应用
|
||||
content_type: tutorial
|
||||
weight: 20
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
This page shows you how to run a single-instance stateful application
|
||||
in Kubernetes using a PersistentVolume and a Deployment. The
|
||||
application is MySQL.
|
||||
-->
|
||||
本文介绍在 Kubernetes 中如何使用 PersistentVolume 和 Deployment 运行一个单实例有状态应用。该应用是 MySQL.
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
<!--
|
||||
* Create a PersistentVolume referencing a disk in your environment.
|
||||
* Create a MySQL Deployment.
|
||||
* Expose MySQL to other pods in the cluster at a known DNS name.
|
||||
-->
|
||||
* 在你的环境中创建一个引用磁盘的 PersistentVolume
|
||||
* 创建一个 MySQL Deployment.
|
||||
* 在集群内以一个已知的 DNS 名称将 MySQL 暴露给其他 Pod
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
* {{< include "default-storage-class-prereqs.md" >}}
|
||||
|
||||
<!-- lessoncontent -->
|
||||
|
||||
## 部署 MySQL {#deploy-mysql}
|
||||
|
||||
<!--
|
||||
You can run a stateful application by creating a Kubernetes Deployment
|
||||
and connecting it to an existing PersistentVolume using a
|
||||
PersistentVolumeClaim. For example, this YAML file describes a
|
||||
Deployment that runs MySQL and references the PersistentVolumeClaim. The file
|
||||
defines a volume mount for /var/lib/mysql, and then creates a
|
||||
PersistentVolumeClaim that looks for a 20G volume. This claim is
|
||||
satisfied by any existing volume that meets the requirements,
|
||||
or by a dynamic provisioner.
|
||||
-->
|
||||
你可以通过创建一个 Kubernetes Deployment 并使用 PersistentVolumeClaim 将其连接到
|
||||
某已有的 PV 卷来运行一个有状态的应用。
|
||||
例如,这里的 YAML 描述的是一个运行 MySQL 的 Deployment,其中引用了 PVC 申领。
|
||||
文件为 /var/lib/mysql 定义了加载卷,并创建了一个 PVC 申领,寻找一个 20G 大小的卷。
|
||||
该申领可以通过现有的满足需求的卷来满足,也可以通过动态供应卷的机制来满足。
|
||||
|
||||
<!--
|
||||
Note: The password is defined in the config yaml, and this is insecure. See
|
||||
[Kubernetes Secrets](/docs/concepts/configuration/secret/)
|
||||
for a secure solution.
|
||||
-->
|
||||
注意:在配置的 YAML 文件中定义密码的做法是不安全的。具体安全解决方案请参考
|
||||
[Kubernetes Secrets](/zh/docs/concepts/configuration/secret/).
|
||||
|
||||
{{< codenew file="application/mysql/mysql-deployment.yaml" >}}
|
||||
{{< codenew file="application/mysql/mysql-pv.yaml" >}}
|
||||
|
||||
1. <!--Deploy the PV and PVC of the YAML file-->
|
||||
部署 YAML 文件中定义的 PV 和 PVC:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
|
||||
```
|
||||
|
||||
1. <!-- Deploy the contents of the YAML file -->
|
||||
部署 YAML 文件中定义的 Deployment:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
|
||||
```
|
||||
|
||||
1. <!-- Display information about the Deployment -->
|
||||
展示 Deployment 相关信息:
|
||||
|
||||
```shell
|
||||
kubectl describe deployment mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
Name: mysql
|
||||
Namespace: default
|
||||
CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700
|
||||
Labels: app=mysql
|
||||
Annotations: deployment.kubernetes.io/revision=1
|
||||
Selector: app=mysql
|
||||
Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
|
||||
StrategyType: Recreate
|
||||
MinReadySeconds: 0
|
||||
Pod Template:
|
||||
Labels: app=mysql
|
||||
Containers:
|
||||
mysql:
|
||||
Image: mysql:5.6
|
||||
Port: 3306/TCP
|
||||
Environment:
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
Mounts:
|
||||
/var/lib/mysql from mysql-persistent-storage (rw)
|
||||
Volumes:
|
||||
mysql-persistent-storage:
|
||||
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
|
||||
ClaimName: mysql-pv-claim
|
||||
ReadOnly: false
|
||||
Conditions:
|
||||
Type Status Reason
|
||||
---- ------ ------
|
||||
Available False MinimumReplicasUnavailable
|
||||
Progressing True ReplicaSetUpdated
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: mysql-63082529 (1/1 replicas created)
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
|
||||
```
|
||||
|
||||
1. <!-- List the pods created by the Deployment -->
|
||||
列举出 Deployment 创建的 pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=mysql
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
mysql-63082529-2z3ki 1/1 Running 0 3m
|
||||
```
|
||||
|
||||
1. <!-- Inspect the PersistentVolumeClaim -->
|
||||
查看 PersistentVolumeClaim:
|
||||
|
||||
```shell
|
||||
kubectl describe pvc mysql-pv-claim
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
Name: mysql-pv-claim
|
||||
Namespace: default
|
||||
StorageClass:
|
||||
Status: Bound
|
||||
Volume: mysql-pv-volume
|
||||
Labels: <none>
|
||||
Annotations: pv.kubernetes.io/bind-completed=yes
|
||||
pv.kubernetes.io/bound-by-controller=yes
|
||||
Capacity: 20Gi
|
||||
Access Modes: RWO
|
||||
Events: <none>
|
||||
```
|
||||
|
||||
<!--
|
||||
## Accessing the MySQL instance
|
||||
|
||||
The preceding YAML file creates a service that
|
||||
allows other Pods in the cluster to access the database. The Service option
|
||||
`clusterIP: None` lets the Service DNS name resolve directly to the
|
||||
Pod's IP address. This is optimal when you have only one Pod
|
||||
behind a Service and you don't intend to increase the number of Pods.
|
||||
|
||||
Run a MySQL client to connect to the server:
|
||||
-->
|
||||
## 访问 MySQL 实例 {#accessing-the-mysql-instance}
|
||||
|
||||
|
||||
前面 YAML 文件中创建了一个允许集群内其他 Pod 访问的数据库服务。该服务中选项
|
||||
`clusterIP: None` 让服务 DNS 名称直接解析为 Pod 的 IP 地址。
|
||||
当在一个服务下只有一个 Pod 并且不打算增加 Pod 的数量这是最好的.
|
||||
|
||||
运行 MySQL 客户端以连接到服务器:
|
||||
|
||||
```
|
||||
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
|
||||
```
|
||||
|
||||
<!--
|
||||
This command creates a new Pod in the cluster running a MySQL client
|
||||
and connects it to the server through the Service. If it connects, you
|
||||
know your stateful MySQL database is up and running.
|
||||
-->
|
||||
此命令在集群内创建一个新的 Pod 并运行 MySQL 客户端,并通过 Service 连接到服务器。
|
||||
如果连接成功,你就知道有状态的 MySQL 数据库正处于运行状态。
|
||||
|
||||
```
|
||||
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
|
||||
mysql>
|
||||
```
|
||||
|
||||
<!--
|
||||
## Updating
|
||||
|
||||
The image or any other part of the Deployment can be updated as usual
|
||||
with the `kubectl apply` command. Here are some precautions that are
|
||||
specific to stateful apps:
|
||||
-->
|
||||
## 更新 {#updating}
|
||||
|
||||
Deployment 中镜像或其他部分同往常一样可以通过 `kubectl apply` 命令更新。
|
||||
以下是特定于有状态应用的一些注意事项:
|
||||
|
||||
<!--
|
||||
* Don't scale the app. This setup is for single-instance apps
|
||||
only. The underlying PersistentVolume can only be mounted to one
|
||||
Pod. For clustered stateful apps, see the
|
||||
[StatefulSet documentation](/docs/concepts/workloads/controllers/statefulset/).
|
||||
* Use `strategy:` `type: Recreate` in the Deployment configuration
|
||||
YAML file. This instructs Kubernetes to _not_ use rolling
|
||||
updates. Rolling updates will not work, as you cannot have more than
|
||||
one Pod running at a time. The `Recreate` strategy will stop the
|
||||
first pod before creating a new one with the updated configuration.
|
||||
-->
|
||||
* 不要对应用进行规模扩缩。这里的设置仅适用于单实例应用。下层的 PersistentVolume
|
||||
仅只能挂载到一个 Pod 上。对于集群级有状态应用,请参考
|
||||
[StatefulSet 文档](/zh/docs/concepts/workloads/controllers/statefulset/).
|
||||
* 在 Deployment 的 YAML 文件中使用 `strategy:` `type: Recreate`。
|
||||
该选项指示 Kubernetes _不_ 使用滚动升级。滚动升级无法工作,因为这里一次不能
|
||||
运行多个 Pod。在使用更新的配置文件创建新的 Pod 前,`Recreate` 策略将
|
||||
保证先停止第一个 Pod。
|
||||
|
||||
<!--
|
||||
## Deleting a deployment
|
||||
|
||||
Delete the deployed objects by name:
|
||||
-->
|
||||
## 删除 Deployment {#deleting-a-deployment}
|
||||
|
||||
通过名称删除部署的对象:
|
||||
|
||||
```
|
||||
kubectl delete deployment,svc mysql
|
||||
kubectl delete pvc mysql-pv-claim
|
||||
kubectl delete pv mysql-pv-volume
|
||||
```
|
||||
|
||||
<!--
|
||||
If you manually provisioned a PersistentVolume, you also need to manually
|
||||
delete it, as well as release the underlying resource.
|
||||
If you used a dynamic provisioner, it automatically deletes the
|
||||
PersistentVolume when it sees that you deleted the PersistentVolumeClaim.
|
||||
Some dynamic provisioners (such as those for EBS and PD) also release the
|
||||
underlying resource upon deleting the PersistentVolume.
|
||||
-->
|
||||
如果通过手动的方式供应 PersistentVolume, 那么也需要手动删除它以释放下层资源。
|
||||
如果是用动态供应方式创建的 PersistentVolume,在删除 PersistentVolumeClaim 后
|
||||
PersistentVolume 将被自动删除。
|
||||
一些存储服务(比如 EBS 和 PD)也会在 PersistentVolume 被删除时自动回收下层资源。
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
* Learn more about [Deployment objects](/docs/concepts/workloads/controllers/deployment/).
|
||||
|
||||
* Learn more about [Deploying applications](/docs/tasks/run-application/run-stateless-application-deployment/)
|
||||
|
||||
* [kubectl run documentation](/docs/reference/generated/kubectl/kubectl-commands/#run)
|
||||
|
||||
* [Volumes](/docs/concepts/storage/volumes/) and [Persistent Volumes](/docs/concepts/storage/persistent-volumes/)
|
||||
-->
|
||||
* 欲进一步了解 Deployment 对象,请参考 [Deployment 对象](/zh/docs/concepts/workloads/controllers/deployment/)
|
||||
* 进一步了解[部署应用](/zh/docs/tasks/run-application/run-stateless-application-deployment/)
|
||||
|
||||
* 参阅 [kubectl run 文档](/docs/reference/generated/kubectl/kubectl-commands/#run)
|
||||
|
||||
* 参阅[卷](/zh/docs/concepts/storage/volumes/)和[持久卷](/zh/docs/concepts/storage/persistent-volumes/)
|
||||
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: 使用 Deployment 运行一个无状态应用
|
||||
min-kubernetes-server-version: v1.9
|
||||
content_type: tutorial
|
||||
weight: 10
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
<!--
|
||||
This page shows how to run an application using a Kubernetes Deployment object.
|
||||
-->
|
||||
本文介绍如何通过 Kubernetes Deployment 对象去运行一个应用.
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
<!--
|
||||
* Create an nginx deployment.
|
||||
* Use kubectl to list information about the deployment.
|
||||
* Update the deployment.
|
||||
-->
|
||||
* 创建一个 nginx Deployment.
|
||||
* 使用 kubectl 列举关于 Deployment 的信息.
|
||||
* 更新 Deployment。
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
<!-- lessoncontent -->
|
||||
|
||||
<!--
|
||||
## Creating and exploring an nginx deployment
|
||||
|
||||
You can run an application by creating a Kubernetes Deployment object, and you
|
||||
can describe a Deployment in a YAML file. For example, this YAML file describes
|
||||
a Deployment that runs the nginx:1.14.2 Docker image:
|
||||
-->
|
||||
## 创建并了解一个 nginx Deployment
|
||||
|
||||
你可以通过创建一个 Kubernetes Deployment 对象来运行一个应用, 且你可以在一个
|
||||
YAML 文件中描述 Deployment。例如, 下面这个 YAML 文件描述了一个运行 nginx:1.14.2
|
||||
Docker 镜像的 Deployment:
|
||||
|
||||
{{< codenew file="application/deployment.yaml" >}}
|
||||
|
||||
<!--
|
||||
1. Create a Deployment based on the YAML file:
|
||||
-->
|
||||
1. 通过 YAML 文件创建一个 Deployment:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Display information about the Deployment:
|
||||
-->
|
||||
2. 显示 Deployment 相关信息:
|
||||
|
||||
```shell
|
||||
kubectl describe deployment nginx-deployment
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出类似于这样:
|
||||
|
||||
```
|
||||
Name: nginx-deployment
|
||||
Namespace: default
|
||||
CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700
|
||||
Labels: app=nginx
|
||||
Annotations: deployment.kubernetes.io/revision=1
|
||||
Selector: app=nginx
|
||||
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
Pod Template:
|
||||
Labels: app=nginx
|
||||
Containers:
|
||||
nginx:
|
||||
Image: nginx:1.7.9
|
||||
Port: 80/TCP
|
||||
Environment: <none>
|
||||
Mounts: <none>
|
||||
Volumes: <none>
|
||||
Conditions:
|
||||
Type Status Reason
|
||||
---- ------ ------
|
||||
Available True MinimumReplicasAvailable
|
||||
Progressing True NewReplicaSetAvailable
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created)
|
||||
No events.
|
||||
```
|
||||
|
||||
<!--
|
||||
1. List the Pods created by the deployment:
|
||||
-->
|
||||
3. 列出 Deployment 创建的 Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=nginx
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出类似于这样:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h
|
||||
nginx-deployment-1771418926-r18az 1/1 Running 0 16h
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Display information about a Pod:
|
||||
-->
|
||||
4. 展示某一个 Pod 信息:
|
||||
|
||||
```shell
|
||||
kubectl describe pod <pod-name>
|
||||
```
|
||||
|
||||
<!--
|
||||
where `<pod-name>` is the name of one of your Pods.
|
||||
-->
|
||||
这里的 `<pod-name>` 是某一 Pod 的名称。
|
||||
|
||||
<!--
|
||||
## Updating the deployment
|
||||
|
||||
You can update the deployment by applying a new YAML file. This YAML file
|
||||
specifies that the deployment should be updated to use nginx 1.16.1.
|
||||
-->
|
||||
## 更新 Deployment
|
||||
|
||||
你可以通过更新一个新的 YAML 文件来更新 Deployment。下面的 YAML 文件指定该
|
||||
Deployment 镜像更新为 nginx 1.16.1。
|
||||
|
||||
{{< codenew file="application/deployment-update.yaml" >}}
|
||||
|
||||
<!--
|
||||
1. Apply the new YAML file:
|
||||
-->
|
||||
1. 应用新的 YAML:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Watch the deployment create pods with new names and delete the old pods:
|
||||
-->
|
||||
2. 查看该 Deployment 以新的名称创建 Pods 同时删除旧的 Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=nginx
|
||||
```
|
||||
<!--
|
||||
## Scaling the application by increasing the replica count
|
||||
|
||||
You can increase the number of Pods in your Deployment by applying a new YAML
|
||||
file. This YAML file sets `replicas` to 4, which specifies that the Deployment
|
||||
should have four Pods:
|
||||
-->
|
||||
## 通过增加副本数来扩缩应用
|
||||
|
||||
你可以通过应用新的 YAML 文件来增加 Deployment 中 Pods 的数量。
|
||||
下面的 YAML 文件将 `replicas` 设置为 4,指定该 Deployment 应有 4 个 Pods:
|
||||
|
||||
{{< codenew file="application/deployment-scale.yaml" >}}
|
||||
|
||||
<!--
|
||||
1. Apply the new YAML file:
|
||||
-->
|
||||
1. 应用新的 YAML 文件:
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
|
||||
```
|
||||
|
||||
<!--
|
||||
1. Verify that the Deployment has four Pods:
|
||||
-->
|
||||
2. 验证 Deployment 有 4 个 Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=nginx
|
||||
```
|
||||
|
||||
<!--
|
||||
The output is similar to this:
|
||||
-->
|
||||
输出的结果类似于:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-148880595-4zdqq 1/1 Running 0 25s
|
||||
nginx-deployment-148880595-6zgi1 1/1 Running 0 25s
|
||||
nginx-deployment-148880595-fxcez 1/1 Running 0 2m
|
||||
nginx-deployment-148880595-rwovn 1/1 Running 0 2m
|
||||
```
|
||||
|
||||
<!--
|
||||
## Deleting a deployment
|
||||
|
||||
Delete the deployment by name:
|
||||
-->
|
||||
## 删除 Deployment
|
||||
|
||||
基于名称删除 Deployment:
|
||||
|
||||
```shell
|
||||
kubectl delete deployment nginx-deployment
|
||||
```
|
||||
|
||||
<!--
|
||||
## ReplicationControllers -- the Old Way
|
||||
|
||||
The preferred way to create a replicated application is to use a Deployment,
|
||||
which in turn uses a ReplicaSet. Before the Deployment and ReplicaSet were
|
||||
added to Kubernetes, replicated applications were configured using a
|
||||
[ReplicationController](/docs/concepts/workloads/controllers/replicationcontroller/).
|
||||
-->
|
||||
## ReplicationControllers -- 旧的方式
|
||||
|
||||
创建一个多副本应用首选方法是使用 Deployment,Deployment 内部使用 ReplicaSet。
|
||||
在 Deployment 和 ReplicaSet 被引入到 Kubernetes 之前,多副本应用通过
|
||||
[ReplicationController](/zh/docs/concepts/workloads/controllers/replicationcontroller/)
|
||||
来配置。
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
* Learn more about [Deployment objects](/docs/concepts/workloads/controllers/deployment/).
|
||||
-->
|
||||
* 进一步了解 [Deployment 对象](/zh/docs/concepts/workloads/controllers/deployment/)。
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
---
|
||||
title: 扩缩 StatefulSet
|
||||
content_type: task
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
<!--
|
||||
This task shows how to scale a StatefulSet. Scaling a StatefulSet refers to increasing or decreasing the number of replicas.
|
||||
-->
|
||||
本文介绍如何扩缩StatefulSet。StatefulSet 的扩缩指的是增加或者减少副本个数。
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
<!--
|
||||
* StatefulSets are only available in Kubernetes version 1.5 or later.
|
||||
To check your version of Kubernetes, run `kubectl version`.
|
||||
|
||||
* Not all stateful applications scale nicely. If you are unsure about whether to scale your StatefulSets, see [StatefulSet concepts](/docs/concepts/workloads/controllers/statefulset/) or [StatefulSet tutorial](/docs/tutorials/stateful-application/basic-stateful-set/) for further information.
|
||||
|
||||
* You should perform scaling only when you are confident that your stateful application
|
||||
cluster is completely healthy.
|
||||
-->
|
||||
* StatefulSets 仅适用于 Kubernetes 1.5 及以上版本。
|
||||
* 不是所有 Stateful 应用都能很好地执行扩缩操作。
|
||||
如果你不是很确定是否要扩缩你的 StatefulSet,可先参阅
|
||||
[StatefulSet 概念](/zh/docs/concepts/workloads/controllers/statefulset/)
|
||||
或者 [StatefulSet 教程](/zh/docs/tutorials/stateful-application/basic-stateful-set/)。
|
||||
|
||||
* 仅当你确定你的有状态应用的集群是完全健康的,才可执行扩缩操作.
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
<!--
|
||||
## Scaling StatefulSets
|
||||
|
||||
### Use kubectl to scale StatefulSets
|
||||
|
||||
First, find the StatefulSet you want to scale.
|
||||
|
||||
```shell
|
||||
kubectl get statefulsets <stateful-set-name>
|
||||
```
|
||||
-->
|
||||
## 扩缩 StatefulSet {#scaling-statefulset}
|
||||
|
||||
## 使用 `kubectl` 扩缩 StatefulSet
|
||||
|
||||
首先,找到你要扩缩的 StatefulSet。
|
||||
|
||||
```shell
|
||||
kubectl get statefulsets <statefulset 名称>
|
||||
```
|
||||
|
||||
<!--
|
||||
Change the number of replicas of your StatefulSet:
|
||||
|
||||
```shell
|
||||
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
||||
```
|
||||
-->
|
||||
更改 StatefulSet 中副本个数:
|
||||
|
||||
```shell
|
||||
kubectl scale statefulsets <statefulset 名称> --replicas=<新的副本数>
|
||||
```
|
||||
|
||||
<!--
|
||||
### Make in-place updates on your StatefulSets
|
||||
|
||||
Alternatively, you can do [in-place updates](/docs/concepts/cluster-administration/manage-deployment/#in-place-updates-of-resources) on your StatefulSets.
|
||||
|
||||
If your StatefulSet was initially created with `kubectl apply`,
|
||||
update `.spec.replicas` of the StatefulSet manifests, and then do a `kubectl apply`:
|
||||
-->
|
||||
### 对 StatefulSet 执行就地更新
|
||||
|
||||
另外, 你可以[就地更新](/zh/docs/concepts/cluster-administration/manage-deployment/#in-place-updates-of-resources) StatefulSet。
|
||||
|
||||
如果你的 StatefulSet 最初通过 `kubectl apply` 或 `kubectl create --save-config` 创建,
|
||||
你可以更新 StatefulSet 清单中的 `.spec.replicas`, 然后执行命令 `kubectl apply`:
|
||||
|
||||
<!--
|
||||
```shell
|
||||
kubectl apply -f <stateful-set-file-updated>
|
||||
```
|
||||
|
||||
Otherwise, edit that field with `kubectl edit`:
|
||||
|
||||
```shell
|
||||
kubectl edit statefulsets <stateful-set-name>
|
||||
```
|
||||
|
||||
Or use `kubectl patch`:
|
||||
|
||||
```shell
|
||||
kubectl patch statefulsets <stateful-set-name> -p '{"spec":{"replicas":<new-replicas>}}'
|
||||
```
|
||||
-->
|
||||
```shell
|
||||
kubectl apply -f <更新后的 statefulset 文件>
|
||||
```
|
||||
|
||||
否则,可以使用 `kubectl edit` 编辑副本字段:
|
||||
|
||||
```shell
|
||||
kubectl edit statefulsets <statefulset 名称>
|
||||
```
|
||||
|
||||
或者使用 `kubectl patch`:
|
||||
|
||||
```shell
|
||||
kubectl patch statefulsets <statefulset 名称> -p '{"spec":{"replicas":<new-replicas>}}'
|
||||
```
|
||||
|
||||
<!--
|
||||
## Troubleshooting
|
||||
|
||||
### Scaling down does not work right
|
||||
-->
|
||||
## 故障排查 {#troubleshooting}
|
||||
|
||||
### 缩容操作无法正常工作
|
||||
|
||||
<!--
|
||||
You cannot scale down a StatefulSet when any of the stateful Pods it manages is unhealthy. Scaling down only takes place
|
||||
after those stateful Pods become running and ready.
|
||||
|
||||
If spec.replicas > 1, Kubernetes cannot determine the reason for an unhealthy Pod. It might be the result of a permanent fault or of a transient fault. A transient fault can be caused by a restart required by upgrading or maintenance.
|
||||
-->
|
||||
当 Stateful 所管理的任何 Pod 不健康时,你不能对该 StatefulSet 执行缩容操作。
|
||||
仅当 StatefulSet 的所有 Pod 都处于运行状态和 Ready 状况后才可缩容.
|
||||
|
||||
如果 `spec.replicas` 大于 1,Kubernetes 无法判定 Pod 不健康的原因。
|
||||
Pod 不健康可能是由于永久性故障造成也可能是瞬态故障。
|
||||
瞬态故障可能是节点升级或维护而引起的节点重启造成的。
|
||||
|
||||
<!--
|
||||
If the Pod is unhealthy due to a permanent fault, scaling
|
||||
without correcting the fault may lead to a state where the StatefulSet membership
|
||||
drops below a certain minimum number of replicas that are needed to function
|
||||
correctly. This may cause your StatefulSet to become unavailable.
|
||||
-->
|
||||
如果该 Pod 不健康是由于永久性故障导致, 则在不纠正该故障的情况下进行缩容可能会导致
|
||||
StatefulSet 进入一种状态,其成员 Pod 数量低于应正常运行的副本数。
|
||||
这种状态也许会导致 StatefulSet 不可用。
|
||||
|
||||
<!--
|
||||
If the Pod is unhealthy due to a transient fault and the Pod might become available again,
|
||||
the transient error may interfere with your scale-up or scale-down operation. Some distributed
|
||||
databases have issues when nodes join and leave at the same time. It is better
|
||||
to reason about scaling operations at the application level in these cases, and
|
||||
perform scaling only when you are sure that your stateful application cluster is
|
||||
completely healthy.
|
||||
-->
|
||||
如果由于瞬态故障而导致 Pod 不健康并且 Pod 可能再次变为可用,那么瞬态错误可能会干扰
|
||||
你对 StatefulSet 的扩容/缩容操作。 一些分布式数据库在同时有节点加入和离开时
|
||||
会遇到问题。在这些情况下,最好是在应用级别进行分析扩缩操作的状态, 并且只有在确保
|
||||
Stateful 应用的集群是完全健康时才执行扩缩操作。
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
<!--
|
||||
* Learn more about [deleting a StatefulSet](/docs/tasks/run-application/delete-stateful-set/).
|
||||
-->
|
||||
* 进一步了解[删除 StatefulSet](/zh/docs/tasks/run-application/delete-stateful-set/)
|
||||
|
||||
Reference in New Issue
Block a user