Merge branch 'master' into hyq-0427

This commit is contained in:
Cria Hu
2021-04-30 15:48:11 +08:00
committed by GitHub
125 changed files with 5935 additions and 4254 deletions
@@ -141,6 +141,7 @@ CSI ephemeral volumes are only supported by a subset of CSI drivers.
The Kubernetes CSI [Drivers list](https://kubernetes-csi.github.io/docs/drivers.html)
shows which drivers support ephemeral volumes.
-->
该特性需要启用参数 `CSIInlineVolume`
[特性门控(feature gate](/zh/docs/reference/command-line-tools-reference/feature-gates/)。
该参数从 Kubernetes 1.16 开始默认启用。
@@ -158,7 +159,7 @@ Conceptually, CSI ephemeral volumes are similar to `configMap`,
scheduled onto a node. Kubernetes has no concept of rescheduling Pods
anymore at this stage. Volume creation has to be unlikely to fail,
otherwise Pod startup gets stuck. In particular, [storage capacity
aware Pod scheduling](/docs/concepts/storage-capacity/) is *not*
aware Pod scheduling](/docs/concepts/storage/storage-capacity/) is *not*
supported for these volumes. They are currently also not covered by
the storage resource usage limits of a Pod, because that is something
that kubelet can only enforce for storage that it manages itself.
@@ -218,19 +219,22 @@ As a cluster administrator, you can use a [PodSecurityPolicy](/docs/concepts/pol
-->
### 通用临时卷 {#generic-ephemeral-volumes}
{{< feature-state for_k8s_version="v1.19" state="alpha" >}}
{{< feature-state for_k8s_version="v1.21" state="beta" >}}
<!--
This feature requires the `GenericEphemeralVolume` [feature gate](/docs/reference/command-line-tools-reference/feature-gates/) to be
enabled. Because this is an alpha feature, it is disabled by default.
enabled. Because this is a beta feature, it is enabled by default.
-->
这个特性需要启用 `GenericEphemeralVolume`
[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)。
因为这是一个alpha特性,默认用。
因为这是一个 beta 特性,默认情况下启用。
<!--
Generic ephemeral volumes are similar to `emptyDir` volumes, just more
flexible:
Generic ephemeral volumes are similar to `emptyDir` volumes in the
sense that they provide a per-pod directory for scratch data that is
usually empty after provisioning. But they may also have additional
features:
- Storage can be local or network-attached.
- Volumes can have a fixed size that Pods are not able to exceed.
- Volumes may have some initial data, depending on the driver and
@@ -240,11 +244,13 @@ flexible:
([snapshotting](/docs/concepts/storage/volume-snapshots/),
[cloning](/docs/concepts/storage/volume-pvc-datasource/),
[resizing](/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims),
and [storage capacity tracking](/docs/concepts/storage-capacity/).
and [storage capacity tracking](/docs/concepts/storage/storage-capacity/).
Example:
-->
通用临时卷类似于 `emptyDir`,但更加灵活:
通用临时卷 `emptyDir`类似,因为它们为暂存数据提供了一个 per-pod 的目录,该目录通常在置备后为空。
但他们可能还会有其他特征:
- 存储可以是本地的,也可以是网络连接的。
- 卷可以有固定的大小,pod不能超量使用。
- 卷可能有一些初始数据,这取决于驱动程序和参数。
@@ -408,23 +414,28 @@ two choices:
集群管理员必须意识到这一点。
如果这不符合他们的安全模型,他们有两种选择:
<!--
- Explicitly disable the feature through the feature gate, to avoid
being surprised when some future Kubernetes version enables it
by default.
- Explicitly disable the feature through the feature gate.
- Use a [Pod Security
Policy](/docs/concepts/policy/pod-security-policy/) where the
`volumes` list does not contain the `ephemeral` volume type.
`volumes` list does not contain the `ephemeral` volume type
(deprecated in Kubernetes 1.21).
- Use an [admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/)
which rejects objects like Pods that have a generic ephemeral
volume.
-->
- 通过特性门控显式禁用该特性,可以避免将来的 Kubernetes 版本默认启用时带来混乱
- 通过特性门控显式禁用该特性。
-`卷`列表不包含 `ephemeral` 卷类型时,使用
[Pod 安全策略](/zh/docs/concepts/policy/pod-security-policy/)
[Pod 安全策略](/zh/docs/concepts/policy/pod-security-policy/)
(在 Kubernetes 1.21 中已弃用)。
- 使用[准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/)
拒绝像 Pod 这样具有通用临时卷。
<!--
The normal namespace quota for PVCs in a namespace still applies, so
The normal [namespace quota for PVCs](/docs/concepts/policy/resource-quotas/#storage-resource-quota) still applies, so
even if users are allowed to use this new mechanism, they cannot use
it to circumvent other policies.
-->
在一个命名空间中,用于 PVCs 的常规命名空间配额仍然适用,
在一个命名空间中,用于 PVCs 的常规命名空间配额[用于 PVCs 的常规命名空间配额](/zh/docs/concepts/policy/resource-quotas/#storage-resource-quota)仍然适用,
因此即使允许用户使用这种新机制,他们也不能使用它来规避其他策略。
## {{% heading "whatsnext" %}}
@@ -0,0 +1,71 @@
---
title: 卷健康监测
content_type: concept
---
<!--
---
reviewers:
- jsafrane
- saad-ali
- msau42
- xing-yang
title: Volume Health Monitoring
content_type: concept
---
-->
<!-- overview -->
{{< feature-state for_k8s_version="v1.21" state="alpha" >}}
<!--
{{< glossary_tooltip text="CSI" term_id="csi" >}} volume health monitoring allows CSI Drivers to detect abnormal volume conditions from the underlying storage systems and report them as events on {{< glossary_tooltip text="PVCs" term_id="persistent-volume-claim" >}} or {{< glossary_tooltip text="Pods" term_id="pod" >}}.
-->
{{< glossary_tooltip text="CSI" term_id="csi" >}} 卷健康监测支持 CSI 驱动从底层的存储系统着手,探测异常的卷状态,并以事件的形式上报到 {{< glossary_tooltip text="PVCs" term_id="persistent-volume-claim" >}} 或 {{< glossary_tooltip text="Pods" term_id="pod" >}}.
<!-- body -->
<!--
## Volume health monitoring
-->
## 卷健康监测 {#volume-health-monitoring}
<!--
Kubernetes _volume health monitoring_ is part of how Kubernetes implements the Container Storage Interface (CSI). Volume health monitoring feature is implemented in two components: an External Health Monitor controller, and the {{< glossary_tooltip term_id="kubelet" text="kubelet" >}}.
If a CSI Driver supports Volume Health Monitoring feature from the controller side, an event will be reported on the related {{< glossary_tooltip text="PersistentVolumeClaim" term_id="persistent-volume-claim" >}} (PVC) when an abnormal volume condition is detected on a CSI volume.
-->
Kubernetes _卷健康监测_ 是 Kubernetes 容器存储接口(CSI)实现的一部分。
卷健康监测特性由两个组件实现:外部健康监测控制器和 {{< glossary_tooltip term_id="kubelet" text="kubelet" >}}。
如果 CSI 驱动器通过控制器的方式支持卷健康监测特性,那么只要在 CSI 卷上监测到异常卷状态,就会在
{{< glossary_tooltip text="PersistentVolumeClaim" term_id="persistent-volume-claim" >}} (PVC)
中上报一个事件。
<!-- The External Health Monitor {{< glossary_tooltip text="controller" term_id="controller" >}} also watches for node failure events. You can enable node failure monitoring by setting the `enable-node-watcher` flag to true. When the external health monitor detects a node failure event, the controller reports an Event will be reported on the PVC to indicate that pods using this PVC are on a failed node.
If a CSI Driver supports Volume Health Monitoring feature from the node side, an Event will be reported on every Pod using the PVC when an abnormal volume condition is detected on a CSI volume.
-->
外部健康监测 {{< glossary_tooltip text="控制器" term_id="controller" >}} 也会监测节点失效事件。
如果要启动节点失效监测功能,你可以设置标志 `enable-node-watcher``true`
当外部健康监测器检测到一个节点失效事件,控制器会报送一个事件,该事件会在 PVC 上继续上报,
以表明使用此 PVC 的 Pod 正位于一个失效的节点上。
如果 CSI 驱动程序支持节点测的卷健康检测,那当在 CSI 卷上检测到异常卷时,会在使用该 PVC 的每个Pod 上触发一个事件。
<!--
You need to enable the `CSIVolumeHealth` [feature gate](/docs/reference/command-line-tools-reference/feature-gates/) to use this feature from the node side.
-->
{{< note >}}
你需要启用
`CSIVolumeHealth` [特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)
,才能从节点测使用此特性。
{{< /note >}}
## {{% heading "whatsnext" %}}
<!--
See the [CSI driver documentation](https://kubernetes-csi.github.io/docs/drivers.html) to find out which CSI drivers have implemented this feature.
-->
参阅 [CSI 驱动程序文档](https://kubernetes-csi.github.io/docs/drivers.html)
可以找出有那些 CSI 驱动程序已实现了此特性。
@@ -6,13 +6,13 @@ content_type: task
weight: 30
---
<!-- ---
<!--
reviewers:
- sig-cluster-lifecycle
title: Creating a cluster with kubeadm
content_type: task
weight: 30
--- -->
-->
<!-- overview -->
@@ -346,6 +346,20 @@ Alternatively, if you are the `root` user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
```
{{< warning >}}
<!--
Kubeadm signs the certificate in the `admin.conf` to have `Subject: O = system:masters, CN = kubernetes-admin`.
`system:masters` is a break-glass, super user group that bypasses the authorization layer (e.g. RBAC).
Do not share the `admin.conf` file with anyone and instead grant users custom permissions by generating
them a kubeconfig file using the `kubeadm kubeconfig user` command.
-->
kubeadm 对 `admin.conf` 中的证书进行签名时,将其配置为
`Subject: O = system:masters, CN = kubernetes-admin`
`system:masters` 是一个例外的、超级用户组,可以绕过鉴权层(例如 RBAC)。
不要将 `admin.conf` 文件与任何人共享,应该使用 `kubeadm kubeconfig user`
命令为其他用户生成 kubeconfig 文件,完成对他们的定制授权。
{{< /warning >}}
<!--
Make a record of the `kubeadm join` command that `kubeadm init` outputs. You
need this command to [join nodes to your cluster](#join-nodes).
@@ -428,13 +442,14 @@ Cluster DNS (CoreDNS) will not start up before a network is installed.**
{{< /caution >}}
<!--
Currently Calico is the only CNI plugin that the kubeadm project performs e2e tests against.
Kubeadm should be CNI agnostic and the validation of CNI providers is out of the scope of our current e2e testing.
If you find an issue related to a CNI plugin you should log a ticket in its respective issue
tracker instead of the kubeadm or kubernetes issue trackers.
-->
{{< note >}}
目前 Calico 是 kubeadm 项目中执行 e2e 测试的唯一 CNI 插件
如果你发现与 CNI 插件相关的问题,应在其各自的问题跟踪器中记录而不是在 kubeadm 或 kubernetes 问题跟踪器中记录。
kubeadm 应该是与 CNI 无关的,对 CNI 驱动进行验证目前不在我们的端到端测试范畴之内
如果你发现与 CNI 插件相关的问题,应在其各自的问题跟踪器中记录而不是在 kubeadm
或 kubernetes 问题跟踪器中记录。
{{< /note >}}
<!--
@@ -1,19 +1,15 @@
---
reviewers:
- sig-cluster-lifecycle
title: 利用 kubeadm 创建高可用集群
content_type: task
weight: 60
---
<!--
---
reviewers:
- sig-cluster-lifecycle
title: Creating Highly Available clusters with kubeadm
content_type: task
weight: 60
---
-->
<!-- overview -->
@@ -42,12 +38,12 @@ in the kubeadm [issue tracker](https://github.com/kubernetes/kubeadm/issues/new)
See also [The upgrade documentation](/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-15).
-->
在下一步之前,应该仔细考虑哪种方法更好的满足的应用程序和环境的需求。
在下一步之前,应该仔细考虑哪种方法更好的满足的应用程序和环境的需求。
[这是对比文档](/zh/docs/setup/production-environment/tools/kubeadm/ha-topology/) 讲述了每种方法的优缺点。
如果在安装 HA 集群时遇到问题,请在 kubeadm [问题跟踪](https://github.com/kubernetes/kubeadm/issues/new)里向我们提供反馈。
如果在安装 HA 集群时遇到问题,请在 kubeadm [问题跟踪](https://github.com/kubernetes/kubeadm/issues/new)里向我们提供反馈。
也可以阅读 [升级文件](/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/)
也可以阅读 [升级文件](/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/)
<!--
This page does not address running your cluster on a cloud provider. In a cloud
environment, neither approach documented here works with Service objects of type
@@ -66,7 +62,7 @@ LoadBalancer, or with dynamic PersistentVolumes.
For both methods you need this infrastructure:
- Three machines that meet [kubeadm's minimum requirements](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin) for
the masters
the control-plane nodes
- Three machines that meet [kubeadm's minimum
requirements](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin) for the workers
- Full network connectivity between all machines in the cluster (public or
@@ -75,44 +71,47 @@ For both methods you need this infrastructure:
- SSH access from one device to all nodes in the system
- `kubeadm` and `kubelet` installed on all machines. `kubectl` is optional.
-->
对于这两种方法,都需要以下基础设施:
对于这两种方法,都需要以下基础设施:
- 配置三台机器 [kubeadm 的最低要求](/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin) 给主节点
- 配置三台机器 [kubeadm 的最低要求](/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin) 给工作节点
- 在集群中,所有计算机之间的完全网络连接(公网或私网)
- 所有机器上的 sudo 权限
- 每台设备对系统中所有节点的 SSH 访问
- 在所有机器上安装 `kubeadm``kubelet``kubectl` 是可选的。
- 配置满足 [kubeadm 的最低要求](/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin)
的三台机器作为控制面节点
- 配置满足 [kubeadm 的最低要求](/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin)
的三台机器作为工作节点
- 在集群中,确保所有计算机之间存在全网络连接(公网或私网)
- 在所有机器上具有 sudo 权限
- 从某台设备通过 SSH 访问系统中所有节点的能力
- 所有机器上已经安装 `kubeadm``kubelet``kubectl` 是可选的。
<!--
For the external etcd cluster only, you also need:
- Three additional machines for etcd members
-->
仅对于外部 etcd 集群来说,还需要:
仅对于外部 etcd 集群来说,还需要:
- 给 etcd 成员使用的另外三台机器
<!-- steps -->
<!-- ## First steps for both methods -->
<!--
## First steps for both methods
### Create load balancer for kube-apiserver
-->
## 这两种方法的第一步
<!-- ### Create load balancer for kube-apiserver -->
### 为 kube-apiserver 创建负载均衡器
{{< note >}}
<!--
There are many configurations for load balancers. The following example is only one
option. Your cluster requirements may need a different configuration.
-->
{{< note >}}
使用负载均衡器需要许多配置。您的集群搭建可能需要不同的配置。下面的例子只是其中的一方面配置。
使用负载均衡器需要许多配置。你的集群搭建可能需要不同的配置。
下面的例子只是其中的一方面配置。
{{< /note >}}
<!--
1. Create a kube-apiserver load balancer with a name that resolves to DNS.
- In a cloud environment you should place your control plane nodes behind a TCP
@@ -135,15 +134,20 @@ option. Your cluster requirements may need a different configuration.
-->
1. 创建一个名为 kube-apiserver 的负载均衡器解析 DNS。
- 在云环境中,应该将控制平面节点放置在 TCP 后面转发负载平衡。 该负载均衡器将流量分配给目标列表中所有运行状况良好的控制平面节点。健康检查 apiserver 是在 kube-apiserver 监听端口(默认值 `:6443`)上的一个 TCP 检查。
- 在云环境中,应该将控制平面节点放置在 TCP 后面转发负载平衡。
该负载均衡器将流量分配给目标列表中所有运行状况良好的控制平面节点。
API 服务器的健康检查是在 kube-apiserver 的监听端口(默认值 `:6443`
上进行的一个 TCP 检查。
- 不建议在云环境中直接使用 IP 地址。
- 负载均衡器必须能够在 apiserver 端口上与所有控制平面节点通信。它还必须允许其监听端口的传入流量。
- 负载均衡器必须能够在 API 服务器端口上与所有控制平面节点通信。
它还必须允许其监听端口的入站流量。
- 确保负载均衡器的地址始终匹配 kubeadm 的 `ControlPlaneEndpoint` 地址。
- 阅读[软件负载平衡选项指南](https://github.com/kubernetes/kubeadm/blob/master/docs/ha-considerations.md#options-for-software-load-balancing)以获取更多详细信息。
- 阅读[软件负载平衡选项指南](https://github.com/kubernetes/kubeadm/blob/master/docs/ha-considerations.md#options-for-software-load-balancing)
以获取更多详细信息。
<!--
1. Add the first control plane nodes to the load balancer and test the
@@ -166,15 +170,19 @@ option. Your cluster requirements may need a different configuration.
nc -v LOAD_BALANCER_IP PORT
```
- 由于 apiserver 尚未运行,预期会出现一个连接拒绝错误。然而超时意味着负载均衡器不能和控制平面节点通信。
如果发生超时,请重新配置负载均衡器控制平面节点进行通信。
- 由于 apiserver 尚未运行,预期会出现一个连接拒绝错误。
然而超时意味着负载均衡器不能和控制平面节点通信。
如果发生超时,请重新配置负载均衡器与控制平面节点进行通信。
3. 将其余控制平面节点添加到负载均衡器目标组。
<!-- ## Stacked control plane and etcd nodes -->
<!--
## Stacked control plane and etcd nodes
### Steps for the first control plane node
-->
## 使用堆控制平面和 etcd 节点
<!-- ### Steps for the first control plane node -->
### 控制平面节点的第一步
<!--
@@ -183,8 +191,6 @@ option. Your cluster requirements may need a different configuration.
```sh
sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
```
- You can use the `--kubernetes-version` flag to set the Kubernetes version to use.
It is recommended that the versions of kubeadm, kubelet, kubectl and Kubernetes match.
- The `--control-plane-endpoint` flag should be set to the address or DNS and port of the load balancer.
@@ -196,142 +202,122 @@ option. Your cluster requirements may need a different configuration.
-->
1. 初始化控制平面:
```sh
```shell
sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
```
- 可以使用 `--kubernetes-version` 标志来设置要使用的 Kubernetes 版本。建议将 kubeadm、kebelet、kubectl 和 Kubernetes 的版本匹配。
- 可以使用 `--kubernetes-version` 标志来设置要使用的 Kubernetes 版本。
建议将 kubeadm、kebelet、kubectl 和 Kubernetes 的版本匹配。
- 这个 `--control-plane-endpoint` 标志应该被设置成负载均衡器的地址或 DNS 和端口。
- 这个 `--upload-certs` 标志用来将在所有控制平面实例之间的共享证书上传到集群。如果正好相反,你更喜欢手动地通过控制平面节点或者使用自动化
工具复制证书,请删除此标志并参考如下部分[证书分配手册](#manual-certs)。
- 这个 `--upload-certs` 标志用来将在所有控制平面实例之间的共享证书上传到集群。
如果正好相反,你更喜欢手动地通过控制平面节点或者使用自动化
工具复制证书,请删除此标志并参考如下部分[证书分配手册](#manual-certs)。
<!--
The `kubeadm init` flags `--config` and `--certificate-key` cannot be mixed, therefore if you want
to use the [kubeadm configuration](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2) you must add the `certificateKey` field in the appropriate config locations (under `InitConfiguration` and `JoinConfiguration: controlPlane`).
-->
{{< note >}}
标志 `kubeadm init`、`--config` 和 `--certificate-key` 不能混合使用,因此如果您要使用[kubeadm 配置](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2),您必须在相应的配置文件(位于 `InitConfiguration` 和 `JoinConfiguration: controlPlane`)添加 `certificateKey` 字段。
{{< /note >}}
{{< note >}}
<!--
The `kubeadm init` flags `--config` and `--certificate-key` cannot be mixed, therefore if you want
to use the [kubeadm configuration](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2) you must add the `certificateKey` field in the appropriate config locations (under `InitConfiguration` and `JoinConfiguration: controlPlane`).
-->
标志 `kubeadm init`、`--config` 和 `--certificate-key` 不能混合使用,
因此如果你要使用
[kubeadm 配置](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2)
你必须在相应的配置文件
(位于 `InitConfiguration` 和 `JoinConfiguration: controlPlane`)添加 `certificateKey` 字段。
{{< /note >}}
<!--
Some CNI network plugins like Calico require a CIDR such as `192.168.0.0/16` and
some like Weave do not. See the [CNI network documentation](/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network).
To add a pod CIDR pass the flag `--pod-network-cidr`, or if you are using a kubeadm configuration file
set the `podSubnet` field under the `networking` object of `ClusterConfiguration`.
-->
{{< note >}}
一些 CNI 网络插件如 Calico 需要 CIDR 例如 `192.168.0.0/16` 和一些像 Weave 没有。参考
[CNI 网络文档](/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network)。
通过传递 `--pod-network-cidr` 标志添加 pod CIDR,或者可以使用 kubeadm 配置文件,在 `ClusterConfiguration` 的 `networking` 对象下设置 `podSubnet` 字段。
{{< /note >}}
{{< note >}}
<!--
Some CNI network plugins like Calico require a CIDR such as `192.168.0.0/16` and
some like Weave do not. See the [CNI network documentation](/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network).
To add a pod CIDR pass the flag `--pod-network-cidr`, or if you are using a kubeadm configuration file
set the `podSubnet` field under the `networking` object of `ClusterConfiguration`.
-->
一些 CNI 网络插件如 Calico 需要 CIDR 例如 `192.168.0.0/16` 和一些像 Weave 没有。参考
[CNI 网络文档](/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network)。
通过传递 `--pod-network-cidr` 标志添加 pod CIDR,或者可以使用 kubeadm
配置文件,在 `ClusterConfiguration` 的 `networking` 对象下设置 `podSubnet` 字段。
{{< /note >}}
<!--
After the command completes you should see something like so:
<!--
- The output looks similar to:
-->
- 输出类似于:
```sh
...
You can now join any number of control-plane node by running the following command on each as a root:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
```sh
...
You can now join any number of control-plane node by running the following command on each as a root:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
```
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
```
<!--
- Copy this output to a text file. You will need it later to join control plane and worker nodes to the cluster.
- When `--upload-certs` is used with `kubeadm init`, the certificates of the primary control plane
are encrypted and uploaded in the `kubeadm-certs` Secret.
- To re-upload the certificates and generate a new decryption key, use the following command on a control plane
node that is already joined to the cluster:
```sh
sudo kubeadm init phase upload-certs --upload-certs
```
- You can also specify a custom `--certificate-key` during `init` that can later be used by `join`.
To generate such a key you can use the following command:
```sh
kubeadm alpha certs certificate-key
```
-->
- 命令完成后,您应该会看到类似以下内容:
```sh
...
现在,您可以通过在根目录上运行以下命令来加入任意数量的控制平面节点:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
请注意,证书密钥可以访问集群内敏感数据,请保密!
为了安全起见,将在两个小时内删除上传的证书; 如有必要,您可以使用 kubeadm 初始化上传证书阶段,之后重新加载证书。
然后,您可以通过在根目录上运行以下命令来加入任意数量的工作节点:
kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
```
- 将此输出复制到文本文件。 稍后您将需要它来将控制平面节点和辅助节点加入集群。
- 当 `--upload-certs` 与 `kubeadm init` 一起使用时,主控制平面的证书被加密并上传到 `kubeadm-certs` 密钥中。
-->
- 将此输出复制到文本文件。 稍后你将需要它来将控制平面节点和工作节点加入集群。
- 当 `--upload-certs` 与 `kubeadm init` 一起使用时,主控制平面的证书
被加密并上传到 `kubeadm-certs` Secret 中。
- 要重新上传证书并生成新的解密密钥,请在已加入集群节点的控制平面上使用以下命令:
```sh
```shell
sudo kubeadm init phase upload-certs --upload-certs
```
<!--
- You can also specify a custom `--certificate-key` during `init` that can later be used by `join`.
To generate such a key you can use the following command:
-->
- 你还可以在 `init` 期间指定自定义的 `--certificate-key`,以后可以由 `join` 使用。
要生成这样的密钥,可以使用以下命令:
- 您还可以在 `init` 期间指定自定义的 `--certificate-key`,以后可以由 `join` 使用。
要生成这样的密钥,可以使用以下命令:
```sh
kubeadm alpha certs certificate-key
```shell
kubeadm certs certificate-key
```
<!--
The `kubeadm-certs` Secret and decryption key expire after two hours.
-->
{{< note >}}
`kubeadm-certs` 密钥和解密密钥会在两个小时后失效。
{{< /note >}}
{{< note >}}
<!--
The `kubeadm-certs` Secret and decryption key expire after two hours.
-->
`kubeadm-certs` 密钥和解密密钥会在两个小时后失效。
{{< /note >}}
<!--
As stated in the command output, the certificate key gives access to cluster sensitive data, keep it secret!
-->
{{< caution >}}
正如命令输出中所述,证书密钥可访问群集敏感数据,并将其保密
{{< /caution >}}
{{< caution >}}
<!--
As stated in the command output, the certificate key gives access to cluster sensitive data, keep it secret!
-->
正如命令输出中所述,证书密钥可访问群集敏感数据。请妥善保管
{{< /caution >}}
<!--
1. Apply the CNI plugin of your choice:
[Follow these instructions](/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network) to install the CNI provider. Make sure the configuration corresponds to the Pod CIDR specified in the kubeadm configuration file if applicable.
In this example we are using Weave Net:
```sh
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
```
1. Type the following and watch the pods of the control plane components get started:
```sh
kubectl get pod -n kube-system -w
```
-->
1. 应用选择的 CNI 插件:
2. 应用你所选择的 CNI 插件:
[请遵循以下指示](/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network)
安装 CNI 提供程序。如果适用,请确保配置与 kubeadm 配置文件中指定的 Pod CIDR 相对应。
安装 CNI 提供程序。如果适用,请确保配置与 kubeadm 配置文件中指定的 Pod
CIDR 相对应。
在此示例中,我们使用 Weave Net:
```sh
```shell
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
```
1. 输入以下内容,并查看 pods 的控制平面组件启动:
<!--
1. Type the following and watch the pods of the control plane components get started:
-->
3. 输入以下内容,并查看控制平面组件的 Pods 启动:
```sh
```shell
kubectl get pod -n kube-system -w
```
@@ -340,14 +326,14 @@ As stated in the command output, the certificate key gives access to cluster sen
-->
### 其余控制平面节点的步骤
{{< note >}}
<!--
Since kubeadm version 1.15 you can join multiple control-plane nodes in parallel.
Prior to this version, you must join new control plane nodes sequentially, only after
the first node has finished initializing.
-->
{{< note >}}
从 kubeadm 1.15 版本开始,您可以并行加入多个控制平面节点。
在此版本之前,您必须在第一个节点初始化后才能依序的增加新的控制平面节点。
从 kubeadm 1.15 版本开始,你可以并行加入多个控制平面节点。
在此版本之前,你必须在第一个节点初始化后才能依序的增加新的控制平面节点。
{{< /note >}}
<!--
@@ -365,9 +351,9 @@ For each additional control plane node you should:
from the `kubeadm-certs` Secret in the cluster and be decrypted using the given key.
-->
对于每个其他控制平面节点,应该:
对于每个其他控制平面节点,应该:
1. 执行先前由第一个节点上的 `kubeadm init` 输出提供给的 join 命令。
1. 执行先前由第一个节点上的 `kubeadm init` 输出提供给的 join 命令。
它看起来应该像这样:
```sh
@@ -375,7 +361,8 @@ For each additional control plane node you should:
```
- 这个 `--control-plane` 命令通知 `kubeadm join` 创建一个新的控制平面。
- `--certificate-key ...` 将导致从集群中的 `kubeadm-certs` 秘钥下载控制平面证书并使用给定的密钥进行解密。
- `--certificate-key ...` 将导致从集群中的 `kubeadm-certs` Secret 下载
控制平面证书并使用给定的密钥进行解密。
<!--
## External etcd nodes
@@ -384,11 +371,10 @@ Setting up a cluster with external etcd nodes is similar to the procedure used f
with the exception that you should setup etcd first, and you should pass the etcd information
in the kubeadm config file.
-->
## 外部 etcd 节点
使用外部 etcd 节点设置集群类似于用于堆叠 etcd 的过程,
不同之处在于应该首先设置 etcd,并在 kubeadm 配置文件中传递 etcd 信息。
不同之处在于应该首先设置 etcd,并在 kubeadm 配置文件中传递 etcd 信息。
<!--
### Set up the etcd cluster
@@ -406,19 +392,18 @@ in the kubeadm config file.
scp /etc/kubernetes/pki/apiserver-etcd-client.key "${CONTROL_PLANE}":
```
- Replace the value of `CONTROL_PLANE` with the `user@host` of the first control plane machine.
- Replace the value of `CONTROL_PLANE` with the `user@host` of the first control-plane machine.
-->
### 设置 ectd 集群
1. 按照 [这些指示](/zh/docs/setup/production-environment/tools/kubeadm/setup-ha-etcd-with-kubeadm/) 去设置 etcd 集群。
1. 按照 [这些指示](/zh/docs/setup/production-environment/tools/kubeadm/setup-ha-etcd-with-kubeadm/)
去设置 etcd 集群。
1. 设置 SSH 在 [这](#manual-certs)描述。
1. 根据[这](#manual-certs)描述配置 SSH
1. 将以下文件从集群中的任何 etcd 节点复制到第一个控制平面节点:
```sh
```shell
export CONTROL_PLANE="ubuntu@10.0.0.7"
scp /etc/kubernetes/pki/etcd/ca.crt "${CONTROL_PLANE}":
scp /etc/kubernetes/pki/apiserver-etcd-client.crt "${CONTROL_PLANE}":
@@ -432,93 +417,86 @@ in the kubeadm config file.
1. Create a file called `kubeadm-config.yaml` with the following contents:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT"
etcd:
external:
endpoints:
- https://ETCD_0_IP:2379
- https://ETCD_1_IP:2379
- https://ETCD_2_IP:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
```yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT"
etcd:
external:
endpoints:
- https://ETCD_0_IP:2379
- https://ETCD_1_IP:2379
- https://ETCD_2_IP:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
```
-->
### 设置第一个控制平面节点
1. 用以下内容创建一个名为 `kubeadm-config.yaml` 的文件:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT"
etcd:
external:
endpoints:
- https://ETCD_0_IP:2379
- https://ETCD_1_IP:2379
- https://ETCD_2_IP:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
```yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT"
etcd:
external:
endpoints:
- https://ETCD_0_IP:2379
- https://ETCD_1_IP:2379
- https://ETCD_2_IP:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
```
<!--
The difference between stacked etcd and external etcd here is that the external etcd setup requires
a configuration file with the etcd endpoints under the `external` object for `etcd`.
In the case of the stacked etcd topology this is managed automatically.
-->
{{< note >}}
这里堆 etcd 和外部 etcd 之前的区别在于设置外部 etcd 需要一个 `etcd` 的 `external` 对象下带有 etcd 端点的配置文件。
如果是堆 etcd 技术,是自动管理的
{{< /note >}}
<!--
{{< note >}}
<!--
The difference between stacked etcd and external etcd here is that the external etcd setup requires
a configuration file with the etcd endpoints under the `external` object for `etcd`.
In the case of the stacked etcd topology this is managed automatically.
-->
这里的内部(stacked etcd 和外部 etcd 之前的区别在于设置外部 etcd
需要一个 `etcd` 的 `external` 对象下带有 etcd 端点的配置文件
如果是内部 etcd,是自动管理的。
{{< /note >}}
<!--
- Replace the following variables in the config template with the appropriate values for your cluster:
-->
- 在你的集群中,将配置模板中的以下变量替换为适当值:
- `LOAD_BALANCER_DNS`
- `LOAD_BALANCER_PORT`
- `ETCD_0_IP`
- `ETCD_1_IP`
- `ETCD_2_IP`
- `LOAD_BALANCER_DNS`
- `LOAD_BALANCER_PORT`
- `ETCD_0_IP`
- `ETCD_1_IP`
- `ETCD_2_IP`
<!--
The following steps are similar to the stacked etcd setup:
-->
以下的步骤与设置内置 etcd 的集群是相似的:
<!--
1. Run `sudo kubeadm init --config kubeadm-config.yaml --upload-certs` on this node.
1. Write the output join commands that are returned to a text file for later use.
1. Apply the CNI plugin of your choice. The given example is for Weave Net:
```sh
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
```
-->
1. 在节点上运行 `sudo kubeadm init --config kubeadm-config.yaml --upload-certs` 命令。
- 在您的集群中,将配置模板中的以下变量替换为适当值:
1. 记下输出的 join 命令,这些命令将在以后使用。
- `LOAD_BALANCER_DNS`
- `LOAD_BALANCER_PORT`
- `ETCD_0_IP`
- `ETCD_1_IP`
- `ETCD_2_IP`
1. 应用你选择的 CNI 插件。以下示例适用于 Weave Net:
以下的步骤与设置堆集群是相似的:
1. 在节点上运行 `sudo kubeadm init --config kubeadm-config.yaml --upload-certs` 命令。
1. 编写输出联接命令,这些命令将返回到文本文件以供以后使用。
1. 应用您选择的 CNI 插件。 给定以下示例适用于 Weave Net:
```sh
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
```
```shell
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
```
<!--
### Steps for the rest of the control plane nodes
@@ -529,34 +507,30 @@ The steps are the same as for the stacked etcd setup:
- Join each control plane node with the join command you saved to a text file. It's recommended
to join the control plane nodes one at a time.
- Don't forget that the decryption key from `--certificate-key` expires after two hours, by default.
-->
### 其他控制平面节点的步骤
步骤与设置 etcd 相同:
步骤与设置内置 etcd 相同:
- 确保第一个控制平面节点已完全初始化。
- 使用保存到文本文件的连接命令将每个控制平面节点连接在一起。建议一次加入一个控制平面节点。
- 使用保存到文本文件的 join 命令将每个控制平面节点连接在一起。
建议一次加入一个控制平面节点。
- 不要忘记默认情况下,`--certificate-key` 中的解密秘钥会在两个小时后过期。
<!-- ## Common tasks after bootstrapping control plane -->
<!--
## Common tasks after bootstrapping control plane
### Install workers
-->
## 列举控制平面之后的常见任务
<!-- ### Install workers -->
### 安装工作节点
<!--
Worker nodes can be joined to the cluster with the command you stored previously
as the output from the `kubeadm init` command:
```sh
sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
```
-->
可以使用之前存储的命令将工作节点加入集群中
作为 `kubeadm init` 命令的输出:
可以使用之前存储的 `kubeadm init` 命令的输出将工作节点加入集群中
```sh
sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
@@ -573,11 +547,10 @@ There are many ways to do this. In the following example we are using `ssh` and
SSH is required if you want to control all nodes from a single machine.
-->
## 手动证书分发 {#manual-certs}
如果选择不将 `kubeadm init` 与 `--upload-certs` 命令一起使用,
则意味着将必须手动将证书从主控制平面节点复制到
如果选择不将 `kubeadm init` 与 `--upload-certs` 命令一起使用,
则意味着将必须手动将证书从主控制平面节点复制到
将要加入的控制平面节点上。
有许多方法可以实现这种操作。在下面的例子中我们使用 `ssh` 和 `scp`
@@ -585,147 +558,106 @@ SSH is required if you want to control all nodes from a single machine.
如果要在单独的一台计算机控制所有节点,则需要 SSH。
<!--
1. Enable ssh-agent on your main device that has access to all other nodes in
the system:
```
eval $(ssh-agent)
```
1. Add your SSH identity to the session:
```
ssh-add ~/.ssh/path_to_private_key
```
1. SSH between nodes to check that the connection is working correctly.
- When you SSH to any node, make sure to add the `-A` flag:
```
ssh -A 10.0.0.7
```
- When using sudo on any node, make sure to preserve the environment so SSH
forwarding works:
```
sudo -E -s
```
1. Enable ssh-agent on your main device that has access to all other nodes in
the system:
-->
1. 在你的主设备上启用 ssh-agent,要求该设备能访问系统中的所有其他节点:
1. 在您的主设备上启动 ssh-agent,要求该设备能访问系统中的所有其他节点:
```shell
eval $(ssh-agent)
```
```
eval $(ssh-agent)
```
<!--
1. Add your SSH identity to the session:
-->
2. 将 SSH 身份添加到会话中:
1. 将 SSH 身份添加到会话中:
```shell
ssh-add ~/.ssh/path_to_private_key
```
```
ssh-add ~/.ssh/path_to_private_key
```
<!--
1. SSH between nodes to check that the connection is working correctly.
-->
3. 检查节点间的 SSH 以确保连接是正常运行的
1. 检查节点间的 SSH 以确保连接是正常运行的
<!--
- When you SSH to any node, make sure to add the `-A` flag:
-->
- SSH 到任何节点时,请确保添加 `-A` 标志:
- SSH 到任何节点时,请确保添加 `-A` 标志:
```shell
ssh -A 10.0.0.7
```
```
ssh -A 10.0.0.7
```
- 当在任何节点上使用 sudo 时,请确保环境完善,以便使用 SSH
转发任务
```
sudo -E -s
```
<!--
- When using sudo on any node, make sure to preserve the environment so SSH
forwarding works:
-->
- 当在任何节点上使用 sudo 时,请确保保持环境变量设置,以便 SSH
转发能够正常工作
```shell
sudo -E -s
```
<!--
1. After configuring SSH on all the nodes you should run the following script on the first control plane node after
running `kubeadm init`. This script will copy the certificates from the first control plane node to the other
control plane nodes:
In the following example, replace `CONTROL_PLANE_IPS` with the IP addresses of the
other control plane nodes.
```sh
USER=ubuntu # customizable
CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
```
-->
1. 在所有节点上配置 SSH 之后,您应该在运行过 `kubeadm init` 命令的第一个控制平面节点上运行以下脚本。
4. 在所有节点上配置 SSH 之后,你应该在运行过 `kubeadm init` 命令的第一个
控制平面节点上运行以下脚本。
该脚本会将证书从第一个控制平面节点复制到另一个控制平面节点:
在以下示例中,用其他控制平面节点的 IP 地址替换 `CONTROL_PLANE_IPS`。
<!--
In the following example, replace `CONTROL_PLANE_IPS` with the IP addresses of the
other control plane nodes.
-->
在以下示例中,用其他控制平面节点的 IP 地址替换 `CONTROL_PLANE_IPS`。
```sh
USER=ubuntu # 可自己设置
CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
```
```sh
USER=ubuntu # 可定制
CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
```
<!--
Copy only the certificates in the above list. kubeadm will take care of generating the rest of the certificates
with the required SANs for the joining control-plane instances. If you copy all the certificates by mistake,
the creation of additional nodes could fail due to a lack of required SANs.
-->
{{< caution >}}
只需要复制上面列表中的证书。kubeadm 将负责生成其余证书以及加入控制平面实例所需的 SAN。
如果错误地复制了所有证书,由于缺少所需的 SAN,创建其他节点可能会失败。
{{< /caution >}}
{{< caution >}}
<!--
Copy only the certificates in the above list. kubeadm will take care of generating the rest of the certificates
with the required SANs for the joining control-plane instances. If you copy all the certificates by mistake,
the creation of additional nodes could fail due to a lack of required SANs.
-->
只需要复制上面列表中的证书。kubeadm 将负责生成其余证书以及加入控制平面实例所需的 SAN。
如果错误地复制了所有证书,由于缺少所需的 SAN,创建其他节点可能会失败。
{{< /caution >}}
<!--
1. Then on each joining control plane node you have to run the following script before running `kubeadm join`.
This script will move the previously copied certificates from the home directory to `/etc/kubernetes/pki`:
```sh
USER=ubuntu # customizable
mkdir -p /etc/kubernetes/pki/etcd
mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
```
-->
1. 然后,在每个连接控制平面节点上,您必须先运行以下脚本,然后再运行 `kubeadm join`。
5. 然后,在每个即将加入集群的控制平面节点上,你必须先运行以下脚本,然后
再运行 `kubeadm join`。
该脚本会将先前复制的证书从主目录移动到 `/etc/kubernetes/pki`
```sh
USER=ubuntu # 可自己设置
mkdir -p /etc/kubernetes/pki/etcd
mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
```
```shell
USER=ubuntu # 可定制
mkdir -p /etc/kubernetes/pki/etcd
mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
```
@@ -495,66 +495,36 @@ kubeadm to tell it what to do.
kubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环。
<!--
## Configure cgroup driver used by kubelet on control-plane node
## Configure cgroup driver
When using Docker, kubeadm will automatically detect the cgroup driver for the kubelet
and set it in the `/var/lib/kubelet/kubeadm-flags.env` file during runtime.
If you are using a different CRI, you must pass your `cgroupDriver` value to `kubeadm init`, like so:
Both the container runtime and the kubelet have a property called
["cgroup driver"](/docs/setup/production-environment/container-runtimes/), which is important
for the management of cgroups on Linux machines.
-->
## 在控制平面节点上配置 kubelet 使用的 cgroup 驱动程序 {#configure-cgroup-driver-used-by-kubelet-on-contol-plane-node}
## 配置 cgroup 驱动程序 {#configure-cgroup-driver}
使用 Docker 时,kubeadm 会自动为其检测 cgroup 驱动并在运行时对
`/var/lib/kubelet/kubeadm-flags.env` 文件进行配置。
如果你在使用不同的 CRI,你必须为 `kubeadm init` 传递 `cgroupDriver`
值,像这样:
```yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: <value>
```
容器运行时和 kubelet 都具有名字为
["cgroup driver"](/zh/docs/setup/production-environment/container-runtimes/)
的属性,该属性对于在 Linux 机器上管理 CGroups 而言非常重要。
{{< warning >}}
<!--
For further details, please read [Using kubeadm init with a configuration file](/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file)
and the [`KubeletConfiguration` reference](/docs/reference/config-api/kubelet-config.v1beta1/)
Matching the container runtime and kubelet cgroup drivers is required or otherwise the kubelet process will fail.
Please mind, that you **only** have to do that if the cgroup driver of your CRI
is not `cgroupfs`, because that is the default value in the kubelet already.
See [Configuring a cgroup driver](/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/) for more details.
-->
进一步的相关细节,可参阅
[使用配置文件来执行 kubeadm init](/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file) 以及 [KubeletConfiguration](/docs/reference/config-api/kubelet-config.v1beta1/)
你需要确保容器运行时和 kubelet 所使用的是相同的 cgroup 驱动,否则 kubelet
进程会失败
请注意,你只需要在你的 cgroup 驱动程序不是 `cgroupfs` 时这么做,
因为它已经是 kubelet 中的默认值。
{{< note >}}
<!--
Since `--cgroup-driver` flag has been deprecated by the kubelet, if you have that in `/var/lib/kubelet/kubeadm-flags.env`
or `/etc/default/kubelet`(`/etc/sysconfig/kubelet` for RPMs), please remove it and use the KubeletConfiguration instead
(stored in `/var/lib/kubelet/config.yaml` by default).
-->
由于 kubelet 已经弃用了 `--cgroup-driver` 标志,如果你在配置文件
`/var/lib/kubelet/kubeadm-flags.env` 或者 `/etc/default/kubelet`
(对于 RPM 而言是 `/etc/sysconfig/kubelet`)包含此设置,请将其删除
并使用 KubeletConfiguration 作为替代(默认存储于
`/var/lib/kubelet/config.yaml` 文件中)。
{{< /note >}}
<!--
The automatic detection of cgroup driver for other container runtimes
like CRI-O and containerd is work in progress.
-->
自动检测其他容器运行时(例如 CRI-O 和 containerd)的 cgroup 驱动的相关
工作扔在进行中。
相关细节可参见[配置 cgroup 驱动](/zh/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/)。
{{< /warning >}}
<!--
## Troubleshooting
If you are running into difficulties with kubeadm, please consult our [troubleshooting docs](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/).
-->
## 故障排查
## 故障排查 {#troubleshooting}
如果你在使用 kubeadm 时遇到困难,请参阅我们的
[故障排查文档](/zh/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/)。
@@ -6,13 +6,11 @@ content_type: concept
weight: 80
---
<!--
---
reviewers:
- sig-cluster-lifecycle
title: Configuring each kubelet in your cluster using kubeadm
content_type: concept
weight: 80
---
-->
<!-- overview -->
@@ -33,10 +31,11 @@ manager instead, but you need to configure it manually.
Some kubelet configuration details need to be the same across all kubelets involved in the cluster, while
other configuration aspects need to be set on a per-kubelet basis to accommodate the different
characteristics of a given machine (such as OS, storage, and networking). You can manage the configuration
of your kubelets manually, but kubeadm now provides a `KubeletConfiguration` API type for [managing your
kubelet configurations centrally](#configure-kubelets-using-kubeadm).
of your kubelets manually, but kubeadm now provides a `KubeletConfiguration` API type for
[managing your kubelet configurations centrally](#configure-kubelets-using-kubeadm).
-->
kubeadm CLI 工具的生命周期与 [kubelet](/zh/docs/reference/command-line-tools-reference/kubelet)解耦,它是一个守护程序,在 Kubernetes 集群中的每个节点上运行。
kubeadm CLI 工具的生命周期与 [kubelet](/zh/docs/reference/command-line-tools-reference/kubelet)
解耦;kubelet 是一个守护程序,在 Kubernetes 集群中的每个节点上运行。
当 Kubernetes 初始化或升级时,kubeadm CLI 工具由用户执行,而 kubelet 始终在后台运行。
由于kubelet是守护程序,因此需要通过某种初始化系统或服务管理器进行维护。
@@ -48,8 +47,6 @@ kubeadm CLI 工具的生命周期与 [kubelet](/zh/docs/reference/command-line-t
你可以手动地管理 kubelet 的配置,但是 kubeadm 现在提供一种 `KubeletConfiguration` API 类型
用于[集中管理 kubelet 的配置](#configure-kubelets-using-kubeadm)。
<!-- body -->
<!--
@@ -80,8 +77,9 @@ Virtual IPs for services are now allocated from this subnet. You also need to se
by the kubelet, using the `--cluster-dns` flag. This setting needs to be the same for every kubelet
on every manager and Node in the cluster. The kubelet provides a versioned, structured API object
that can configure most parameters in the kubelet and push out this configuration to each running
kubelet in the cluster. This object is called **the kubelet's ComponentConfig**.
The ComponentConfig allows the user to specify flags such as the cluster DNS IP addresses expressed as
kubelet in the cluster. This object is called
[`KubeletConfiguration`](/docs/reference/config-api/kubelet-config.v1beta1/).
The `KubeletConfiguration` allows the user to specify flags such as the cluster DNS IP addresses expressed as
a list of values to a camelCased key, illustrated by the following example:
```yaml
@@ -90,6 +88,8 @@ kind: KubeletConfiguration
clusterDNS:
- 10.96.0.10
```
For more details on the `KubeletConfiguration` have a look at [this section](#configure-kubelets-using-kubeadm).
-->
### 将集群级配置传播到每个 kubelet 中
@@ -106,8 +106,8 @@ kubeadm init --service-cidr 10.96.0.0/12
你还需要通过 kubelet 使用 `--cluster-dns` 标志设置 DNS 地址。
在集群中的每个管理器和节点上的 kubelet 的设置需要相同。
kubelet 提供了一个版本化的结构化 API 对象,该对象可以配置 kubelet 中的大多数参数,并将此配置推送到集群中正在运行的每个 kubelet 上。
此对象被称为 **kubelet 的配置组件**
该配置组件允许用户指定标志,例如用骆峰值代表集群的 DNS IP 地址,如下所示:
此对象被称为 [`KubeletConfiguration`](/zh/docs/reference/config-api/kubelet-config.v1beta1/)
`KubeletConfiguration` 允许用户指定标志,例如用骆峰值代表集群的 DNS IP 地址,如下所示:
```yaml
apiVersion: kubelet.config.k8s.io/v1beta1
@@ -116,7 +116,7 @@ clusterDNS:
- 10.96.0.10
```
有关组件配置的更多详细信息,亲参阅 [本节](#configure-kubelets-using-kubeadm)。
有关 `KubeletConfiguration` 的更多详细信息,亲参阅[本节](#configure-kubelets-using-kubeadm)。
<!--
### Providing instance-specific configuration details
@@ -175,8 +175,8 @@ API object is passed with a configuration file like so `kubeadm ... --config som
By calling `kubeadm config print init-defaults --component-configs KubeletConfiguration` you can
see all the default values for this structure.
Also have a look at the [API reference for the
kubelet ComponentConfig](https://godoc.org/k8s.io/kubernetes/pkg/kubelet/apis/config#KubeletConfiguration)
Also have a look at the
[reference for the KubeletConfiguration](/docs/reference/config-api/kubelet-config.v1beta1/)
for more information on the individual fields.
-->
## 使用 kubeadm 配置 kubelet
@@ -186,7 +186,8 @@ for more information on the individual fields.
通过调用 `kubeadm config print init-defaults --component-configs KubeletConfiguration`
你可以看到此结构中的所有默认值。
也可以阅读 [kubelet 配置组件的 API 参考](https://godoc.org/k8s.io/kubernetes/pkg/kubelet/apis/config#KubeletConfiguration)来获取有关各个字段的更多信息。
也可以阅读 [KubeletConfiguration 参考](/docs/reference/config-api/kubelet-config.v1beta1/)
来获取有关各个字段的更多信息。
<!--
### Workflow when using `kubeadm init`
@@ -291,9 +292,13 @@ kubelet 使用这些证书执行 TLS 引导程序并获取唯一的凭据,该
`kubeadm` ships with configuration for how systemd should run the kubelet.
Note that the kubeadm CLI command never touches this drop-in file.
This configuration file installed by the `kubeadm` [DEB](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf) or [RPM package](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/rpm/kubeadm/10-kubeadm.conf) is written to
This configuration file installed by the `kubeadm`
[DEB](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf) or
[RPM package](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/rpm/kubeadm/10-kubeadm.conf) is written to
`/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` and is used by systemd.
It augments the basic [`kubelet.service` for RPM](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/rpm/kubelet/kubelet.service) or [`kubelet.service` for DEB](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/deb/kubelet/lib/systemd/system/kubelet.service):
It augments the basic
[`kubelet.service` for RPM](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/rpm/kubelet/kubelet.service) or
[`kubelet.service` for DEB](https://github.com/kubernetes/release/blob/master/cmd/kubepkg/templates/latest/deb/kubelet/lib/systemd/system/kubelet.service):
```none
[Service]
@@ -365,14 +370,14 @@ ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELE
The DEB and RPM packages shipped with the Kubernetes releases are:
| Package name | Description |
|--------------|-------------|
| `kubeadm` | Installs the `/usr/bin/kubeadm` CLI tool and the [kubelet drop-in file](#the-kubelet-drop-in-file-for-systemd) for the kubelet. |
| `kubelet` | Installs the kubelet binary in `/usr/bin` and CNI binaries in `/opt/cni/bin`. |
| `kubectl` | Installs the `/usr/bin/kubectl` binary. |
| `cri-tools` | Installs the `/usr/bin/crictl` binary from the [cri-tools git repository](https://github.com/kubernetes-sigs/cri-tools). |
| Package name | Description |
|----------------|-------------|
| `kubeadm` | Installs the `/usr/bin/kubeadm` CLI tool and the [kubelet drop-in file](#the-kubelet-drop-in-file-for-systemd) for the kubelet. |
| `kubelet` | Installs the kubelet binary in `/usr/bin` and CNI binaries in `/opt/cni/bin`. |
| `kubectl` | Installs the `/usr/bin/kubectl` binary. |
| `cri-tools` | Installs the `/usr/bin/crictl` binary from the [cri-tools git repository](https://github.com/kubernetes-sigs/cri-tools). |
-->
## Kubernetes 二进制文件和软件包内容
## Kubernetes 可执行文件和软件包内容
Kubernetes 版本对应的 DEB 和 RPM 软件包是:
@@ -383,4 +388,3 @@ Kubernetes 版本对应的 DEB 和 RPM 软件包是:
| `kubectl` | 安装 `/usr/bin/kubectl` 可执行文件。 |
| `cri-tools` | 从 [cri-tools git 仓库](https://github.com/kubernetes-sigs/cri-tools)中安装 `/usr/bin/crictl` 可执行文件。 |
@@ -5,13 +5,11 @@ weight: 70
---
<!--
---
reviewers:
- sig-cluster-lifecycle
title: Set up a High Availability etcd cluster with kubeadm
content_type: task
weight: 70
---
-->
<!-- overview -->
@@ -35,7 +33,7 @@ becoming unavailable. This task walks through the process of creating a high
availability etcd cluster of three members that can be used as an external etcd
when using kubeadm to set up a kubernetes cluster.
-->
默认情况下,kubeadm 运行单成员的 etcd 集群,该集群由控制面节点上的 kubelet 以静态 Pod 的方式进行管理。由于 etcd 集群只包含一个成员且不能在任一成员不可用时保持运行,所以这不是一种高可用设置。本任务,将告诉如何在使用 kubeadm 创建一个 kubernetes 集群时创建一个外部 etcd:有三个成员的高可用 etcd 集群。
默认情况下,kubeadm 运行单成员的 etcd 集群,该集群由控制面节点上的 kubelet 以静态 Pod 的方式进行管理。由于 etcd 集群只包含一个成员且不能在任一成员不可用时保持运行,所以这不是一种高可用设置。本任务,将告诉如何在使用 kubeadm 创建一个 kubernetes 集群时创建一个外部 etcd:有三个成员的高可用 etcd 集群。
@@ -85,334 +83,287 @@ kubeadm 包含生成下述证书所需的所有必要的密码学工具;在这
<!--
1. Configure the kubelet to be a service manager for etcd.
Since etcd was created first, you must override the service priority by creating a new unit file
that has higher precedence than the kubeadm-provided kubelet unit file.
{{< note >}}You must do this on every host where etcd should be running.{{< /note >}}
Since etcd was created first, you must override the service priority by creating a new unit file
that has higher precedence than the kubeadm-provided kubelet unit file.
-->
1. 将 kubelet 配置为 etcd 的服务管理器。
由于 etcd 是首先创建的,因此您必须通过创建具有更高优先级的新文件来覆盖 kubeadm 提供的 kubelet 单元文件。
{{< note >}}
你必须在要运行 etcd 的所有主机上执行此操作。
{{< /note >}}
由于 etcd 是首先创建的,因此你必须通过创建具有更高优先级的新文件来覆盖
kubeadm 提供的 kubelet 单元文件。
```sh
cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
ExecStart=
# Replace "systemd" with the cgroup driver of your container runtime. The default value in the kubelet is "cgroupfs".
ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd
Restart=always
EOF
```sh
cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
ExecStart=
# 将下面的 "systemd" 替换为你的容器运行时所使用的 cgroup 驱动。
# kubelet 的默认值为 "cgroupfs"。
ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd
Restart=always
EOF
systemctl daemon-reload
systemctl restart kubelet
```
systemctl daemon-reload
systemctl restart kubelet
```
<!--
1.Create configuration files for kubeadm.
<!--
Check the kubelet status to ensure it is running.
-->
检查 kubelet 的状态以确保其处于运行状态:
Generate one kubeadm configuration file for each host that will have an etcd
member running on it using the following script.
-->
1. 为 kubeadm 创建配置文件。
```shell
systemctl status kubelet
```
使用以下脚本为每个将要运行 etcd 成员的主机生成一个 kubeadm 配置文件。
<!--
1. Create configuration files for kubeadm.
<!--
```sh
# Update HOST0, HOST1, and HOST2 with the IPs or resolvable names of your hosts
export HOST0=10.0.0.6
export HOST1=10.0.0.7
export HOST2=10.0.0.8
Generate one kubeadm configuration file for each host that will have an etcd
member running on it using the following script.
-->
2. 为 kubeadm 创建配置文件。
# Create temp directories to store files that will end up on other hosts.
mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/
使用以下脚本为每个将要运行 etcd 成员的主机生成一个 kubeadm 配置文件。
ETCDHOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=("infra0" "infra1" "infra2")
```sh
# 使用 IP 或可解析的主机名替换 HOST0、HOST1 和 HOST2
export HOST0=10.0.0.6
export HOST1=10.0.0.7
export HOST2=10.0.0.8
for i in "${!ETCDHOSTS[@]}"; do
HOST=${ETCDHOSTS[$i]}
NAME=${NAMES[$i]}
cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
apiVersion: "kubeadm.k8s.io/v1beta2"
kind: ClusterConfiguration
etcd:
local:
serverCertSANs:
- "${HOST}"
peerCertSANs:
- "${HOST}"
extraArgs:
initial-cluster: infra0=https://${ETCDHOSTS[0]}:2380,infra1=https://${ETCDHOSTS[1]}:2380,infra2=https://${ETCDHOSTS[2]}:2380
initial-cluster-state: new
name: ${NAME}
listen-peer-urls: https://${HOST}:2380
listen-client-urls: https://${HOST}:2379
advertise-client-urls: https://${HOST}:2379
initial-advertise-peer-urls: https://${HOST}:2380
EOF
done
```
-->
```sh
# 使用 IP 或可解析的主机名替换 HOST0、HOST1 和 HOST2
export HOST0=10.0.0.6
export HOST1=10.0.0.7
export HOST2=10.0.0.8
# 创建临时目录来存储将被分发到其它主机上的文件
mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/
# 创建临时目录来存储将被分发到其它主机上的文件
mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/
ETCDHOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=("infra0" "infra1" "infra2")
ETCDHOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=("infra0" "infra1" "infra2")
for i in "${!ETCDHOSTS[@]}"; do
HOST=${ETCDHOSTS[$i]}
NAME=${NAMES[$i]}
cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
apiVersion: "kubeadm.k8s.io/v1beta2"
kind: ClusterConfiguration
etcd:
local:
serverCertSANs:
- "${HOST}"
peerCertSANs:
- "${HOST}"
extraArgs:
initial-cluster: infra0=https://${ETCDHOSTS[0]}:2380,infra1=https://${ETCDHOSTS[1]}:2380,infra2=https://${ETCDHOSTS[2]}:2380
initial-cluster-state: new
name: ${NAME}
listen-peer-urls: https://${HOST}:2380
listen-client-urls: https://${HOST}:2379
advertise-client-urls: https://${HOST}:2379
initial-advertise-peer-urls: https://${HOST}:2380
EOF
done
```
for i in "${!ETCDHOSTS[@]}"; do
HOST=${ETCDHOSTS[$i]}
NAME=${NAMES[$i]}
cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
apiVersion: "kubeadm.k8s.io/v1beta2"
kind: ClusterConfiguration
etcd:
local:
serverCertSANs:
- "${HOST}"
peerCertSANs:
- "${HOST}"
extraArgs:
initial-cluster: infra0=https://${ETCDHOSTS[0]}:2380,infra1=https://${ETCDHOSTS[1]}:2380,infra2=https://${ETCDHOSTS[2]}:2380
initial-cluster-state: new
name: ${NAME}
listen-peer-urls: https://${HOST}:2380
listen-client-urls: https://${HOST}:2379
advertise-client-urls: https://${HOST}:2379
initial-advertise-peer-urls: https://${HOST}:2380
EOF
done
```
<!--
1. Generate the certificate authority
<!--
1.Generate the certificate authority
If you already have a CA then the only action that is copying the CA's `crt` and
`key` file to `/etc/kubernetes/pki/etcd/ca.crt` and
`/etc/kubernetes/pki/etcd/ca.key`. After those files have been copied,
proceed to the next step, "Create certificates for each member".
-->
3. 生成证书颁发机构
If you already have a CA then the only action that is copying the CA's `crt` and
`key` file to `/etc/kubernetes/pki/etcd/ca.crt` and
`/etc/kubernetes/pki/etcd/ca.key`. After those files have been copied,
proceed to the next step, "Create certificates for each member".
-->
1. 生成证书颁发机构
如果你已经拥有 CA,那么唯一的操作是复制 CA 的 `crt``key` 文件到
`etc/kubernetes/pki/etcd/ca.crt` `/etc/kubernetes/pki/etcd/ca.key`
复制完这些文件后继续下一步,“为每个成员创建证书”。
如果您已经拥有 CA,那么唯一的操作是复制 CA 的 `crt``key` 文件到 `etc/kubernetes/pki/etcd/ca.crt``/etc/kubernetes/pki/etcd/ca.key`。复制完这些文件后继续下一步,“为每个成员创建证书”。
<!--
If you do not already have a CA then run this command on `$HOST0` (where you generated the configuration files for kubeadm).
-->
如果你还没有 CA,则在 `$HOST0`(你为 kubeadm 生成配置文件的位置)上运行此命令。
<!--
If you do not already have a CA then run this command on `$HOST0` (where you generated the configuration files for kubeadm).
-->
如果您还没有 CA,则在 `$HOST0`(您为 kubeadm 生成配置文件的位置)上运行此命令。
```
kubeadm init phase certs etcd-ca
```
```
kubeadm init phase certs etcd-ca
```
<!--
This creates two files
-->
这一操作创建如下两个文件
<!--
This creates two files
-->
创建了如下两个文件
- `/etc/kubernetes/pki/etcd/ca.crt`
- `/etc/kubernetes/pki/etcd/ca.key`
- `/etc/kubernetes/pki/etcd/ca.crt`
- `/etc/kubernetes/pki/etcd/ca.key`
<!--
1. Create certificates for each member
-->
4. 为每个成员创建证书
<!--
1. Create certificates for each member
-->
1. 为每个成员创建证书
```shell
kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# 清理不可重复使用的证书
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
<!--
```sh
kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# cleanup non-reusable certificates
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
# 不需要移动 certs 因为它们是给 HOST0 使用的
kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
# No need to move the certs because they are for HOST0
# 清理不应从此主机复制的证书
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete
```
# clean up certs that should not be copied off this host
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete
```
-->
```sh
kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST2}/
# 清理不可重复使用的证书
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
<!--
1. Copy certificates and kubeadm configs
The certificates have been generated and now they must be moved to their
respective hosts.
-->
5. 复制证书和 kubeadm 配置
kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
cp -R /etc/kubernetes/pki /tmp/${HOST1}/
find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
证书已生成,现在必须将它们移动到对应的主机。
kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
# 不需要移动 certs 因为它们是给 HOST0 使用的
```shell
USER=ubuntu
HOST=${HOST1}
scp -r /tmp/${HOST}/* ${USER}@${HOST}:
ssh ${USER}@${HOST}
USER@HOST $ sudo -Es
root@HOST $ chown -R root:root pki
root@HOST $ mv pki /etc/kubernetes/
```
# 清理不应从此主机复制的证书
find /tmp/${HOST2} -name ca.key -type f -delete
find /tmp/${HOST1} -name ca.key -type f -delete
```
<!--
1. Ensure all expected files exist
<!--
1.Copy certificates and kubeadm configs
The complete list of required files on `$HOST0` is:
-->
6. 确保已经所有预期的文件都存在
The certificates have been generated and now they must be moved to their
respective hosts.
-->
1. 复制证书和 kubeadm 配置
`$HOST0` 所需文件的完整列表如下:
证书已生成,现在必须将它们移动到对应的主机。
```none
/tmp/${HOST0}
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── ca.key
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
```sh
USER=ubuntu
HOST=${HOST1}
scp -r /tmp/${HOST}/* ${USER}@${HOST}:
ssh ${USER}@${HOST}
USER@HOST $ sudo -Es
root@HOST $ chown -R root:root pki
root@HOST $ mv pki /etc/kubernetes/
```
<!--
On `$HOST1`:
-->
`$HOST1` 上:
<!--
1.Ensure all expected files exist
```
$HOME
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
The complete list of required files on `$HOST0` is:
-->
1. 确保已经所有预期的文件都存在
<!--
On `$HOST2`
-->
`$HOST2` 上:
`$HOST0` 所需文件的完整列表如下:
```
$HOME
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
```
/tmp/${HOST0}
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── ca.key
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
<!--
1. Create the static pod manifests
<!--
On `$HOST1`:
-->
`$HOST1`:
Now that the certificates and configs are in place it's time to create the
manifests. On each host run the `kubeadm` command to generate a static manifest
for etcd.
-->
7. 创建静态 Pod 清单
```
$HOME
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
既然证书和配置已经就绪,是时候去创建清单了。
在每台主机上运行 `kubeadm` 命令来生成 etcd 使用的静态清单。
<!--
On `$HOST2`
-->
`$HOST2`
```shell
root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml
root@HOST1 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml
root@HOST2 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml
```
```
$HOME
└── kubeadmcfg.yaml
---
/etc/kubernetes/pki
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
└── etcd
├── ca.crt
├── healthcheck-client.crt
├── healthcheck-client.key
├── peer.crt
├── peer.key
├── server.crt
└── server.key
```
<!--
1. Optional: Check the cluster health
-->
8. 可选:检查群集运行状况
<!--
1.Create the static pod manifests
Now that the certificates and configs are in place it's time to create the
manifests. On each host run the `kubeadm` command to generate a static manifest
for etcd.
-->
1. 创建静态 Pod 清单
既然证书和配置已经就绪,是时候去创建清单了。在每台主机上运行 `kubeadm` 命令来生成 etcd 使用的静态清单。
```sh
root@HOST0 $ kubeadm init phase etcd local --config=/tmp/${HOST0}/kubeadmcfg.yaml
root@HOST1 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml
root@HOST2 $ kubeadm init phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml
```
<!--
1.Optional: Check the cluster health
-->
1. 可选:检查群集运行状况
```sh
docker run --rm -it \
--net host \
-v /etc/kubernetes:/etc/kubernetes k8s.gcr.io/etcd:${ETCD_TAG} etcdctl \
--cert /etc/kubernetes/pki/etcd/peer.crt \
--key /etc/kubernetes/pki/etcd/peer.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://${HOST0}:2379 endpoint health --cluster
...
https://[HOST0 IP]:2379 is healthy: successfully committed proposal: took = 16.283339ms
https://[HOST1 IP]:2379 is healthy: successfully committed proposal: took = 19.44402ms
https://[HOST2 IP]:2379 is healthy: successfully committed proposal: took = 35.926451ms
```
<!--
Set ${ETCD_TAG} to the version tag of your etcd image. For example 3.4.3-0. To see the etcd image and tag that kubeadm uses execute kubeadm config images list --kubernetes-version ${K8S_VERSION}, where ${K8S_VERSION} is for example v1.17.0
-->
- 将 `${ETCD_TAG}` 设置为你的 etcd 镜像的版本标签,例如 `3.4.3-0`。要查看 kubeadm 使用的 etcd 镜像和标签,请执行 `kubeadm config images list --kubernetes-version ${K8S_VERSION}`,其中 `${K8S_VERSION}``v1.17.0` 作为例子。
<!--
Set ${HOST0}to the IP address of the host you are testing.
-->
- 将 `${HOST0}` 设置为要测试的主机的 IP 地址
```shell
docker run --rm -it \
--net host \
-v /etc/kubernetes:/etc/kubernetes k8s.gcr.io/etcd:${ETCD_TAG} etcdctl \
--cert /etc/kubernetes/pki/etcd/peer.crt \
--key /etc/kubernetes/pki/etcd/peer.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://${HOST0}:2379 endpoint health --cluster
...
https://[HOST0 IP]:2379 is healthy: successfully committed proposal: took = 16.283339ms
https://[HOST1 IP]:2379 is healthy: successfully committed proposal: took = 19.44402ms
https://[HOST2 IP]:2379 is healthy: successfully committed proposal: took = 35.926451ms
```
<!--
Set ${ETCD_TAG} to the version tag of your etcd image. For example 3.4.3-0. To see the etcd image and tag that kubeadm uses execute kubeadm config images list --kubernetes-version ${K8S_VERSION}, where ${K8S_VERSION} is for example v1.17.0
Set ${HOST0}to the IP address of the host you are testing.
-->
- 将 `${ETCD_TAG}` 设置为你的 etcd 镜像的版本标签,例如 `3.4.3-0`
要查看 kubeadm 使用的 etcd 镜像和标签,请执行
`kubeadm config images list --kubernetes-version ${K8S_VERSION}`
例如,其中的 `${K8S_VERSION}` 可以是 `v1.17.0`
- 将 `${HOST0}` 设置为要测试的主机的 IP 地址。
## {{% heading "whatsnext" %}}
@@ -422,7 +373,6 @@ highly available control plane using the [external etcd method with
kubeadm](/docs/setup/independent/high-availability/).
-->
一旦拥有了一个正常工作的 3 成员的 etcd 集群,你就可以基于
[使用 kubeadm 外部 etcd 方法](/zh/docs/setup/production-environment/tools/kubeadm/high-availability/)
[使用 kubeadm 外部 etcd 方法](/zh/docs/setup/production-environment/tools/kubeadm/high-availability/)
继续部署一个高可用的控制平面。
@@ -101,11 +101,11 @@ This may be caused by a number of problems. The most common are:
There are two common ways to fix the cgroup driver problem:
1. Install Docker again following instructions
1. Install Docker again following instructions
[here](/docs/setup/production-environment/container-runtimes/#docker).
1. Change the kubelet config to match the Docker cgroup driver manually, you can refer to
[Configure cgroup driver used by kubelet on control-plane node](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-control-plane-node)
1. Change the kubelet config to match the Docker cgroup driver manually, you can refer to
[Configure cgroup driver used by kubelet on control-plane node](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-control-plane-node)
- control plane Docker containers are crashlooping or hanging. You can check this by running `docker ps` and investigating each container by running `docker logs`.
-->
@@ -122,7 +122,8 @@ This may be caused by a number of problems. The most common are:
有两种常见方法可解决 cgroup 驱动程序问题:
1. 按照 [此处](/zh/docs/setup/production-environment/container-runtimes/#docker) 的说明再次安装 Docker。
1. 按照[此处](/zh/docs/setup/production-environment/container-runtimes/#docker) 的说明
重新安装 Docker。
1. 更改 kubelet 配置以手动匹配 Docker cgroup 驱动程序,你可以参考
[在主节点上配置 kubelet 要使用的 cgroup 驱动程序](/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-control-plane-node)
@@ -134,8 +135,11 @@ This may be caused by a number of problems. The most common are:
The following could happen if Docker halts and does not remove any Kubernetes-managed containers:
```bash
```shell
sudo kubeadm reset
```
```console
[preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
@@ -145,14 +149,14 @@ sudo kubeadm reset
A possible solution is to restart the Docker service and then re-run `kubeadm reset`:
```bash
```shell
sudo systemctl restart docker.service
sudo kubeadm reset
```
Inspecting the logs for docker may also be useful:
```sh
```shell
journalctl -ul docker
```
-->
@@ -160,8 +164,11 @@ journalctl -ul docker
如果 Docker 停止并且不删除 Kubernetes 所管理的所有容器,可能发生以下情况:
```bash
```shell
sudo kubeadm reset
```
```none
[preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
@@ -171,7 +178,7 @@ sudo kubeadm reset
一个可行的解决方案是重新启动 Docker 服务,然后重新运行 `kubeadm reset`
```bash
```shell
sudo systemctl restart docker.service
sudo kubeadm reset
```
@@ -189,10 +196,10 @@ Right after `kubeadm init` there should not be any pods in these states.
- If there are pods in one of these states _right after_ `kubeadm init`, please open an
issue in the kubeadm repo. `coredns` (or `kube-dns`) should be in the `Pending` state
until you have deployed the network solution.
until you have deployed the network add-on.
- If you see Pods in the `RunContainerError`, `CrashLoopBackOff` or `Error` state
after deploying the network solution and nothing happens to `coredns` (or `kube-dns`),
it's very likely that the Pod Network solution that you installed is somehow broken.
after deploying the network add-on and nothing happens to `coredns` (or `kube-dns`),
it's very likely that the Pod Network add-on that you installed is somehow broken.
You might have to grant it more RBAC privileges or use a newer version. Please file
an issue in the Pod Network providers' issue tracker and get the issue triaged there.
- If you install a version of Docker older than 1.12.1, remove the `MountFlags=slave` option
@@ -206,11 +213,11 @@ Right after `kubeadm init` there should not be any pods in these states.
- 在 `kubeadm init` 命令执行完后,如果有 pods 处于这些状态之一,请在 kubeadm
仓库提起一个 issue。`coredns` (或者 `kube-dns`) 应该处于 `Pending` 状态,
直到你部署了网络解决方案为止。
直到你部署了网络插件为止。
- 如果在部署完网络解决方案之后,有 Pods 处于 `RunContainerError``CrashLoopBackOff`
- 如果在部署完网络插件之后,有 Pods 处于 `RunContainerError``CrashLoopBackOff`
`Error` 状态之一,并且`coredns` (或者 `kube-dns`)仍处于 `Pending` 状态,
那很可能是你安装的网络解决方案由于某种原因无法工作。你或许需要授予它更多的
那很可能是你安装的网络插件由于某种原因无法工作。你或许需要授予它更多的
RBAC 特权或使用较新的版本。请在 Pod Network 提供商的问题跟踪器中提交问题,
然后在此处分类问题。
@@ -221,17 +228,18 @@ Right after `kubeadm init` there should not be any pods in these states.
当 Kubernetes 不能找到 `var/run/secrets/kubernetes.io/serviceaccount` 文件时会发生错误。
<!--
## `coredns` (or `kube-dns`) is stuck in the `Pending` state
## `coredns` is stuck in the `Pending` state
This is **expected** and part of the design. kubeadm is network provider-agnostic, so the admin
should [install the pod network solution](/docs/concepts/cluster-administration/addons/)
should [install the pod network add-on](/docs/concepts/cluster-administration/addons/)
of choice. You have to install a Pod Network
before CoreDNS may be deployed fully. Hence the `Pending` state before the network is set up.
-->
## `coredns` (或 `kube-dns`停滞在 `Pending` 状态
## `coredns` 停滞在 `Pending` 状态
这一行为是 **预期之中** 的,因为系统就是这么设计的。
kubeadm 的网络供应商是中立的,因此管理员应该选择 [安装 pod 的网络解决方案](/zh/docs/concepts/cluster-administration/addons/)。
kubeadm 的网络供应商是中立的,因此管理员应该选择
[安装 pod 的网络插件](/zh/docs/concepts/cluster-administration/addons/)。
你必须完成 Pod 的网络配置,然后才能完全部署 CoreDNS。
在网络被配置好之前,DNS 组件会一直处于 `Pending` 状态。
@@ -239,7 +247,7 @@ kubeadm 的网络供应商是中立的,因此管理员应该选择 [安装 pod
## `HostPort` services do not work
The `HostPort` and `HostIP` functionality is available depending on your Pod Network
provider. Please contact the author of the Pod Network solution to find out whether
provider. Please contact the author of the Pod Network add-on to find out whether
`HostPort` and `HostIP` functionality are available.
Calico, Canal, and Flannel CNI providers are verified to support HostPort.
@@ -251,7 +259,7 @@ services](/docs/concepts/services-networking/service/#nodeport) or use `HostNetw
-->
## `HostPort` 服务无法工作
`HostPort``HostIP` 功能是否可用取决于你的 Pod 网络配置。请联系 Pod 解决方案的作者,
`HostPort``HostIP` 功能是否可用取决于你的 Pod 网络配置。请联系 Pod 网络插件的作者,
以确认 `HostPort``HostIP` 功能是否可用。
已验证 Calico、Canal 和 Flannel CNI 驱动程序支持 HostPort。
@@ -663,3 +671,139 @@ kubectl taint nodes NODE_NAME node-role.kubernetes.io/master:NoSchedule-
kubectl taint nodes NODE_NAME node-role.kubernetes.io/master:NoSchedule-
```
<!--
## `/usr` is mounted read-only on nodes {#usr-mounted-read-only}
On Linux distributions such as Fedora CoreOS or Flatcar Container Linux, the directory `/usr` is mounted as a read-only filesystem.
For [flex-volume support](https://github.com/kubernetes/community/blob/ab55d85/contributors/devel/sig-storage/flexvolume.md),
Kubernetes components like the kubelet and kube-controller-manager use the default path of
`/usr/libexec/kubernetes/kubelet-plugins/volume/exec/`, yet the flex-volume directory _must be writeable_
for the feature to work.
-->
## 节点上的 `/usr` 被以只读方式挂载 {#usr-mounted-read-only}
在类似 Fedora CoreOS 或者 Flatcar Container Linux 这类 Linux 发行版本中,
目录 `/usr` 是以只读文件系统的形式挂载的。
在支持 [FlexVolume](https://github.com/kubernetes/community/blob/ab55d85/contributors/devel/sig-storage/flexvolume.md)时,
类似 kubelet 和 kube-controller-manager 这类 Kubernetes 组件使用默认路径
`/usr/libexec/kubernetes/kubelet-plugins/volume/exec/`
而 FlexVolume 的目录 _必须是可写入的_,该功能特性才能正常工作。
<!--
To workaround this issue you can configure the flex-volume directory using the kubeadm
[configuration file](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2).
On the primary control-plane Node (created using `kubeadm init`) pass the following
file using `--config`:
-->
为了解决这个问题,你可以使用 kubeadm 的[配置文件](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2)
来配置 FlexVolume 的目录。
在(使用 `kubeadm init` 创建的)主控制节点上,使用 `-config`
参数传入如下文件:
```yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controllerManager:
extraArgs:
flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
```
<!--
On joining Nodes:
-->
在加入到集群中的节点上,使用下面的文件:
```yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
```
<!--
Alternatively, you can modify `/etc/fstab` to make the `/usr` mount writeable, but please
be advised that this is modifying a design principle of the Linux distribution.
-->
或者,你要可以更改 `/etc/fstab` 使得 `/usr` 目录能够以可写入的方式挂载,不过
请注意这样做本质上是在更改 Linux 发行版的某种设计原则。
<!--
## `kubeadm upgrade plan` prints out `context deadline exceeded` error message
This error message is shown when upgrading a Kubernetes cluster with `kubeadm` in the case of running an external etcd. This is not a critical bug and happens because older versions of kubeadm perform a version check on the external etcd cluster. You can proceed with `kubeadm upgrade apply ...`.
This issue is fixed as of version 1.19.
-->
## `kubeadm upgrade plan` 输出错误信息 `context deadline exceeded`
在使用 `kubeadm` 来升级某运行外部 etcd 的 Kubernetes 集群时可能显示这一错误信息。
这并不是一个非常严重的一个缺陷,之所以出现此错误信息,原因是老的 kubeadm
版本会对外部 etcd 集群执行版本检查。你可以继续执行 `kubeadm upgrade apply ...`
这一问题已经在 1.19 版本中得到修复。
<!--
## `kubeadm reset` unmounts `/var/lib/kubelet`
If `/var/lib/kubelet` is being mounted, performing a `kubeadm reset` will effectively unmount it.
To workaround the issue, re-mount the `/var/lib/kubelet` directory after performing the `kubeadm reset` operation.
This is a regression introduced in kubeadm 1.15. The issue is fixed in 1.20.
-->
## `kubeadm reset` 会卸载 `/var/lib/kubelet`
如果已经挂载了 `/var/lib/kubelet` 目录,执行 `kubeadm reset` 操作的时候
会将其卸载。
要解决这一问题,可以在执行了 `kubeadm reset` 操作之后重新挂载
`/var/lib/kubelet` 目录。
这是一个在 1.15 中引入的故障,已经在 1.20 版本中修复。
<!--
## Cannot use the metrics-server securely in a kubeadm cluster
In a kubeadm cluster, the [metrics-server](https://github.com/kubernetes-sigs/metrics-server)
can be used insecurely by passing the `--kubelet-insecure-tls` to it. This is not recommended for production clusters.
-->
## 无法在 kubeadm 集群中安全地使用 metrics-server
在 kubeadm 集群中可以通过为 [metrics-server](https://github.com/kubernetes-sigs/metrics-server)
设置 `--kubelet-insecure-tls` 来以不安全的形式使用该服务。
建议不要在生产环境集群中这样使用。
<!--
If you want to use TLS between the metrics-server and the kubelet there is a problem,
since kubeadm deploys a self-signed serving certificate for the kubelet. This can cause the following errors
on the side of the metrics-server:
-->
如果你需要在 metrics-server 和 kubelt 之间使用 TLS,会有一个问题,
kubeadm 为 kubelt 部署的是自签名的服务证书。这可能会导致 metrics-server
端报告下面的错误信息:
```
x509: certificate signed by unknown authority
x509: certificate is valid for IP-foo not IP-bar
```
<!--
See [Enabling signed kubelet serving certificates](/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/#kubelet-serving-certs)
to understand how to configure the kubelets in a kubeadm cluster to have properly signed serving certificates.
Also see [How to run the metrics-server securely](https://github.com/kubernetes-sigs/metrics-server/blob/master/FAQ.md#how-to-run-metrics-server-securely).
-->
参见[为 kubelet 启用签名的服务证书](/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/#kubelet-serving-certs)
以进一步了解如何在 kubeadm 集群中配置 kubelet 使用正确签名了的服务证书。
另请参阅[How to run the metrics-server securely](https://github.com/kubernetes-sigs/metrics-server/blob/master/FAQ.md#how-to-run-metrics-server-securely)。
@@ -0,0 +1,293 @@
---
title: "将重复的控制平面迁至云控制器管理器"
linkTitle: "将重复的控制平面迁至云控制器管理器"
content_type: task
---
<!--
---
reviewers:
- jpbetz
- cheftako
title: "Migrate Replicated Control Plane To Use Cloud Controller Manager"
linkTitle: "Migrate Replicated Control Plane To Use Cloud Controller Manager"
content_type: task
---
-->
<!-- overview -->
{{< feature-state state="alpha" for_k8s_version="v1.21" >}}
{{< glossary_definition term_id="cloud-controller-manager" length="all" prepend="云管理控制器是">}}
<!--
## Background
As part of the [cloud provider extraction effort](https://kubernetes.io/blog/2019/04/17/the-future-of-cloud-providers-in-kubernetes/),
all cloud specific controllers must be moved out of the `kube-controller-manager`.
All existing clusters that run cloud controllers in the `kube-controller-manager` must migrate to instead run the controllers in a cloud provider specific `cloud-controller-manager`.
Leader Migration provides a mechanism in which HA clusters can safely migrate "cloud specific" controllers between
the `kube-controller-manager` and the `cloud-controller-manager` via a shared resource lock between the two components while upgrading the replicated control plane.
For a single-node control plane, or if unavailability of controller managers can be tolerated during the upgrade, Leader Migration is not needed and this guide can be ignored.
-->
## 背景
作为[云驱动提取工作](https://kubernetes.io/blog/2019/04/17/the-future-of-cloud-providers-in-kubernetes/)
的一部分,所有特定于云的控制器都必须移出 `kube-controller-manager`
所有在 `kube-controller-manager` 中运行云控制器的现有集群必须迁移到云驱动特定的 `cloud-controller-manager` 中运行控制器。
领导者迁移提供了一种机制,使得 HA 集群可以通过两个组件之间的共享资源锁定,
安全地将“特定于云”的控制器从 `kube-controller-manager` 和迁移到`cloud-controller-manager`
同时升级复制的控制平面。
对于单节点控制平面,或者在升级过程中可以容忍控制器管理器不可用的情况,则不需要领导者迁移,并且可以忽略本指南。
<!--
Leader Migration is an alpha feature that is disabled by default and it requires `--enable-leader-migration` to be set on controller managers.
It can be enabled by setting the feature gate `ControllerManagerLeaderMigration` plus `--enable-leader-migration` on `kube-controller-manager` or `cloud-controller-manager`.
Leader Migration only applies during the upgrade and can be safely disabled or left enabled after the upgrade is complete.
This guide walks you through the manual process of upgrading the control plane from `kube-controller-manager` with
built-in cloud provider to running both `kube-controller-manager` and `cloud-controller-manager`.
If you use a tool to administrator the cluster, please refer to the documentation of the tool and the cloud provider for more details.
-->
领导者迁移是一项 Alpha 阶段功能,默认情况下处于禁用状态,它需要设置控制器管理器的 `--enable-leader-migration` 参数。
可以通过在 `kube-controller-manager``cloud-controller-manager` 上设置特性门控
`ControllerManagerLeaderMigration``--enable-leader-migration` 来启用。
领导者迁移仅在升级期间适用,并且可以安全地禁用,也可以在升级完成后保持启用状态。
本指南将引导你手动将控制平面从内置的云驱动的 `kube-controller-manager` 升级为
同时运行 `kube-controller-manager``cloud-controller-manager`
如果使用工具来管理群集,请参阅对应工具和云驱动的文档以获取更多详细信息。
## {{% heading "prerequisites" %}}
<!--
It is assumed that the control plane is running Kubernetes version N and to be upgraded to version N + 1.
Although it is possible to migrate within the same version, ideally the migration should be performed as part of a upgrade so that changes of configuration can be aligned to releases.
The exact versions of N and N + 1 depend on each cloud provider. For example, if a cloud provider builds a `cloud-controller-manager` to work with Kubernetes 1.22, then N can be 1.21 and N + 1 can be 1.22.
The control plane nodes should run `kube-controller-manager` with Leader Election enabled through `--leader-elect=true`.
As of version N, an in-tree cloud privider must be set with `--cloud-provider` flag and `cloud-controller-manager` should not yet be deployed.
-->
假定控制平面正在运行 Kubernetes N 版本,并且要升级到 N+1 版本。
尽管可以在同一版本中进行迁移,但理想情况下,迁移应作为升级的一部分执行,以便可以更改配置与发布保持一致。
N 和 N+1的确切版本取决于各个云驱动。例如,如果云驱动构建了一个可与 Kubernetes 1.22 配合使用的 `cloud-controller-manager`
则 N 可以为 1.21N+1 可以为 1.22。
控制平面节点应运行 `kube-controller-manager`,并通过 `--leader-elect=true` 启用领导者选举。
从版本 N 开始,树内云驱动必须设置 `--cloud-provider` 标志,而且 `cloud-controller-manager` 尚未部署。
<!--
The out-of-tree cloud provider must have built a `cloud-controller-manager` with Leader Migration implementation.
If the cloud provider imports `k8s.io/cloud-provider` and `k8s.io/controller-manager` of version v0.21.0 or later, Leader Migration will be avaliable.
This guide assumes that kubelet of each control plane node starts `kube-controller-manager`
and `cloud-controller-manager` as static pods defined by their manifests.
If the components run in a different setting, please adjust the steps accordingly.
For authorization, this guide assumes that the cluser uses RBAC.
If another authorization mode grants permissions to `kube-controller-manager` and `cloud-controller-manager` components,
please grant the needed access in a way that matches the mode.
-->
树外云驱动必须已经构建了一个实现领导者迁移的 `cloud-controller-manager`
如果云驱动导入了 v0.21.0 或更高版本的 `k8s.io/cloud-provider``k8s.io/controller-manager`
则可以进行领导者迁移。
本指南假定每个控制平面节点的 kubelet 以静态 pod 的形式启动 `kube-controller-manager`
`cloud-controller-manager`,静态 pod 的定义在清单文件中。
如果组件以其他设置运行,请相应地调整步骤。
为了获得授权,本指南假定集群使用 RBAC。
如果其他授权模式授予 `kube-controller-manager``cloud-controller-manager` 组件权限,
请以与该模式匹配的方式授予所需的访问权限。
<!-- steps -->
<!--
### Grant access to Migration Lease
The default permissions of the controller manager allow only accesses to their main Lease.
In order for the migration to work, accesses to another Lease are required.
You can grant `kube-controller-manager` full access to the leases API by modifying
the `system::leader-locking-kube-controller-manager` role.
This task guide assumes that the name of the migration lease is `cloud-provider-extraction-migration`.
`kubectl patch -n kube-system role 'system::leader-locking-kube-controller-manager' -p '{"rules": [ {"apiGroups":[ "coordination.k8s.io"], "resources": ["leases"], "resourceNames": ["cloud-provider-extraction-migration"], "verbs": ["create", "list", "get", "update"] } ]}' --type=merge`
Do the same to the `system::leader-locking-cloud-controller-manager` role.
`kubectl patch -n kube-system role 'system::leader-locking-cloud-controller-manager' -p '{"rules": [ {"apiGroups":[ "coordination.k8s.io"], "resources": ["leases"], "resourceNames": ["cloud-provider-extraction-migration"], "verbs": ["create", "list", "get", "update"] } ]}' --type=merge`
-->
### 授予访问迁移 Lease 的权限
控制器管理器的默认权限仅允许访问其主 Lease 对象。为了使迁移正常进行,需要访问其他 Lease 对象。
你可以通过修改 `system::leader-locking-kube-controller-manager` 角色来授予
`kube-controller-manager` 对 Lease API 的完全访问权限。
本任务指南假定迁移 Lease 的名称为 `cloud-provider-extraction-migration`
`kubectl patch -n kube-system role 'system::leader-locking-kube-controller-manager' -p '{"rules": [ {"apiGroups":[ "coordination.k8s.io"], "resources": ["leases"], "resourceNames": ["cloud-provider-extraction-migration"], "verbs": ["create", "list", "get", "update"] } ]}' --type=merge`
`system::leader-locking-cloud-controller-manager` 角色执行相同的操作。
`kubectl patch -n kube-system role 'system::leader-locking-cloud-controller-manager' -p '{"rules": [ {"apiGroups":[ "coordination.k8s.io"], "resources": ["leases"], "resourceNames": ["cloud-provider-extraction-migration"], "verbs": ["create", "list", "get", "update"] } ]}' --type=merge`
<!--
### Initial Leader Migration configuration
Leader Migration requires a configuration file representing the state of controller-to-manager assignment.
At this moment, with in-tree cloud provider, `kube-controller-manager` runs `route`, `service`, and `cloud-node-lifecycle`.
The following example configuration shows the assignment.
-->
### 初始领导者迁移配置
领导者迁移需要一个表示控制器到管理器分配状态的配置文件。
目前,对于树内云驱动,`kube-controller-manager` 运行 `route``service``cloud-node-lifecycle`
以下示例配置显示了分配。
```yaml
kind: LeaderMigrationConfiguration
apiVersion: controllermanager.config.k8s.io/v1alpha1
leaderName: cloud-provider-extraction-migration
resourceLock: leases
controllerLeaders:
- name: route
component: kube-controller-manager
- name: service
component: kube-controller-manager
- name: cloud-node-lifecycle
component: kube-controller-manager
```
<!--
On each control plane node, save the content to `/etc/leadermigration.conf`,
and update the manifest of `kube-controller-manager` so that the file is mounted inside the container at the same location.
Also, update the same manifest to add the following arguments:
- `--feature-gates=ControllerManagerLeaderMigration=true` to enable Leader Migration which is an alpha feature
- `--enable-leader-migration` to enable Leader Migration on the controller manager
- `--leader-migration-config=/etc/leadermigration.conf` to set configuration file
Restart `kube-controller-manager` on each node. At this moment, `kube-controller-manager` has leader migration enabled and is ready for the migration.
-->
在每个控制平面节点上,将内容保存到 `/etc/leadermigration.conf` 中,
并更新 `kube-controller-manager` 清单,以便将文件安装在容器内的同一位置。
另外,更新相同的清单,添加以下参数:
- `--feature-gates=ControllerManagerLeaderMigration=true` 启用领导者迁移(这是 Alpha 版功能)
- `--enable-leader-migration` 在控制器管理器上启用领导者迁移
- `--leader-migration-config=/etc/leadermigration.conf` 设置配置文件
在每个节点上重新启动 `kube-controller-manager`。这时,`kube-controller-manager`
已启用领导者迁移,并准备进行迁移。
<!--
### Deploy Cloud Controller Manager
In version N + 1, the desired state of controller-to-manager assignment can be represented by a new configuration file, shown as follows.
Please note `component` field of each `controllerLeaders` changing from `kube-controller-manager` to `cloud-controller-manager`.
-->
### 部署云控制器管理器
在 N+1 版本中,控制器到管理器分配的期望状态可以由新的配置文件表示,如下所示。
请注意,每个 `controllerLeaders``component` 字段从 `kube-controller-manager` 更改为 `cloud-controller-manager`
```yaml
kind: LeaderMigrationConfiguration
apiVersion: controllermanager.config.k8s.io/v1alpha1
leaderName: cloud-provider-extraction-migration
resourceLock: leases
controllerLeaders:
- name: route
component: cloud-controller-manager
- name: service
component: cloud-controller-manager
- name: cloud-node-lifecycle
component: cloud-controller-manager
```
<!--
When creating control plane nodes of version N + 1, the content should be deploy to `/etc/leadermigration.conf`.
The manifest of `cloud-controller-manager` should be updated to mount the configuration file in
the same manner as `kube-controller-manager` of version N. Similarly, add `--feature-gates=ControllerManagerLeaderMigration=true`,
`--enable-leader-migration`, and `--leader-migration-config=/etc/leadermigration.conf` to the arguments of `cloud-controller-manager`.
Create a new control plane node of version N + 1 with the updated `cloud-controller-manager` manifest,
and with the `--cloud-provider` flag unset for `kube-controller-manager`.
`kube-controller-manager` of version N + 1 MUST NOT have Leader Migration enabled because,
with an external cloud provider, it does not run the migrated controllers anymore and thus it is not involved in the migration.
Please refer to [Cloud Controller Manager Administration](/docs/tasks/administer-cluster/running-cloud-controller/)
for more detail on how to deploy `cloud-controller-manager`.
-->
当创建 N+1 版本的控制平面节点时,应将内容部署到 `/etc/leadermigration.conf`
应该更新 `cloud-controller-manager` 清单,以与 N 版本的 `kube-controller-manager` 相同的方式挂载配置文件。
类似地,添加 `--feature-gates=ControllerManagerLeaderMigration=true``--enable-leader-migration`
`--leader-migration-config=/etc/leadermigration.conf``cloud-controller-manager` 的参数中。
使用已更新的 `cloud-controller-manager` 清单创建一个新的 N+1 版本的控制平面节点。
并且没有设置 `kube-controller-manager``--cloud-provider` 标志。
N+1 版本的 `kube-controller-manager` 不能启用领导者迁移,
因为在使用外部云驱动的情况下,它不再运行已迁移的控制器,因此不参与迁移。
请参阅[云控制器管理器管理](/zh/docs/tasks/administer-cluster/running-cloud-controller/)
了解有关如何部署 `cloud-controller-manager` 的更多细节。
<!--
### Upgrade Control Plane
The control plane now contains nodes of both version N and N + 1.
The nodes of version N run `kube-controller-manager` only,
and these of version N + 1 run both `kube-controller-manager` and `cloud-controller-manager`.
The migrated controllers, as specified in the configuration, are running under either `kube-controller-manager` of
version N or `cloud-controller-manager` of version N + 1 depending on which controller manager holds the migration lease.
No controller will ever be running under both controller managers at any time.
In a rolling manner, create a new control plane node of version N + 1 and bring down one of version N + 1 until the control plane contains only nodes of version N + 1.
If a rollback from version N + 1 to N is required, add nodes of version N with Leader Migration enabled for `kube-controller-manager` back to the control plane, replacing one of version N + 1 each time until there are only nodes of version N.
-->
### 升级控制平面
现在,控制平面包含 N 和 N+1 版本的节点。
N 版本的节点仅运行 `kube-controller-manager`,而 N+1 版本的节点同时运行
`kube-controller-manager``cloud-controller-manager`
根据配置所指定,已迁移的控制器在 N 版本的 `kube-controller-manager` 或 N+1 版本的
`cloud-controller-manager` 下运行,
具体取决于哪个控制器管理器拥有迁移 Lease 对象。任何时候都不存在一个控制器在两个控制器管理器下运行。
以滚动的方式创建一个新的版本为 N+1 的控制平面节点,并将 N+1 版本中的一个关闭,
直到控制平面仅包含版本为 N+1 的节点。
如果需要从 N+1 版本回滚到 N 版本,则将启用了领导者迁移的 `kube-controller-manager`
且版本为 N 的节点添加回控制平面,每次替换 N+1 版本的一个,直到只有 N 版本的节点为止。
<!--
### (Optional) Disable Leader Migration {#disable-leader-migration}
Now that the control plane has been upgraded to run both `kube-controller-manager` and `cloud-controller-manager` of version N + 1,
Leader Migration has finished its job and can be safely disabled to save one Lease resource.
It is safe to re-enable Leader Migration for the rollback in the future.
In a rolling manager, update manifest of `cloud-controller-manager` to unset both
`--enable-leader-migration` and `--leader-migration-config=` flag,
also remove the mount of `/etc/leadermigration.conf`, and finally remove `/etc/leadermigration.conf`.
To re-enable Leader Migration, recreate the configuration file and add its mount and the flags that enable Leader Migration back to `cloud-controller-manager`.
-->
### (可选)禁用领导者迁移 {#disable-leader-migration}
现在,控制平面已经升级,可以同时运行 N+1 版本的 `kube-controller-manager``cloud-controller-manager` 了。
领导者迁移已经完成工作,可以安全地禁用以节省一个 Lease 资源。
在将来可以安全地重新启用领导者迁移以完成回滚。
在滚动管理器中,更新 `cloud-controller-manager` 的清单以同时取消设置 `--enable-leader-migration`
`--leader-migration-config=` 标志,并删除 `/etc/leadermigration.conf` 的挂载。
最后删除 `/etc/leadermigration.conf`
要重新启用领导者迁移,请重新创建配置文件,并将其挂载和启用领导者迁移的标志添加回到 `cloud-controller-manager`
## {{% heading "whatsnext" %}}
<!--
- Read the [Controller Manager Leader Migration](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cloud-provider/2436-controller-manager-leader-migration) enhancement proposal
-->
- 阅读[领导者迁移控制器管理器](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cloud-provider/2436-controller-manager-leader-migration)改进建议
+4
View File
@@ -51,10 +51,14 @@ Kubernetes 文档的这一部分包含教程。每个教程展示了如何完成
<!--
## Configuration
* [Example: Configuring a Java Microservice](/docs/tutorials/configuration/configure-java-microservice/)
* [Configuring Redis Using a ConfigMap](/docs/tutorials/configuration/configure-redis-using-configmap/)
-->
## 配置
* [示例:配置 Java 微服务](/zh/docs/tutorials/configuration/configure-java-microservice/)
* [使用一个 ConfigMap 配置 Redis](/zh/docs/tutorials/configuration/configure-redis-using-configmap/)
<!--
+20 -12
View File
@@ -1,12 +1,14 @@
---
title: AppArmor
title: 使用 AppArmor 限制容器对资源的访问
content_type: tutorial
weight: 10
---
<!-- ---
reviewers:
- stclair
title: AppArmor
title: Restrict a Container's Access to Resources with AppArmor
content_type: tutorial
weight: 10
--- -->
<!-- overview -->
@@ -17,11 +19,15 @@ content_type: tutorial
<!-- AppArmor is a Linux kernel security module that supplements the standard Linux user and group based
permissions to confine programs to a limited set of resources. AppArmor can be configured for any
application to reduce its potential attack surface and provide greater in-depth defense. It is
configured through profiles tuned to whitelist the access needed by a specific program or container,
configured through profiles tuned to allow the access needed by a specific program or container,
such as Linux capabilities, network access, file permissions, etc. Each profile can be run in either
*enforcing* mode, which blocks access to disallowed resources, or *complain* mode, which only reports
violations. -->
Apparmor 是一个 Linux 内核安全模块,它补充了标准的基于 Linux 用户和组的安全模块将程序限制为有限资源集的权限。AppArmor 可以配置为任何应用程序减少潜在的攻击面,并且提供更加深入的防御。AppArmor 是通过配置文件进行配置的,这些配置文件被调整为报名单,列出了特定程序或者容器所需要的访问权限,如 Linux 功能、网络访问、文件权限等。每个配置文件都可以在*强制*模式(阻止访问不允许的资源)或*投诉*模式(仅报告冲突)下运行。
Apparmor 是一个 Linux 内核安全模块,它补充了标准的基于 Linux 用户和组的安全模块将程序限制为有限资源集的权限。
AppArmor 可以配置为任何应用程序减少潜在的攻击面,并且提供更加深入的防御。
AppArmor 是通过配置文件进行配置的,这些配置文件被调整为允许特定程序或者容器访问,如 Linux 功能、网络访问、文件权限等。
每个配置文件都可以在*强制(enforcing)*模式(阻止访问不允许的资源)或*投诉(complain)*模式
(仅报告冲突)下运行。
@@ -244,9 +250,8 @@ k8s-apparmor-example-deny-write (enforce)
<!-- *This example assumes you have already set up a cluster with AppArmor support.* -->
*本例假设您已经使用 AppArmor 支持设置了一个集群。*
<!-- First, we need to load the profile we want to use onto our nodes. The profile we'll use simply
denies all file writes: -->
首先,我们需要将要使用的配置文件加载到节点上。我们将使用的配置文件仅拒绝所有文件写入:
<!-- First, we need to load the profile we want to use onto our nodes. This profile denies all file writes: -->
首先,我们需要将要使用的配置文件加载到节点上。配置文件拒绝所有文件写入:
```shell
#include <tunables/global>
@@ -259,9 +264,12 @@ profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
```
<!-- Since we don't know where the Pod will be scheduled, we'll need to load the profile on all our
nodes. For this example we'll just use SSH to install the profiles, but other approaches are
discussed in [Setting up nodes with profiles](#setting-up-nodes-with-profiles). -->
由于我们不知道 Pod 将被安排在那里,我们需要在所有节点上加载配置文件。在本例中,我们将只使用 SSH 来安装概要文件,但是在[使用配置文件设置节点](#setting-up-nodes-with-profiles)中讨论了其他方法。
nodes. For this example we'll use SSH to install the profiles, but other approaches are
discussed in [Setting up nodes with profiles](#setting-up-nodes-with-profiles).
-->
由于我们不知道 Pod 将被调度到哪里,我们需要在所有节点上加载配置文件。
在本例中,我们将使用 SSH 来安装概要文件,但是在[使用配置文件设置节点](#setting-up-nodes-with-profiles)
中讨论了其他方法。
```shell
NODES=(
@@ -403,9 +411,9 @@ Events:
23s 23s 1 {kubelet e2e-test-stclair-node-pool-t1f5} Warning AppArmor Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
```
<!-- Note the pod status is Failed, with a helpful error message: `Pod Cannot enforce AppArmor: profile
<!-- Note the pod status is Pending, with a helpful error message: `Pod Cannot enforce AppArmor: profile
"k8s-apparmor-example-allow-write" is not loaded`. An event was also recorded with the same message. -->
注意 pod 呈现失败状态,并且显示一条有用的错误信息:`Pod Cannot enforce AppArmor: profile
注意 pod 呈现 Pending 状态,并且显示一条有用的错误信息:`Pod Cannot enforce AppArmor: profile
"k8s-apparmor-example-allow-write" 未加载`。还用相同的消息记录了一个事件。
<!-- ## Administration -->
@@ -52,14 +52,14 @@ Kubernetes 允许你将加载到节点上的 seccomp 配置文件自动应用于
<!--
In order to complete all steps in this tutorial, you must install
[kind](https://kind.sigs.k8s.io/docs/user/quick-start/) and
[kubectl](/docs/tasks/tools/install-kubectl/). This tutorial will show examples
[kubectl](/docs/tasks/tools/). This tutorial will show examples
with both alpha (pre-v1.19) and generally available seccomp functionality, so
make sure that your cluster is [configured
correctly](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)
for the version you are using.
-->
为了完成本教程中的所有步骤,你必须安装 [kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
和 [kubectl](/zh/docs/tasks/tools/install-kubectl/)。本教程将显示同时具有 alpha(v1.19 之前的版本)
和 [kubectl](/zh/docs/tasks/tools/)。本教程将显示同时具有 alpha(v1.19 之前的版本)
和通常可用的 seccomp 功能的示例,因此请确保为所使用的版本[正确配置](https://kind.sigs.k8s.io/docs/user/quick-start/#setting-kubernetes-version)了集群。
<!-- steps -->
@@ -91,8 +91,8 @@ into the cluster.
For simplicity, [kind](https://kind.sigs.k8s.io/) can be used to create a single
node cluster with the seccomp profiles loaded. Kind runs Kubernetes in Docker,
so each node of the cluster is actually just a container. This allows for files
to be mounted in the filesystem of each container just as one might load files
so each node of the cluster is a container. This allows for files
to be mounted in the filesystem of each container similar to loading files
onto a node.
Download the example above, and save it to a file named `kind.yaml`. Then create
@@ -101,8 +101,8 @@ the cluster with the configuration.
## 使用 Kind 创建一个本地 Kubernetes 集群
为简单起见,可以使用 [kind](https://kind.sigs.k8s.io/) 创建一个已经加载 seccomp 配置文件的单节点集群。
Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点实际上只是一个容器。这允许将文件挂载到每个容器的文件系统中,
就像将文件挂载到节点上一样
Kind 在 Docker 中运行 Kubernetes,因此集群的每个节点是一个容器。这允许将文件挂载到每个容器的文件系统中,
类似于将文件挂载到节点上。
{{< codenew file="pods/security/seccomp/kind.yaml" >}}
<br>
@@ -19,17 +19,13 @@ This page provides a real world example of how to configure Redis using a Config
<!--
* * Create a `kustomization.yaml` file containing:
* a ConfigMap generator
* a Pod resource config using the ConfigMap
* Apply the directory by running `kubectl apply -k ./`
* Create a ConfigMap with Redis configuration values
* Create a Redis Pod that mounts and uses the created ConfigMap
* Verify that the configuration was correctly applied.
-->
* * 创建一个包含以下内容的 `kustomization.yaml` 文件:
* 一个 ConfigMap 生成器
* 一个使用 ConfigMap 的 Pod 资源配置
* 使用 `kubectl apply -k ./` 应用整个路径的配置
* 使用 Redis 配置的值创建一个 ConfigMap
* 创建一个 Redis Pod,挂载并使用创建的 ConfigMap
* 验证配置已经被正确应用。
@@ -55,106 +51,312 @@ This page provides a real world example of how to configure Redis using a Config
<!--
## Real World Example: Configuring Redis using a ConfigMap
You can follow the steps below to configure a Redis cache using data stored in a ConfigMap.
Follow the steps below to configure a Redis cache using data stored in a ConfigMap.
First create a `kustomization.yaml` containing a ConfigMap from the `redis-config` file:
First create a ConfigMap with an empty configuration block:
-->
## 真实世界的案例:使用 ConfigMap 来配置 Redis
按照下面的步骤,您可以使用ConfigMap中的数据来配置Redis缓存。
按照下面的步骤,使用 ConfigMap 中的数据来配置 Redis 缓存。
1. 根据`docs/user-guide/configmap/redis/redis-config`来创建一个ConfigMap
{{< codenew file="pods/config/redis-config" >}}
首先创建一个配置模块为空的 ConfigMap
```shell
curl -OL https://k8s.io/examples/pods/config/redis-config
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-redis-config
files:
- redis-config
cat <<EOF >./example-redis-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: ""
EOF
```
<!--
Add the pod resource config to the `kustomization.yaml`:
Apply the ConfigMap created above, along with a Redis pod manifest:
-->
将 pod 的资源配置添加到 `kustomization.yaml` 文件中
应用上面创建的 ConfigMap 以及 Redis pod 清单
```shell
kubectl apply -f example-redis-config.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/config/redis-pod.yaml
```
<!--
Examine the contents of the Redis pod manifest and note the following:
* A volume named `config` is created by `spec.volumes[1]`
* The `key` and `path` under `spec.volumes[1].items[0]` exposes the `redis-config` key from the
`example-redis-config` ConfigMap as a file named `redis.conf` on the `config` volume.
* The `config` volume is then mounted at `/redis-master` by `spec.containers[0].volumeMounts[1]`.
This has the net effect of exposing the data in `data.redis-config` from the `example-redis-config`
ConfigMap above as `/redis-master/redis.conf` inside the Pod.
-->
检查 Redis pod 清单的内容,并注意以下几点:
* 由 `spec.volumes[1]` 创建一个名为 `config` 的卷。
* `spec.volumes[1].items[0]` 下的 `key``path` 会将来自 `example-redis-config`
ConfigMap 中的 `redis-config` 密钥公开在 `config` 卷上一个名为 `redis-config` 的文件中。
* 然后 `config` 卷被 `spec.containers[0].volumeMounts[1]` 挂载在 `/redis-master`
这样做的最终效果是将上面 `example-redis-config` 配置中 `data.redis-config` 的数据作为 Pod 中的 `/redis-master/redis.conf` 公开。
{{< codenew file="pods/config/redis-pod.yaml" >}}
```shell
curl -OL https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/config/redis-pod.yaml
<!--
Examine the created objects:
-->
检查创建的对象:
cat <<EOF >>./kustomization.yaml
resources:
- redis-pod.yaml
EOF
```shell
kubectl get pod/redis configmap/example-redis-config
```
<!--
Apply the kustomization directory to create both the ConfigMap and Pod objects:
You should see the following output:
-->
应用整个 kustomization 文件夹以创建 ConfigMap 和 Pod 对象
你应该可以看到以下输出
```shell
kubectl apply -k .
```
<!--
Examine the created objects by
-->
使用以下命令检查创建的对象
```shell
> kubectl get -k .
NAME DATA AGE
configmap/example-redis-config-dgh9dg555m 1 52s
NAME READY STATUS RESTARTS AGE
pod/redis 1/1 Running 0 52s
pod/redis 1/1 Running 0 8s
NAME DATA AGE
configmap/example-redis-config 1 14s
```
<!--
In the example, the config volume is mounted at `/redis-master`.
It uses `path` to add the `redis-config` key to a file named `redis.conf`.
The file path for the redis config, therefore, is `/redis-master/redis.conf`.
This is where the image will look for the config file for the redis master.
Recall that we left `redis-config` key in the `example-redis-config` ConfigMap blank:
-->
在示例中,配置卷挂载在 `/redis-master` 下。
它使用 `path``redis-config` 密钥添加到名为 `redis.conf` 的文件中。
因此,redis配置的文件路径为 `/redis-master/redis.conf`
这是镜像将在其中查找 redis master 的配置文件的位置。
回顾一下,我们在 `example-redis-config` ConfigMap 保留了空的 `redis-config` 键:
```shell
kubectl describe configmap/example-redis-config
```
<!--
Use `kubectl exec` to enter the pod and run the `redis-cli` tool to verify that
the configuration was correctly applied:
You should see an empty `redis-config` key:
-->
使用 `kubectl exec` 进入 pod 并运行 `redis-cli` 工具来验证配置已正确应用
你应该可以看到一个空的 `redis-config`
```shell
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
```
<!--
Use `kubectl exec` to enter the pod and run the `redis-cli` tool to check the current configuration:
-->
使用 `kubectl exec` 进入 pod,运行 `redis-cli` 工具检查当前配置:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It should show the default value of 0:
-->
它应该显示默认值 0
```shell
1) "maxmemory"
2) "0"
```
<!--
Similarly, check `maxmemory-policy`:
-->
同样,查看 `maxmemory-policy`
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
Which should also yield its default value of `noeviction`:
-->
它也应该显示默认值 `noeviction`
```shell
1) "maxmemory-policy"
2) "noeviction"
```
<!--
Now let's add some configuration values to the `example-redis-config` ConfigMap:
-->
现在,向 `example-redis-config` ConfigMap 添加一些配置:
{{< codenew file="pods/config/example-redis-config.yaml" >}}
<!--
Apply the updated ConfigMap:
-->
应用更新的 ConfigMap:
```shell
kubectl apply -f example-redis-config.yaml
```
<!--
Confirm that the ConfigMap was updated:
-->
确认 ConfigMap 已更新:
```shell
kubectl describe configmap/example-redis-config
```
<!--
You should see the configuration values we just added:
-->
你应该可以看到我们刚刚添加的配置:
```shell
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
----
maxmemory 2mb
maxmemory-policy allkeys-lru
```
<!--
Check the Redis Pod again using `redis-cli` via `kubectl exec` to see if the configuration was applied:
-->
通过 `kubectl exec` 使用 `redis-cli` 再次检查 Redis Pod,查看是否已应用配置:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It remains at the default value of 0:
-->
它保持默认值 0
```shell
1) "maxmemory"
2) "0"
```
<!--
Similarly, `maxmemory-policy` remains at the `noeviction` default setting:
-->
同样,`maxmemory-policy` 保留为默认设置 `noeviction`
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
Returns:
-->
返回:
```shell
1) "maxmemory-policy"
2) "noeviction"
```
<!--
The configuration values have not changed because the Pod needs to be restarted to grab updated
values from associated ConfigMaps. Let's delete and recreate the Pod:
-->
配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
让我们删除并重新创建 Pod
```shell
kubectl delete pod redis
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/config/redis-pod.yaml
```
<!--
Now re-check the configuration values one last time:
-->
现在,最后一次重新检查配置值:
```shell
kubectl exec -it redis -- redis-cli
```
<!--
Check `maxmemory`:
-->
查看 `maxmemory`
```shell
127.0.0.1:6379> CONFIG GET maxmemory
```
<!--
It should now return the updated value of 2097152:
-->
现在,它应该返回更新后的值 2097152:
```shell
1) "maxmemory"
2) "2097152"
```
<!--
Similarly, `maxmemory-policy` has also been updated:
-->
同样,`maxmemory-policy` 也已更新:
```shell
127.0.0.1:6379> CONFIG GET maxmemory-policy
```
<!--
It now reflects the desired value of `allkeys-lru`:
-->
现在它反映了期望值 `allkeys-lru`
```shell
1) "maxmemory-policy"
2) "allkeys-lru"
```
<!--
Delete the created pod:
Clean up your work by deleting the created resources:
-->
删除创建的 pod
删除创建的资源,清理你的工作
```shell
kubectl delete pod redis
kubectl delete pod/redis configmap/example-redis-config
```
## {{% heading "whatsnext" %}}
+6 -6
View File
@@ -112,7 +112,7 @@ This tutorial provides a container image that uses NGINX to echo back all the re
<!--
The `dashboard` command enables the dashboard add-on and opens the proxy in the default web browser. You can create Kubernetes resources on the dashboard such as Deployment and Service.
If you are running in an environment as root, see [Open Dashboard with URL](/docs/tutorials/hello-minikube#open-dashboard-with-url).
If you are running in an environment as root, see [Open Dashboard with URL](#open-dashboard-with-url).
To stop the proxy, run `Ctrl+C` to exit the process. The dashboard remains running.
-->
@@ -120,7 +120,7 @@ To stop the proxy, run `Ctrl+C` to exit the process. The dashboard remains runni
`dashboard` 命令启用仪表板插件,并在默认的 Web 浏览器中打开代理。你可以在仪表板上创建 Kubernetes 资源,例如 Deployment 和 Service。
如果你以 root 用户身份在环境中运行,
请参见[使用 URL 打开仪表板](/zh/docs/tutorials/hello-minikube#open-dashboard-with-url)。
请参见[使用 URL 打开仪表板](#open-dashboard-with-url)。
要停止代理,请运行 `Ctrl+C` 退出该进程。仪表板仍在运行中。
{{< /note >}}
@@ -273,9 +273,9 @@ Kubernetes [*Service*](/docs/concepts/services-networking/service/).
如果你用 `kubectl expose` 暴露了其它的端口,客户端将不能访问其它端口。
<!--
2. View the Service you just created:
2. View the Service you created:
-->
2. 查看你刚刚创建的 Service
2. 查看你创建的 Service
```shell
kubectl get services
@@ -391,9 +391,9 @@ Minikube 有一组内置的 {{< glossary_tooltip text="插件" term_id="addons"
```
<!--
3. View the Pod and Service you just created:
3. View the Pod and Service you created:
-->
3. 查看刚才创建的 Pod 和 Service
3. 查看创建的 Pod 和 Service
```shell
kubectl get pod,svc -n kube-system
@@ -133,6 +133,8 @@ Headless Service and StatefulSet defined in `web.yaml`.
```shell
kubectl apply -f web.yaml
```
```
service/nginx created
statefulset.apps/web created
```
@@ -148,10 +150,19 @@ The command above creates two Pods, each running an
```shell
kubectl get service nginx
```
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 12s
```
<!--
...then get the `web` StatefulSet, to verify that both were created successfully:
-->
...然后获取 `web` StatefulSet,以验证两者均已成功创建:
```shell
kubectl get statefulset web
```
```
NAME DESIRED CURRENT AGE
web 2 1 20s
```
@@ -174,6 +185,8 @@ look like the example below.
```shell
kubectl get pods -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
@@ -215,10 +228,11 @@ StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份
```shell
kubectl get pods -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
```
<!--
@@ -247,7 +261,9 @@ Pod 的名称的形式为`<statefulset name>-<ordinal index>`。
每个 Pod 都拥有一个基于其顺序索引的稳定的主机名。使用[`kubectl exec`](/zh/docs/reference/generated/kubectl/kubectl-commands/#exec)在每个 Pod 中执行`hostname`
```shell
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
```
```
web-0
web-1
```
@@ -265,7 +281,20 @@ addresses.
```shell
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
```
<!--
which starts a new shell. In that new shell, run:
-->
这将启动一个新的 shell。在新 shell 中,运行:
```shell
# Run this in the dns-test container shell
nslookup web-0.nginx
```
<!--
The output is similar to:
-->
输出类似于:
```
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
@@ -306,6 +335,8 @@ the Pods in the StatefulSet.
```shell
kubectl delete pod -l app=nginx
```
```
pod "web-0" deleted
pod "web-1" deleted
```
@@ -319,6 +350,8 @@ Running and Ready.
```shell
kubectl get pod -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
@@ -338,11 +371,32 @@ DNS entries.
```shell
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
```
```
web-0
web-1
```
<!--
then, run:
-->
然后,运行:
```
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
```
<!--
which starts a new shell.
In that new shell, run:
-->
这将启动一个新的 shell。在新 shell 中,运行:
```shell
# Run this in the dns-test container shell
nslookup web-0.nginx
```
<!--
The output is similar to:
-->
输出类似于:
```
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
@@ -401,6 +455,12 @@ Get the PersistentVolumeClaims for `web-0` and `web-1`.
```shell
kubectl get pvc -l app=nginx
```
<!--
The output is similar to:
-->
输出类似于:
```
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
@@ -430,31 +490,35 @@ StatefulSets `spec` 中的 `volumeMounts` 字段保证了 `/usr/share/nginx/html
将 Pod 的主机名写入它们的`index.html`文件并验证 NGINX web 服务器使用该主机名提供服务。
```shell
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'echo "$(hostname)" > /usr/share/nginx/html/index.html'; done
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
```
```
web-0
web-1
```
{{< note >}}
<!--
If you instead see 403 Forbidden responses for the above curl command,
If you instead see **403 Forbidden** responses for the above curl command,
you will need to fix the permissions of the directory mounted by the `volumeMounts`
(due to a [bug when using hostPath volumes](https://github.com/kubernetes/kubernetes/issues/2630)) with:
(due to a [bug when using hostPath volumes](https://github.com/kubernetes/kubernetes/issues/2630)),
by running:
-->
请注意,如果你看见上面的 curl 命令返回了 403 Forbidden 的响应,
你需要像这样修复使用 `volumeMounts`due to a [bug when using hostPath volumes](https://github.com/kubernetes/kubernetes/issues/2630)挂载的目录的权限:
请注意,如果你看见上面的 curl 命令返回了 **403 Forbidden** 的响应,你需要像这样修复使用 `volumeMounts`
(原因归咎于[使用 hostPath 卷时存在的缺陷](https://github.com/kubernetes/kubernetes/issues/2630)
挂载的目录的权限
运行:
`for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done`
```shell
for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done
```
<!--
before retrying the curl command above.
before retrying the `curl` command above.
-->
在你重新尝试上面的 curl 命令之前。
在你重新尝试上面的 `curl` 命令之前。
{{< /note >}}
<!--
@@ -475,6 +539,8 @@ In a second terminal, delete all of the StatefulSet's Pods.
```shell
kubectl delete pod -l app=nginx
```
```
pod "web-0" deleted
pod "web-1" deleted
```
@@ -487,6 +553,8 @@ for all of the Pods to transition to Running and Ready.
```shell
kubectl get pod -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
@@ -504,7 +572,9 @@ Verify the web servers continue to serve their hostnames.
验证所有 web 服务器在继续使用它们的主机名提供服务。
```
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
```
```
web-0
web-1
```
@@ -555,6 +625,8 @@ to 5.-->
```shell
kubectl scale sts web --replicas=5
```
```
statefulset.apps/web scaled
```
<!--
@@ -566,6 +638,8 @@ for the three additional Pods to transition to Running and Ready.
```shell
kubectl get pods -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2h
web-1 1/1 Running 0 2h
@@ -617,8 +691,9 @@ three replicas.
```shell
kubectl patch sts web -p '{"spec":{"replicas":3}}'
```
```
statefulset.apps/web patched
```
<!--
@@ -627,8 +702,10 @@ Wait for `web-4` and `web-3` to transition to Terminating.
等待 `web-4``web-3` 状态变为 Terminating。
```
```shell
kubectl get pods -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
@@ -663,6 +740,8 @@ Get the StatefulSet's PersistentVolumeClaims.
```shell
kubectl get pvc -l app=nginx
```
```
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h
@@ -718,6 +797,8 @@ Patch `web` StatefulSet 来执行 `RollingUpdate` 更新策略。
```shell
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
```
```
statefulset.apps/web patched
```
<!--
@@ -729,8 +810,9 @@ image again.
```shell
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
```
```
statefulset.apps/web patched
```
<!--
@@ -741,6 +823,12 @@ In another terminal, watch the Pods in the StatefulSet.
```shell
kubectl get po -l app=nginx -w
```
<!--
The output is similar to:
-->
输出类似于:
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 7m
web-1 1/1 Running 0 7m
@@ -798,7 +886,9 @@ StatefulSet 里的 Pod 采用和序号相反的顺序更新。在更新下一个
获取 Pod 来查看他们的容器镜像。
```shell
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
```
```
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
@@ -836,6 +926,8 @@ Patch `web` StatefulSet 来对 `updateStrategy` 字段添加一个分区。
```shell
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
```
```
statefulset.apps/web patched
```
@@ -847,6 +939,8 @@ Patch the StatefulSet again to change the container's image.
```shell
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
```
```
statefulset.apps/web patched
```
@@ -857,7 +951,9 @@ Delete a Pod in the StatefulSet.
删除 StatefulSet 中的 Pod。
```shell
kubectl delete po web-2
kubectl delete pod web-2
```
```
pod "web-2" deleted
```
@@ -868,7 +964,9 @@ Wait for the Pod to be Running and Ready.
等待 Pod 变成 Running 和 Ready。
```shell
kubectl get po -lapp=nginx -w
kubectl get pod -l app=nginx -w
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
@@ -883,10 +981,10 @@ Get the Pod's container.
获取 Pod 的容器。
```shell
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
```
```
k8s.gcr.io/nginx-slim:0.8
```
<!--
@@ -915,6 +1013,8 @@ Patch the StatefulSet to decrement the partition.
```shell
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
```
```
statefulset.apps/web patched
```
@@ -925,7 +1025,9 @@ Wait for `web-2` to be Running and Ready.
等待 `web-2` 变成 Running 和 Ready。
```shell
kubectl get po -lapp=nginx -w
kubectl get pod -l app=nginx -w
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
@@ -940,7 +1042,9 @@ Get the Pod's container.
获取 Pod 的容器。
```shell
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
```
```
k8s.gcr.io/nginx-slim:0.7
```
@@ -959,7 +1063,9 @@ Delete the `web-1` Pod.
删除 `web-1` Pod。
```shell
kubectl delete po web-1
kubectl delete pod web-1
```
```
pod "web-1" deleted
```
@@ -970,7 +1076,13 @@ Wait for the `web-1` Pod to be Running and Ready.
等待 `web-1` 变成 Running 和 Ready。
```shell
kubectl get po -lapp=nginx -w
kubectl get pod -l app=nginx -w
```
<!--
The output is similar to:
-->
输出类似于:
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 0/1 Terminating 0 6m
@@ -991,7 +1103,9 @@ Get the `web-1` Pods container.
获取 `web-1` Pod 的容器。
```shell
kubectl get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
```
```
k8s.gcr.io/nginx-slim:0.8
```
@@ -1027,6 +1141,8 @@ The partition is currently set to `2`. Set the partition to `0`.
```shell
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
```
```
statefulset.apps/web patched
```
@@ -1037,7 +1153,13 @@ Wait for all of the Pods in the StatefulSet to become Running and Ready.
等待 StatefulSet 中的所有 Pod 变成 Running 和 Ready。
```shell
kubectl get po -lapp=nginx -w
kubectl get pod -l app=nginx -w
```
<!--
The output is similar to:
-->
输出类似于:
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m
web-1 0/1 ContainerCreating 0 11s
@@ -1061,11 +1183,12 @@ Get the Pod's containers.
获取 Pod 的容器。
```shell
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
```
```
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
```
<!--
@@ -1126,6 +1249,8 @@ not delete any of its Pods.
```shell
kubectl delete statefulset web --cascade=false
```
```
statefulset.apps "web" deleted
```
@@ -1137,6 +1262,8 @@ Get the Pods to examine their status.
```shell
kubectl get pods -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 1/1 Running 0 7m
@@ -1153,6 +1280,8 @@ Delete `web-0`.
```shell
kubectl delete pod web-0
```
```
pod "web-0" deleted
```
@@ -1164,6 +1293,8 @@ Get the StatefulSet's Pods.
```shell
kubectl get pods -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 10m
web-2 1/1 Running 0 7m
@@ -1193,9 +1324,10 @@ an error indicating that the Service already exists.
```shell
kubectl apply -f web.yaml
```
```
statefulset.apps/web created
service/nginx unchanged
```
<!--
Ignore the error. It only indicates that an attempt was made to create the nginx
@@ -1211,6 +1343,8 @@ Examine the output of the `kubectl get` command running in the first terminal.
```shell
kubectl get pods -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 2m
@@ -1228,24 +1362,28 @@ web-2 0/1 Terminating 0 3m
<!--
When the `web` StatefulSet was recreated, it first relaunched `web-0`.
Since `web-1` was already Running and Ready, when `web-0` transitioned to
Running and Ready, it simply adopted this Pod. Since you recreated the StatefulSet
with `replicas` equal to 2, once `web-0` had been recreated, and once
`web-1` had been determined to already be Running and Ready, `web-2` was
terminated.
Running and Ready, it adopted this Pod. Since you recreated the StatefulSet
with `replicas` equal to 2, once `web-0` had been recreated, and once
`web-1` had been determined to already be Running and Ready, `web-2` was
terminated.
Let's take another look at the contents of the `index.html` file served by the
Pods' webservers.
Pods' webservers:
-->
当重新创建 `web` StatefulSet 时,`web-0`被第一个重新启动。
由于 `web-1` 已经处于 Running 和 Ready 状态,当 `web-0` 变成 Running 和 Ready 时,StatefulSet 会直接接收这个 Pod。
由于你重新创建的 StatefulSet 的 `replicas` 等于 2一旦 `web-0` 被重新创建并且 `web-1` 被认为已经处于 Running 和 Ready 状态时,`web-2`将会被终止。
当重新创建 `web` StatefulSet 时,`web-0` 被第一个重新启动。
由于 `web-1` 已经处于 Running 和 Ready 状态,当 `web-0` 变成 Running 和 Ready 时,
StatefulSet 会接收这个 Pod。由于你重新创建的 StatefulSet 的 `replicas` 等于 2
一旦 `web-0` 被重新创建并且 `web-1` 被认为已经处于 Running 和 Ready 状态时,`web-2` 将会被终止。
让我们再看看被 Pod 的 web 服务器加载的 `index.html` 的内容
让我们再看看被 Pod 的 web 服务器加载的 `index.html` 的内容
```shell
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
```
```
web-0
web-1
```
@@ -1276,11 +1414,17 @@ In one terminal window, watch the Pods in the StatefulSet.
kubectl get pods -w -l app=nginx
```
<!--
In another terminal, delete the StatefulSet again. This time, omit the
-->
在另一个窗口中再次删除这个 StatefulSet。这次省略 `--cascade=false` 参数。
```shell
kubectl delete statefulset web
```
```
statefulset.apps "web" deleted
```
@@ -1293,6 +1437,9 @@ and wait for all of the Pods to transition to Terminating.
```shell
kubectl get pods -w -l app=nginx
```
```
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 11m
web-1 1/1 Running 0 27m
@@ -1327,6 +1474,9 @@ must delete the `nginx` Service manually.
```shell
kubectl delete service nginx
```
```
service "nginx" deleted
```
@@ -1338,9 +1488,11 @@ Recreate the StatefulSet and Headless Service one more time.
```shell
kubectl apply -f web.yaml
```
```
service/nginx created
statefulset.apps/web created
```
<!--
@@ -1351,7 +1503,10 @@ the contents of their `index.html` files.
当 StatefulSet 所有的 Pod 变成 Running 和 Ready 时,获取它们的 `index.html` 文件的内容。
```shell
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
```
```
web-0
web-1
```
@@ -1372,13 +1527,17 @@ Finally delete the `web` StatefulSet and the `nginx` service.
```shell
kubectl delete service nginx
```
```
service "nginx" deleted
```
... 并且删除 `web` StatefulSet:
```shell
kubectl delete statefulset web
```
```
statefulset "web" deleted
```
@@ -1402,15 +1561,17 @@ above.
`Parallel` pod management tells the StatefulSet controller to launch or
terminate all Pods in parallel, and not to wait for Pods to become Running
and Ready or completely terminated prior to launching or terminating another
Pod.
Pod. This option only affects the behavior for scaling operations. Updates are not affected.
-->
## Pod 管理策略
对于某些分布式系统来说,StatefulSet 的顺序性保证是不必要和/或者不应该的。这些系统仅仅要求唯一性和身份标志。
为了解决这个问题,在 Kubernetes 1.7 中我们针对 StatefulSet API Object 引入了 `.spec.podManagementPolicy`
对于某些分布式系统来说,StatefulSet 的顺序性保证是不必要和/或者不应该的。
这些系统仅仅要求唯一性和身份标志。为了解决这个问题,在 Kubernetes 1.7 中
我们针对 StatefulSet API 对象引入了 `.spec.podManagementPolicy`
此选项仅影响扩缩操作的行为。更新不受影响。
### OrderedReady Pod 管理策略
@@ -1421,7 +1582,8 @@ Pod.
### Parallel Pod 管理策略
`Parallel` pod 管理策略告诉 StatefulSet 控制器并行的终止所有 Pod,在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态。
`Parallel` pod 管理策略告诉 StatefulSet 控制器并行的终止所有 Pod,
在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态。
{{< codenew file="application/web/web-parallel.yaml" >}}
@@ -1447,16 +1609,17 @@ kubectl get po -lapp=nginx -w
```
<!--
In another terminal, create the StatefulSet and Service in the manifest.
In another terminal, create the StatefulSet and Service in the manifest:
-->
在另一个终端窗口创建清单中的 StatefulSet 和 Service
在另一个终端窗口创建清单中的 StatefulSet 和 Service
```shell
kubectl apply -f web-parallel.yaml
```
```
service/nginx created
statefulset.apps/web created
```
<!--
@@ -1466,7 +1629,9 @@ Examine the output of the `kubectl get` command that you executed in the first t
查看你在第一个终端中运行的 `kubectl get` 命令的输出。
```shell
kubectl get po -lapp=nginx -w
kubectl get pod -l app=nginx -w
```
```
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
@@ -1491,6 +1656,8 @@ StatefulSet 控制器同时启动了 `web-0` 和 `web-1`。
```shell
kubectl scale statefulset/web --replicas=4
```
```
statefulset.apps/web scaled
```
@@ -1500,7 +1667,7 @@ Examine the output of the terminal where the `kubectl get` command is running.
`kubectl get` 命令运行的终端里检查它的输出。
```shell
```
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 7s
@@ -1510,27 +1677,36 @@ web-3 1/1 Running 0 26s
```
<!--
The StatefulSet controller launched two new Pods, and it did not wait for
The StatefulSet launched two new Pods, and it did not wait for
the first to become Running and Ready prior to launching the second.
Keep this terminal open, and in another terminal delete the `web` StatefulSet.
## {{% heading "cleanup" %}}
You should have two terminals open, ready for you to run `kubectl` commands as
part of cleanup.
-->
StatefulSet 控制器启动了两个新的 Pod,而且在启动第二个之前并没有等待第一个变成 Running 和 Ready 状态。
StatefulSet 启动了两个新的 Pod,而且在启动第二个之前并没有等待第一个变成 Running 和 Ready 状态。
保持这个终端打开,并在另一个终端删除 `web` StatefulSet。
## {{% heading "cleanup" %}}
您应该打开两个终端,准备在清理过程中运行 `kubectl` 命令。
```shell
kubectl delete sts web
# sts is an abbreviation for statefulset
```
<!--
Again, examine the output of the `kubectl get` command running in the other terminal.
You can watch `kubectl get` to see those Pods being deleted.
-->
在另一个终端里再次检查 `kubectl get` 命令的输出。
你可以监测 `kubectl get` 来查看那些 Pod 被删除
```shell
kubectl get pod -l app=nginx -w
```
```
web-3 1/1 Terminating 0 9m
web-2 1/1 Terminating 0 9m
web-3 1/1 Terminating 0 9m
@@ -1579,10 +1755,12 @@ kubectl delete svc nginx
<!--
You will need to delete the persistent storage media for the PersistentVolumes
used in this tutorial. Follow the necessary steps, based on your environment,
storage configuration, and provisioning method, to ensure that all storage is
reclaimed.
You also need to delete the persistent storage media for the PersistentVolumes
used in this tutorial.
Follow the necessary steps, based on your environment, storage configuration,
and provisioning method, to ensure that all storage is reclaimed.
-->
你需要删除本教程中用到的 PersistentVolumes 的持久化存储介质。基于你的环境、存储配置和提供方式,按照必须的步骤保证回收所有的存储。
File diff suppressed because it is too large Load Diff
@@ -20,7 +20,7 @@ external IP address.
## {{% heading "prerequisites" %}}
<!--
* Install [kubectl](/docs/tasks/tools/install-kubectl/).
* Install [kubectl](/docs/tasks/tools/).
* Use a cloud provider like Google Kubernetes Engine or Amazon Web Services to
create a Kubernetes cluster. This tutorial creates an
[external load balancer](/docs/tasks/access-application-cluster/create-external-load-balancer/),
@@ -28,7 +28,7 @@ external IP address.
* Configure `kubectl` to communicate with your Kubernetes API server. For instructions, see the
documentation for your cloud provider.
-->
* 安装 [kubectl](/zh/docs/tasks/tools/install-kubectl/).
* 安装 [kubectl](/zh/docs/tasks/tools/).
* 使用 Google Kubernetes Engine 或 Amazon Web Services 等云供应商创建 Kubernetes 集群。
本教程创建了一个[外部负载均衡器](/zh/docs/tasks/access-application-cluster/create-external-load-balancer/)
需要云供应商。
@@ -100,16 +100,15 @@ The manifest file, included below, specifies a Deployment controller that runs a
1. 在下载清单文件的目录中启动终端窗口。
2. 从 `mongo-deployment.yaml` 文件中应用 MongoDB Deployment
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/mongo-deployment.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-deployment.yaml
```
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/mongo-deployment.yaml
-->
<!--
1. Query the list of Pods to verify that the MongoDB Pod is running:
-->
@@ -156,15 +155,15 @@ The guestbook application needs to communicate to the MongoDB to write its data.
-->
1. 使用下面的 `mongo-service.yaml` 文件创建 MongoDB 的服务:
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/mongo-service.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/mongo-service.yaml
```
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/mongo-service.yaml
-->
<!--
1. Query the list of Services to verify that the MongoDB Service is running:
-->
@@ -182,7 +181,7 @@ kubectl apply -f ./content/en/examples/application/guestbook/mongo-service.yaml
```shell
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 1m
mongo ClusterIP 10.0.0.151 <none> 6379/TCP 8s
mongo ClusterIP 10.0.0.151 <none> 27017/TCP 8s
```
<!--
@@ -216,15 +215,15 @@ The guestbook application has a web frontend serving the HTTP requests written i
-->
1. 从 `frontend-deployment.yaml` 应用前端 Deployment 文件:
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-deployment.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
```
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-deployment.yaml
-->
<!--
1. Query the list of Pods to verify that the three frontend replicas are running:
-->
@@ -253,10 +252,11 @@ kubectl apply -f ./content/en/examples/application/guestbook/frontend-deployment
### 创建前端服务
<!--
The `mongo` Services you applied is only accessible within the Kubernetes cluster because the default type for a Service is [ClusterIP](/docs/concepts/services-networking/service/#publishing-services---service-types). `ClusterIP` provides a single IP address for the set of Pods the Service is pointing to. This IP address is accessible only within the cluster.
The `mongo` Services you applied is only accessible within the Kubernetes cluster because the default type for a Service is [ClusterIP](/docs/concepts/services-networking/service/#publishing-services-service-types). `ClusterIP` provides a single IP address for the set of Pods the Service is pointing to. This IP address is accessible only within the cluster.
-->
应用的 `mongo` 服务只能在 Kubernetes 集群中访问,因为服务的默认类型是
[ClusterIP](/zh/docs/concepts/services-networking/service/#publishing-services---service-types)。`ClusterIP` 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。
[ClusterIP](/zh/docs/concepts/services-networking/service/#publishing-services-service-types)。
`ClusterIP` 为服务指向的 Pod 集提供一个 IP 地址。这个 IP 地址只能在集群中访问。
<!--
If you want guests to be able to access your guestbook, you must configure the frontend Service to be externally visible, so a client can request the Service from outside the Kubernetes cluster. However a Kubernetes user you can use `kubectl port-forward` to access the service even though it uses a `ClusterIP`.
@@ -278,15 +278,15 @@ Some cloud providers, like Google Compute Engine or Google Kubernetes Engine, su
-->
1. 从 `frontend-service.yaml` 文件中应用前端服务:
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-service.yaml
-->
```shell
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
```
<!---
for local testing of the content via relative file path
kubectl apply -f ./content/en/examples/application/guestbook/frontend-service.yaml
-->
<!--
1. Query the list of Services to verify that the frontend Service is running:
-->
@@ -303,7 +303,7 @@ kubectl apply -f ./content/en/examples/application/guestbook/frontend-service.ya
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.0.0.112 <none> 80/TCP 6s
frontend ClusterIP 10.0.0.112 <none> 80/TCP 6s
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 4m
mongo ClusterIP 10.0.0.151 <none> 6379/TCP 2m
```
@@ -364,8 +364,8 @@ If you deployed the `frontend-service.yaml` manifest with type: `LoadBalancer` y
响应应该与此类似:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend ClusterIP 10.51.242.136 109.197.92.229 80:32372/TCP 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.242.136 109.197.92.229 80:32372/TCP 1m
```
<!--
@@ -414,7 +414,7 @@ Scaling up or down is easy because your servers are defined as a Service that us
frontend-3823415956-k22zn 1/1 Running 0 54m
frontend-3823415956-w9gbt 1/1 Running 0 54m
frontend-3823415956-x2pld 1/1 Running 0 5s
mongo-1068406935-3lswp 1/1 Running 0 56m
mongo-1068406935-3lswp 1/1 Running 0 56m
```
<!--
@@ -444,7 +444,7 @@ Scaling up or down is easy because your servers are defined as a Service that us
NAME READY STATUS RESTARTS AGE
frontend-3823415956-k22zn 1/1 Running 0 1h
frontend-3823415956-w9gbt 1/1 Running 0 1h
mongo-1068406935-3lswp 1/1 Running 0 1h
mongo-1068406935-3lswp 1/1 Running 0 1h
```