Update localization guidelines (#10485)
* Update localization guidelines for language labels
Continuing work
Continuing work
Continuing work
More work in progress
Add local OWNERS folders
Add an OWNERS file to Chinese
Remove shortcode for repos
Add Japanese
Alphabetize languages, change weights accordingly
More updates
Add Korean in Korean
Add English to languageName
Feedback from gochist
Move Chinese content from cn/ to zh/
Move OWNERS from cn/ to zh/
Resolve merge conflicts by updating from master
Add files back in to prep for resolution
After rebase on upstream/master, remove files
Review and update localization guidelines
Feedback from gochist, tnir, cstoku
Add a trailing newline to content/ja/OWNERS
Add a trailing newline to content/zh/OWNERS
Drop requirement for GH repo project
Clarify language about forks/branches
Edits and typos
Remove a shortcode specific to a multi-repo language setup
Update aliases and owners
Add explicit OWNERS for content/en
Migrate content from Chinese repo, update regex in config.toml
Remove untranslated strings
Add trailing newline to content/en/OWNERS
Add trailing newlines to OWNERS files
add Jaguar project description (#10433)
* add Jaguar project description
[Jaguar](https://gitlab.com/sdnlab/jaguar) is an open source solution for Kubernetes's network based on OpenDaylight.
Jaguar provides overlay network using vxlan and Jaguar CNIPlugin provides one IP address per pod.
* Minor newline tweak
blog post for azure vmss (#10538)
Add microk8s to pick-right-solution.md (#10542)
* Add microk8s to pick-right-solution.md
Microk8s is a single-command installation of upstream Kubernetes on any Linux and should be included in the list of local-machine solutions.
* capitalized Istio
Add microk8s to foundational.md (#10543)
* Add microk8s to foundational.md
Adding microk8s as credible and stable alternative to get started with Kubernetes on a local machine. This is especially attractive for those not wanting to incur the overhead of running a VM for a local cluster.
* Update foundational.md
Thank you for your suggestions! LMK if this works now?
* Rewrote first paragraph
And included a bullet list of features of microk8s
* Copyedit
fix typo (#10545)
Fix the kubectl subcommands links. (#10550)
Signed-off-by: William Zhang <warmchang@outlook.com>
Fix command issue (#10515)
Signed-off-by: mooncake <xcoder@tenxcloud.com>
remove imported community files per issue 10184 (#10501)
networking.md: Markdown fix (#10498)
Fix front matter, federation command-line tools (#10500)
Clean up glossary entry (#10399)
update slack link (#10536)
typo in StatefulSet docs (#10558)
fix discription about horizontal pod autoscale (#10557)
Remove redundant symbols (#10556)
Fix issue #10520 (#10554)
Signed-off-by: William Zhang <warmchang@outlook.com>
Update api-concepts.md (#10534)
Revert "Fix command issue (#10515)"
This reverts commit c02a7fb9f9.
Update memory-constraint-namespace.md (#10530)
update memory request to 100MiB corresponding the yaml content
Blog: Introducing Volume Snapshot Alpha for Kubernetes (#10562)
* blog post for azure vmss
* snapshot blog post
Resolve merge conflicts in OWNERS*
Minor typo fix (#10567)
Not sure what's supposed to be here, proposing removing it.
* Feedback from gochist
Tweaks to feedback
* Feedback from ClaudiaJKang
This commit is contained in:
committed by
k8s-ci-robot
parent
753f57f0e6
commit
abcee2dccd
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: command-demo
|
||||
labels:
|
||||
purpose: demonstrate-command
|
||||
spec:
|
||||
containers:
|
||||
- name: command-demo-container
|
||||
image: debian
|
||||
command: ["printenv"]
|
||||
args: ["HOSTNAME", "KUBERNETES_PORT"]
|
||||
restartPolicy: OnFailure
|
||||
@@ -0,0 +1,299 @@
|
||||
---
|
||||
title: Managing Compute Resources for Containers
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
当您定义 [Pod](/docs/user-guide/pods) 的时候可以选择为每个容器指定需要的 CPU 和内存(RAM)大小。当为容器指定了资源请求后,调度器就能够更好的判断出将容器调度到哪个节点上。如果您还为容器指定了资源限制,节点上的资源就可以按照指定的方式做竞争。关于资源请求和限制的不同点和更多资料请参考 [Resource QoS](https://git.k8s.io/community/contributors/design-proposals/resource-qos.md)。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 资源类型
|
||||
|
||||
*CPU* 和 *内存* 都是 *资源类型*。资源类型具有基本单位。CPU 的单位是 core,内存的单位是 byte。
|
||||
|
||||
CPU和内存统称为*计算资源*,也可以称为*资源*。计算资源的数量是可以被请求、分配、消耗和可测量的。它们与 [API 资源](/docs/api/) 不同。 API 资源(如 Pod 和 [Service](/docs/user-guide/services))是可通过 Kubernetes API server 读取和修改的对象。
|
||||
|
||||
## Pod 和 容器的资源请求和限制
|
||||
|
||||
Pod 中的每个容器都可以指定以下的一个或者多个值:
|
||||
|
||||
- `spec.containers[].resources.limits.cpu`
|
||||
- `spec.containers[].resources.limits.memory`
|
||||
- `spec.containers[].resources.requests.cpu`
|
||||
- `spec.containers[].resources.requests.memory`
|
||||
|
||||
尽管只能在个别容器上指定请求和限制,但是我们可以方便地计算出 Pod 资源请求和限制。特定资源类型的Pod 资源请求/限制是 Pod 中每个容器的该类型的资源请求/限制的总和。
|
||||
|
||||
## CPU 的含义
|
||||
|
||||
CPU 资源的限制和请求以 *cpu* 为单位。
|
||||
|
||||
Kubernetes 中的一个 cpu 等于:
|
||||
|
||||
- 1 AWS vCPU
|
||||
- 1 GCP Core
|
||||
- 1 Azure vCore
|
||||
- 1 *Hyperthread* 在带有超线程的裸机 Intel 处理器上
|
||||
|
||||
允许浮点数请求。具有 `spec.containers[].resources.requests.cpu` 为 0.5 的容器保证了一半 CPU 要求 1 CPU的一半。表达式 `0.1` 等价于表达式 `100m`,可以看作 “100 millicpu”。有些人说成是“一百毫 cpu”,其实说的是同样的事情。具有小数点(如 `0.1`)的请求由 API 转换为`100m`,精度不超过 `1m`。因此,可能会优先选择 `100m` 的形式。
|
||||
|
||||
CPU 总是要用绝对数量,不可以使用相对数量;0.1 的 CPU 在单核、双核、48核的机器中的意义是一样的。
|
||||
|
||||
## 内存的含义
|
||||
|
||||
内存的限制和请求以字节为单位。您可以使用以下后缀之一作为平均整数或定点整数表示内存:E,P,T,G,M,K。您还可以使用两个字母的等效的幂数:Ei,Pi,Ti ,Gi,Mi,Ki。例如,以下代表大致相同的值:
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
下面是个例子。
|
||||
|
||||
以下 Pod 有两个容器。每个容器的请求为 0.25 cpu 和 64MiB(2<sup>26</sup> 字节)内存,每个容器的限制为 0.5 cpu 和 128MiB 内存。您可以说该 Pod 请求 0.5 cpu 和 128 MiB 的内存,限制为 1 cpu 和 256MiB 的内存。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
- name: wp
|
||||
image: wordpress
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
## 具有资源请求的 Pod 如何调度
|
||||
|
||||
当您创建一个 Pod 时,Kubernetes 调度程序将为 Pod 选择一个节点。每个节点具有每种资源类型的最大容量:可为 Pod 提供的 CPU 和内存量。调度程序确保对于每种资源类型,调度的容器的资源请求的总和小于节点的容量。请注意,尽管节点上的实际内存或 CPU 资源使用量非常低,但如果容量检查失败,则调度程序仍然拒绝在该节点上放置 Pod。当资源使用量稍后增加时,例如在请求率的每日峰值期间,这可以防止节点上的资源短缺。
|
||||
|
||||
## 具有资源限制的 Pod 如何运行
|
||||
|
||||
当 kubelet 启动一个 Pod 的容器时,它会将 CPU 和内存限制传递到容器运行时。
|
||||
|
||||
当使用 Docker 时:
|
||||
|
||||
- `spec.containers[].resources.requests.cpu` 的值将转换成 millicore 值,这是个浮点数,并乘以1024,这个数字中的较大者或2用作 `docker run` 命令中的[ `--cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint) 标志的值。
|
||||
- `spec.containers[].resources.limits.cpu` 被转换成 millicore 值。被乘以 100000 然后 除以 1000。这个数字用作 `docker run` 命令中的 [`--cpu-quota`](https://docs.docker.com/engine/reference/run/#/cpu-quota-constraint) 标志的值。[`--cpu-quota` ] 标志被设置成了 100000,表示测量配额使用的默认100ms 周期。如果 [`--cpu-cfs-quota`] 标志设置为 true,则 kubelet 会强制执行 cpu 限制。从 Kubernetes 1.2 版本起,此标志默认为 true。
|
||||
- `spec.containers[].resources.limits.memory` 被转换为整型,作为 `docker run` 命令中的 [`--memory`](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) 标志的值。
|
||||
|
||||
如果容器超过其内存限制,则可能会被终止。如果可重新启动,则与所有其他类型的运行时故障一样,kubelet 将重新启动它。
|
||||
|
||||
如果一个容器超过其内存请求,那么当节点内存不足时,它的 Pod 可能被逐出。
|
||||
|
||||
容器可能被允许也可能不被允许超过其 CPU 限制时间。但是,由于 CPU 使用率过高,不会被杀死。
|
||||
|
||||
要确定容器是否由于资源限制而无法安排或被杀死,请参阅 [疑难解答](#troubleshooting) 部分。
|
||||
|
||||
## 监控计算资源使用
|
||||
|
||||
Pod 的资源使用情况被报告为 Pod 状态的一部分。
|
||||
|
||||
如果为集群配置了 [可选监控](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/cluster-monitoring/README.md),则可以从监控系统检索 Pod 资源的使用情况。
|
||||
|
||||
## 疑难解答
|
||||
|
||||
### 我的 Pod 处于 pending 状态且事件信息显示 failedScheduling
|
||||
|
||||
如果调度器找不到任何该 Pod 可以匹配的节点,则该 Pod 将保持不可调度状态,直到找到一个可以被调度到的位置。每当调度器找不到 Pod 可以调度的地方时,会产生一个事件,如下所示:
|
||||
|
||||
```shell
|
||||
$ kubectl describe pod frontend | grep -A 3 Events
|
||||
Events:
|
||||
FirstSeen LastSeen Count From Subobject PathReason Message
|
||||
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
|
||||
```
|
||||
|
||||
在上述示例中,由于节点上的 CPU 资源不足,名为 “frontend” 的 Pod 将无法调度。由于内存不足(PodExceedsFreeMemory),类似的错误消息也可能会导致失败。一般来说,如果有这种类型的消息而处于 pending 状态,您可以尝试如下几件事情:
|
||||
|
||||
```shell
|
||||
$ kubectl describe nodes e2e-test-minion-group-4lw4
|
||||
Name: e2e-test-minion-group-4lw4
|
||||
[ ... lines removed for clarity ...]
|
||||
Capacity:
|
||||
alpha.kubernetes.io/nvidia-gpu: 0
|
||||
cpu: 2
|
||||
memory: 7679792Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
alpha.kubernetes.io/nvidia-gpu: 0
|
||||
cpu: 1800m
|
||||
memory: 7474992Ki
|
||||
pods: 110
|
||||
[ ... lines removed for clarity ...]
|
||||
Non-terminated Pods: (5 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
--------- ---- ------------ ---------- --------------- -------------
|
||||
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
|
||||
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
|
||||
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
|
||||
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
|
||||
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
------------ ---------- --------------- -------------
|
||||
680m (34%) 400m (20%) 920Mi (12%) 1070Mi (14%)
|
||||
```
|
||||
|
||||
在上面的输出中,您可以看到如果 Pod 请求超过 1120m CPU 或者 6.23Gi 内存,节点将无法满足。
|
||||
|
||||
通过查看 `Pods` 部分,您将看到哪些 Pod 占用的节点上的资源。
|
||||
|
||||
Pod 可用的资源量小于节点容量,因为系统守护程序使用一部分可用资源。 [NodeStatus](/docs/resources-reference/{{< param "version" >}}/#nodestatus-v1-core) 的 `allocatable` 字段给出了可用于 Pod 的资源量。有关更多信息,请参阅 [节点可分配资源](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md)。
|
||||
|
||||
可以将 [资源配额](/docs/concepts/policy/resource-quotas/) 功能配置为限制可以使用的资源总量。如果与 namespace 配合一起使用,就可以防止一个团队占用所有资源。
|
||||
|
||||
## 我的容器被终止了
|
||||
|
||||
您的容器可能因为资源枯竭而被终止了。要查看容器是否因为遇到资源限制而被杀死,请在相关的 Pod 上调用 `kubectl describe pod`:
|
||||
|
||||
```shell
|
||||
[12:54:41] $ kubectl describe pod simmemleak-hra99
|
||||
Name: simmemleak-hra99
|
||||
Namespace: default
|
||||
Image(s): saadali/simmemleak
|
||||
Node: kubernetes-node-tf0f/10.240.216.66
|
||||
Labels: name=simmemleak
|
||||
Status: Running
|
||||
Reason:
|
||||
Message:
|
||||
IP: 10.244.2.75
|
||||
Replication Controllers: simmemleak (1/1 replicas created)
|
||||
Containers:
|
||||
simmemleak:
|
||||
Image: saadali/simmemleak
|
||||
Limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
State: Running
|
||||
Started: Tue, 07 Jul 2015 12:54:41 -0700
|
||||
Last Termination State: Terminated
|
||||
Exit Code: 1
|
||||
Started: Fri, 07 Jul 2015 12:54:30 -0700
|
||||
Finished: Fri, 07 Jul 2015 12:54:33 -0700
|
||||
Ready: False
|
||||
Restart Count: 5
|
||||
Conditions:
|
||||
Type Status
|
||||
Ready False
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {scheduler } scheduled Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD pulled Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD created Created with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD started Started with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
|
||||
```
|
||||
|
||||
在上面的例子中,`Restart Count: 5` 意味着 Pod 中的 `simmemleak` 容器被终止并重启了五次。
|
||||
|
||||
您可以使用 `kubectl get pod` 命令加上 `-o go-template=...` 选项来获取之前终止容器的状态。
|
||||
|
||||
```shell
|
||||
[13:59:01] $ kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-60xbc
|
||||
Container Name: simmemleak
|
||||
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
|
||||
```
|
||||
|
||||
您可以看到容器因为 `reason:OOM killed` 被终止,`OOM` 表示 Out Of Memory。
|
||||
|
||||
## 不透明整型资源(Alpha功能)
|
||||
|
||||
Kubernetes 1.5 版本中引入不透明整型资源。不透明的整数资源允许集群运维人员发布新的节点级资源,否则系统将不了解这些资源。
|
||||
|
||||
用户可以在 Pod 的 spec 中消费这些资源,就像 CPU 和内存一样。调度器负责资源计量,以便在不超过可用量的同时分配给 Pod。
|
||||
|
||||
**注意:** 不透明整型资源在 kubernetes 1.5 中还是 Alpha 版本。只实现了资源计量,节点级别的隔离还处于积极的开发阶段。
|
||||
|
||||
不透明整型资源是以 `pod.alpha.kubernetes.io/opaque-int-resource-` 为前缀的资源。API server 将限制这些资源的数量为整数。*有效* 数量的例子有 `3`、`3000m` 和 `3Ki`。*无效*数量的例子有 `0.5` 和 `1500m`。
|
||||
|
||||
申请使用不透明整型资源需要两步。首先,集群运维人员必须在一个或多个节点上通告每个节点不透明的资源。然后,用户必须在 Pod 中请求不透明资源。
|
||||
|
||||
要发布新的不透明整型资源,集群运维人员应向 API server 提交 `PATCH` HTTP请求,以指定集群中节点的`status.capacity` 的可用数量。在此操作之后,节点的 `status.capacity` 将包括一个新的资源。 `status.allocatable` 字段由 kubelet 异步地使用新资源自动更新。请注意,由于调度器在评估 Pod 适应度时使用节点 `status.allocatable` 值,所以在使用新资源修补节点容量和请求在该节点上调度资源的第一个 pod 之间可能会有短暂的延迟。
|
||||
|
||||
**示例**
|
||||
|
||||
这是一个 HTTP 请求,master 节点是 k8s-master,在 k8s-node-1 节点上通告 5 个 “foo” 资源。
|
||||
|
||||
```http
|
||||
PATCH /api/v1/nodes/k8s-node-1/status HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json-patch+json
|
||||
Host: k8s-master:8080
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
curl --header "Content-Type: application/json-patch+json" \
|
||||
--request PATCH \
|
||||
--data '[{"op": "add", "path": "/status/capacity/pod.alpha.kubernetes.io~1opaque-int-resource-foo", "value": "5"}]' \
|
||||
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
|
||||
```
|
||||
|
||||
**注意:** 在前面的请求中,`~1` 是 patch 路径中 `/` 字符的编码。JSON-Patch 中的操作路径值被解释为 JSON-Pointer。更多详细信息请参阅 [IETF RFC 6901, section 3](https://tools.ietf.org/html/rfc6901#section-3)。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: my-container
|
||||
image: myimage
|
||||
resources:
|
||||
requests:
|
||||
cpu: 2
|
||||
pod.alpha.kubernetes.io/opaque-int-resource-foo: 1
|
||||
```
|
||||
|
||||
## 计划改进
|
||||
|
||||
在 kubernetes 1.5 版本中仅允许在容器上指定资源量。计划改进对所有容器在 Pod 中共享资源的计量,如 [emptyDir volume](/docs/concepts/storage/volumes/#emptydir)。
|
||||
|
||||
在 kubernetes 1.5 版本中仅支持容器对 CPU 和内存的申请和限制。计划增加新的资源类型,包括节点磁盘空间资源和一个可支持自定义 [资源类型](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/resources.md) 的框架。
|
||||
|
||||
Kubernetes 通过支持通过多级别的 [服务质量](http://issue.k8s.io/168) 来支持资源的过度使用。
|
||||
|
||||
在 kubernetes 1.5 版本中,一个 CPU 单位在不同的云提供商和同一云提供商的不同机器类型中的意味都不同。例如,在 AWS 上,节点的容量报告为 [ECU](http://aws.amazon.com/ec2/faqs/),而在 GCE 中报告为逻辑内核。我们计划修改 cpu 资源的定义,以便在不同的提供商和平台之间保持一致。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
- 获取将 [CPU 和内存资源分配给容器](/docs/tasks/configure-pod-container/assign-cpu-ram-container/) 的实践经验
|
||||
- [容器](/docs/api-reference/{{< param "version" >}}/#container-v1-core)
|
||||
- [ResourceRequirements](/docs/resources-reference/{{< param "version" >}}/#resourcerequirements-v1-core)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
- [容器](/docs/api-reference/{{< param "version" >}}/#container-v1-core)
|
||||
- [ResourceRequirements](/docs/resources-reference/{{< param "version" >}}/#resourcerequirements-v1-core)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: with-node-affinity
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/e2e-az-name
|
||||
operator: In
|
||||
values:
|
||||
- e2e-az1
|
||||
- e2e-az2
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 1
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: another-node-label-key
|
||||
operator: In
|
||||
values:
|
||||
- another-node-label-value
|
||||
containers:
|
||||
- name: with-node-affinity
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: with-pod-affinity
|
||||
spec:
|
||||
affinity:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: security
|
||||
operator: In
|
||||
values:
|
||||
- S1
|
||||
topologyKey: failure-domain.beta.kubernetes.io/zone
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: security
|
||||
operator: In
|
||||
values:
|
||||
- S2
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: with-pod-affinity
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
nodeSelector:
|
||||
disktype: ssd
|
||||
@@ -0,0 +1,586 @@
|
||||
---
|
||||
approvers:
|
||||
- mikedanese
|
||||
title: Secret
|
||||
---
|
||||
|
||||
`Secret` 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。将这些信息放在 `secret` 中比放在 `pod` 的定义或者 docker 镜像中来说更加安全和灵活。参阅 [Secret 设计文档](https://git.k8s.io/community/contributors/design-proposals/secrets.md) 获取更多详细信息。
|
||||
|
||||
{{< toc >}}
|
||||
## Secret 概览
|
||||
|
||||
Secret 是一种包含少量敏感信息例如密码、token 或 key 的对象。这样的信息可能会被放在 Pod spec 中或者镜像中;将其放在一个 secret 对象中可以更好地控制它的用途,并降低意外暴露的风险。
|
||||
|
||||
用户可以创建 secret,同时系统也创建了一些 secret。
|
||||
|
||||
要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:作为 [volume](/docs/concepts/storage/volumes/) 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。
|
||||
|
||||
### 内置 secret
|
||||
|
||||
#### Service Account 使用 API 凭证自动创建和附加 secret
|
||||
|
||||
Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改您的 pod 以使用此类型的 secret。
|
||||
|
||||
如果需要,可以禁用或覆盖自动创建和使用API凭据。但是,如果您需要的只是安全地访问 apiserver,我们推荐这样的工作流程。
|
||||
|
||||
参阅 [Service Account](/docs/user-guide/service-accounts) 文档获取关于 Service Account 如何工作的更多信息。
|
||||
|
||||
### 创建您自己的 Secret
|
||||
|
||||
#### 使用 kubectl 创建 Secret
|
||||
|
||||
假设有些 pod 需要访问数据库。这些 pod 需要使用的用户名和密码在您本地机器的 `./username.txt` 和 `./password.txt` 文件里。
|
||||
|
||||
```shell
|
||||
# Create files needed for rest of example.
|
||||
$ echo -n "admin" > ./username.txt
|
||||
$ echo -n "1f2d1e2e67df" > ./password.txt
|
||||
```
|
||||
|
||||
`kubectl create secret` 命令将这些文件打包到一个 Secret 中并在 API server 中创建了一个对象。
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
|
||||
secret "db-user-pass" created
|
||||
```
|
||||
|
||||
您可以这样检查刚创建的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA AGE
|
||||
db-user-pass Opaque 2 51s
|
||||
|
||||
$ kubectl describe secrets/db-user-pass
|
||||
Name: db-user-pass
|
||||
Namespace: default
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
|
||||
Type: Opaque
|
||||
|
||||
Data
|
||||
====
|
||||
password.txt: 12 bytes
|
||||
username.txt: 5 bytes
|
||||
```
|
||||
|
||||
请注意,默认情况下,`get` 和 `describe` 命令都不会显示文件的内容。这是为了防止将 secret 中的内容被意外暴露给从终端日志记录中刻意寻找它们的人。
|
||||
|
||||
请参阅 [解码 secret](#decoding-a-secret) 了解如何查看它们的内容。
|
||||
|
||||
#### 手动创建 Secret
|
||||
|
||||
您也可以先以 json 或 yaml 格式在文件中创建一个 secret 对象,然后创建该对象。
|
||||
|
||||
每一项必须是 base64 编码:
|
||||
|
||||
```shell
|
||||
$ echo -n "admin" | base64
|
||||
YWRtaW4=
|
||||
$ echo -n "1f2d1e2e67df" | base64
|
||||
MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
现在可以像这样写一个 secret 对象:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mysecret
|
||||
type: Opaque
|
||||
data:
|
||||
username: YWRtaW4=
|
||||
password: MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
数据字段是一个映射。它的键必须匹配 [`DNS_SUBDOMAIN`](https://git.k8s.io/community/contributors/design-proposals/identifiers.md),前导点也是可以的。这些值可以是任意数据,使用 base64 进行编码。
|
||||
|
||||
使用 [`kubectl create`](/docs/user-guide/kubectl/v1.7/#create) 创建 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./secret.yaml
|
||||
secret "mysecret" created
|
||||
```
|
||||
|
||||
**编码注意:** secret 数据的序列化 JSON 和 YAML 值使用 base64 编码成字符串。换行符在这些字符串中无效,必须省略。当在 Darwin/OS X 上使用 `base64` 实用程序时,用户应避免使用 `-b` 选项来拆分长行。另外,对于 Linux 用户如果 `-w` 选项不可用的话,应该添加选项 `-w 0` 到 `base64` 命令或管道 `base64 | tr -d '\n' ` 。
|
||||
|
||||
#### 解码 Secret
|
||||
|
||||
可以使用 `kubectl get secret` 命令获取 secret。例如,获取在上一节中创建的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl get secret mysecret -o yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
username: YWRtaW4=
|
||||
password: MWYyZDFlMmU2N2Rm
|
||||
kind: Secret
|
||||
metadata:
|
||||
creationTimestamp: 2016-01-22T18:41:56Z
|
||||
name: mysecret
|
||||
namespace: default
|
||||
resourceVersion: "164619"
|
||||
selfLink: /api/v1/namespaces/default/secrets/mysecret
|
||||
uid: cfee02d6-c137-11e5-8d73-42010af00002
|
||||
type: Opaque
|
||||
```
|
||||
|
||||
解码密码字段:
|
||||
|
||||
```shell
|
||||
$ echo "MWYyZDFlMmU2N2Rm" | base64 --decode
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
### 使用 Secret
|
||||
|
||||
Secret 可以作为数据卷被挂载,或作为环境变量暴露出来以供 pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 pod 内。例如,它们可以保存凭据,系统的其他部分应该用它来代表您与外部系统进行交互。
|
||||
|
||||
#### 在 Pod 中使用 Secret 文件
|
||||
|
||||
在 Pod 中的 volume 里使用 Secret:
|
||||
|
||||
1. 创建一个 secret 或者使用已有的 secret。多个 pod 可以引用同一个 secret。
|
||||
2. 修改您的 pod 的定义在 `spec.volumes[]` 下增加一个 volume。可以给这个 volume 随意命名,它的 `spec.volumes[].secret.secretName` 必须等于 secret 对象的名字。
|
||||
3. 将 `spec.containers[].volumeMounts[]` 加到需要用到该 secret 的容器中。指定 `spec.containers[].volumeMounts[].readOnly = true` 和 `spec.containers[].volumeMounts[].mountPath` 为您想要该 secret 出现的尚未使用的目录。
|
||||
4. 修改您的镜像并且/或者命令行让程序从该目录下寻找文件。Secret 的 `data` 映射中的每一个键都成为了 `mountPath` 下的一个文件名。
|
||||
|
||||
这是一个在 pod 中使用 volume 挂在 secret 的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
```
|
||||
|
||||
您想要用的每个 secret 都需要在 `spec.volumes` 中指明。
|
||||
|
||||
如果 pod 中有多个容器,每个容器都需要自己的 `volumeMounts` 配置块,但是每个 secret 只需要一个 `spec.volumes`。
|
||||
|
||||
您可以打包多个文件到一个 secret 中,或者使用的多个 secret,怎样方便就怎样来。
|
||||
|
||||
**向特性路径映射 secret 密钥**
|
||||
|
||||
我们还可以控制 Secret key 映射在 volume 中的路径。您可以使用 `spec.volumes[].secret.items` 字段修改每个 key 的目标路径:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
items:
|
||||
- key: username
|
||||
path: my-group/my-username
|
||||
```
|
||||
|
||||
将会发生什么呢:
|
||||
|
||||
- `username` secret 存储在 `/etc/foo/my-group/my-username` 文件中而不是 `/etc/foo/username` 中。
|
||||
- `password` secret 没有被映射
|
||||
|
||||
如果使用了 `spec.volumes[].secret.items`,只有在 `items` 中指定的 key 被映射。要使用 secret 中所有的 key,所有这些都必须列在 `items` 字段中。所有列出的密钥必须存在于相应的 secret 中。否则,不会创建卷。
|
||||
|
||||
**Secret 文件权限**
|
||||
|
||||
您还可以指定 secret 将拥有的权限模式位文件。如果不指定,默认使用 `0644`。您可以为整个保密卷指定默认模式,如果需要,可以覆盖每个密钥。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
defaultMode: 256
|
||||
```
|
||||
|
||||
然后,secret 将被挂载到 `/etc/foo` 目录,所有通过该 secret volume 挂载创建的文件的权限都是 `0400`。
|
||||
|
||||
请注意,JSON 规范不支持八进制符号,因此使用 256 值作为 0400 权限。如果您使用 yaml 而不是 json 作为 pod,则可以使用八进制符号以更自然的方式指定权限。
|
||||
|
||||
您还可以使用映射,如上一个示例,并为不同的文件指定不同的权限,如下所示:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
items:
|
||||
- key: username
|
||||
path: my-group/my-username
|
||||
mode: 511
|
||||
```
|
||||
|
||||
在这种情况下,导致 `/etc/foo/my-group/my-username` 的文件的权限值为 `0777`。由于 JSON 限制,必须以十进制格式指定模式。
|
||||
|
||||
请注意,如果稍后阅读此权限值可能会以十进制格式显示。
|
||||
|
||||
**从 Volume 中消费 secret 值**
|
||||
|
||||
在挂载的 secret volume 的容器内,secret key 将作为文件,并且 secret 的值使用 base-64 解码并存储在这些文件中。这是在上面的示例容器内执行的命令的结果:
|
||||
|
||||
```shell
|
||||
$ ls /etc/foo/
|
||||
username
|
||||
password
|
||||
$ cat /etc/foo/username
|
||||
admin
|
||||
$ cat /etc/foo/password
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
容器中的程序负责从文件中读取 secret。
|
||||
|
||||
**挂载的 secret 被自动更新**
|
||||
|
||||
当已经在 volume 中被消费的 secret 被更新时,被映射的 key 也将被更新。
|
||||
|
||||
Kubelet 在周期性同步时检查被挂载的 secret 是不是最新的。但是,它正在使用其基于本地 ttl 的缓存来获取当前的 secret 值。结果是,当 secret 被更新的时刻到将新的 secret 映射到 pod 的时刻的总延迟可以与 kubelet 中的secret 缓存的 kubelet sync period + ttl 一样长。
|
||||
|
||||
#### Secret 作为环境变量
|
||||
|
||||
将 secret 作为 pod 中的环境变量使用:
|
||||
|
||||
1. 创建一个 secret 或者使用一个已存在的 secret。多个 pod 可以引用同一个 secret。
|
||||
2. 修改 Pod 定义,为每个要使用 secret 的容器添加对应 secret key 的环境变量。消费secret key 的环境变量应填充 secret 的名称,并键入 `env[x].valueFrom.secretKeyRef`。
|
||||
3. 修改镜像并/或者命令行,以便程序在指定的环境变量中查找值。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: secret-env-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: mycontainer
|
||||
image: redis
|
||||
env:
|
||||
- name: SECRET_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysecret
|
||||
key: username
|
||||
- name: SECRET_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysecret
|
||||
key: password
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
**消费环境变量里的 Secret 值**
|
||||
|
||||
在一个消耗环境变量 secret 的容器中,secret key 作为包含 secret 数据的 base-64 解码值的常规环境变量。这是从上面的示例在容器内执行的命令的结果:
|
||||
|
||||
```shell
|
||||
$ echo $SECRET_USERNAME
|
||||
admin
|
||||
$ echo $SECRET_PASSWORD
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
#### 使用 imagePullSecret
|
||||
|
||||
imagePullSecret 是将包含 Docker(或其他)镜像注册表密码的 secret 传递给 Kubelet 的一种方式,因此可以代表您的 pod 拉取私有镜像。
|
||||
|
||||
**手动指定 imagePullSecret**
|
||||
|
||||
imagePullSecret 的使用在 [镜像文档](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) 中说明。
|
||||
|
||||
### 安排 imagePullSecrets 自动附加
|
||||
|
||||
您可以手动创建 imagePullSecret,并从 serviceAccount 引用它。使用该 serviceAccount 创建的任何 pod 和默认使用该 serviceAccount 的 pod 将会将其的 imagePullSecret 字段设置为服务帐户的 imagePullSecret 字段。有关该过程的详细说明,请参阅 [将 ImagePullSecrets 添加到服务帐户](/docs/tasks/configure-pod-container/configure-service-account/#adding-imagepullsecrets-to-a-service-account)。
|
||||
|
||||
#### 自动挂载手动创建的 Secret
|
||||
|
||||
手动创建的 secret(例如包含用于访问 github 帐户的令牌)可以根据其服务帐户自动附加到 pod。请参阅 [使用 PodPreset 向 Pod 中注入信息](/docs/tasks/run-application/podpreset/) 以获取该进程的详细说明。
|
||||
|
||||
## 详细
|
||||
|
||||
### 限制
|
||||
|
||||
验证 secret volume 来源确保指定的对象引用实际上指向一个类型为 Secret 的对象。因此,需要在依赖于它的任何 pod 之前创建一个 secret。
|
||||
|
||||
Secret API 对象驻留在命名空间中。它们只能由同一命名空间中的 pod 引用。
|
||||
|
||||
每个 secret 的大小限制为1MB。这是为了防止创建非常大的 secret 会耗尽 apiserver 和 kubelet 的内存。然而,创建许多较小的 secret 也可能耗尽内存。更全面得限制 secret 对内存使用的功能还在计划中。
|
||||
|
||||
Kubelet 仅支持从 API server 获取的 Pod 使用 secret。这包括使用 kubectl 创建的任何 pod,或间接通过 replication controller 创建的 pod。它不包括通过 kubelet `--manifest-url` 标志,其 `--config` 标志或其 REST API 创建的pod(这些不是创建 pod 的常用方法)。
|
||||
|
||||
必须先创建 secret,除非将它们标记为可选项,否则必须在将其作为环境变量在 pod 中使用之前创建 secret。对不存在的 secret 的引用将阻止其启动。
|
||||
|
||||
使用 `secretKeyRef` ,引用指定的 secret 中的不存在的 key ,这会阻止 pod 的启动。
|
||||
|
||||
对于通过 `envFrom` 填充环境变量的 secret,这些环境变量具有被认为是无效环境变量名称的 key 将跳过这些键。该 pod 将被允许启动。将会有一个事件,其原因是 `InvalidVariableNames`,该消息将包含被跳过的无效键的列表。该示例显示一个 pod,它指的是包含2个无效键,1badkey 和 2alsobad 的默认/mysecret ConfigMap。
|
||||
|
||||
```shell
|
||||
$ kubectl get events
|
||||
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON
|
||||
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names.
|
||||
```
|
||||
|
||||
### Secret 与 Pod 生命周期的联系
|
||||
|
||||
通过 API 创建 Pod 时,不会检查应用的 secret 是否存在。一旦 Pod 被调度,kubelet 就会尝试获取该 secret 的值。如果获取不到该 secret,或者暂时无法与 API server 建立连接,kubelet 将会定期重试。Kubelet 将会报告关于 pod 的事件,并解释它无法启动的原因。一旦获取到 secret,kubelet将创建并装载一个包含它的卷。在所有 pod 的卷被挂载之前,都不会启动 pod 的容器。
|
||||
|
||||
## 使用案例
|
||||
|
||||
### 使用案例:包含 ssh 密钥的 pod
|
||||
|
||||
创建一个包含 ssh key 的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
|
||||
```
|
||||
|
||||
**安全性注意事项**:发送自己的 ssh 密钥之前要仔细思考:集群的其他用户可能有权访问该密钥。使用您想要共享 Kubernetes 群集的所有用户可以访问的服务帐户,如果它们遭到入侵,可以撤销。
|
||||
|
||||
现在我们可以创建一个使用 ssh 密钥引用 secret 的pod,并在一个卷中使用它:
|
||||
|
||||
```yaml
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: secret-test-pod
|
||||
labels:
|
||||
name: secret-test
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: ssh-key-secret
|
||||
containers:
|
||||
- name: ssh-test-container
|
||||
image: mySshImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
当容器中的命令运行时,密钥的片段将可在以下目录:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/ssh-publickey
|
||||
/etc/secret-volume/ssh-privatekey
|
||||
```
|
||||
|
||||
然后容器可以自由使用密钥数据建立一个 ssh 连接。
|
||||
|
||||
### 使用案例:包含 prod/test 凭据的 pod
|
||||
|
||||
下面的例子说明一个 pod 消费一个包含 prod 凭据的 secret,另一个 pod 使用测试环境凭据消费 secret。
|
||||
|
||||
创建 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
|
||||
secret "prod-db-secret" created
|
||||
$ kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
|
||||
secret "test-db-secret" created
|
||||
```
|
||||
|
||||
创建 pod :
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: prod-db-client-pod
|
||||
labels:
|
||||
name: prod-db-client
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: prod-db-secret
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
- kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: test-db-client-pod
|
||||
labels:
|
||||
name: test-db-client
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: test-db-secret
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
这两个容器将在其文件系统上显示以下文件,其中包含每个容器环境的值:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/username
|
||||
/etc/secret-volume/password
|
||||
```
|
||||
|
||||
请注意,两个 pod 的 spec 配置中仅有一个字段有所不同;这有助于使用普通的 pod 配置模板创建具有不同功能的 pod。您可以使用两个 service account 进一步简化基本 pod spec:一个名为 `prod-user` 拥有 `prod-db-secret` ,另一个称为 `test-user` 拥有 `test-db-secret` 。然后,pod spec 可以缩短为,例如:
|
||||
|
||||
```yaml
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: prod-db-client-pod
|
||||
labels:
|
||||
name: prod-db-client
|
||||
spec:
|
||||
serviceAccount: prod-db-client
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
```
|
||||
|
||||
### 使用案例:Secret 卷中以点号开头的文件
|
||||
|
||||
为了将数据“隐藏”起来(即文件名以点号开头的文件),简单地说让该键以一个点开始。例如,当如下 secret 被挂载到卷中:
|
||||
|
||||
```yaml
|
||||
kind: Secret
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: dotfile-secret
|
||||
data:
|
||||
.secret-file: dmFsdWUtMg0KDQo=
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: secret-dotfiles-pod
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: dotfile-secret
|
||||
containers:
|
||||
- name: dotfile-test-container
|
||||
image: k8s.gcr.io/busybox
|
||||
command:
|
||||
- ls
|
||||
- "-l"
|
||||
- "/etc/secret-volume"
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
`Secret-volume` 将包含一个单独的文件,叫做 `.secret-file`,`dotfile-test-container` 的 `/etc/secret-volume/.secret-file` 路径下将有该文件。
|
||||
|
||||
**注意**
|
||||
|
||||
以点号开头的文件在 `ls -l` 的输出中被隐藏起来了;列出目录内容时,必须使用 `ls -la` 才能查看它们。
|
||||
|
||||
### 使用案例:Secret 仅对 pod 中的一个容器可见
|
||||
|
||||
考虑以下一个需要处理 HTTP 请求的程序,执行一些复杂的业务逻辑,然后使用 HMAC 签署一些消息。因为它具有复杂的应用程序逻辑,所以在服务器中可能会出现一个未被注意的远程文件读取漏洞,这可能会将私钥暴露给攻击者。
|
||||
|
||||
这可以在两个容器中分为两个进程:前端容器,用于处理用户交互和业务逻辑,但无法看到私钥;以及可以看到私钥的签名者容器,并且响应来自前端的简单签名请求(例如通过本地主机网络)。
|
||||
|
||||
使用这种分割方法,攻击者现在必须欺骗应用程序服务器才能进行任意的操作,这可能比使其读取文件更难。
|
||||
|
||||
<!-- TODO: explain how to do this while still using automation. -->
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 客户端使用 Secret API
|
||||
|
||||
当部署与 secret API 交互的应用程序时,应使用诸如 [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) 之类的 [授权策略](https://kubernetes.io/docs/admin/authorization/) 来限制访问。
|
||||
|
||||
Secret 中的值对于不同的环境来说重要性可能不同,例如对于 Kubernetes 集群内部(例如 service account 令牌)和集群外部来说就不一样。即使一个应用程序可以理解其期望的与之交互的 secret 有多大的能力,但是同一命名空间中的其他应用程序却可能不这样认为。
|
||||
|
||||
由于这些原因,在命名空间中 `watch` 和 `list` secret 的请求是非常强大的功能,应该避免这样的行为,因为列出 secret 可以让客户端检查所有 secret 是否在该命名空间中。在群集中`watch` 和 `list` 所有 secret 的能力应该只保留给最有特权的系统级组件。
|
||||
|
||||
需要访问 secrets API 的应用程序应该根据他们需要的 secret 执行 `get` 请求。这允许管理员限制对所有 secret 的访问,同时设置 [白名单访问](https://kubernetes.io/docs/admin/authorization/rbac/#referring-to-resources) 应用程序需要的各个实例。
|
||||
|
||||
为了提高循环获取的性能,客户端可以设计引用 secret 的资源,然后 `watch` 资源,在引用更改时重新请求 secret。此外,还提出了一种 [”批量监控“ API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bulk_watch.md) 来让客户端 `watch` 每个资源,该功能可能会在将来的 Kubernetes 版本中提供。
|
||||
|
||||
## 安全属性
|
||||
|
||||
### 保护
|
||||
|
||||
因为 `secret` 对象可以独立于使用它们的 `pod` 而创建,所以在创建、查看和编辑 pod 的流程中 secret 被暴露的风险较小。系统还可以对 `secret` 对象采取额外的预防措施,例如避免将其写入到磁盘中可能的位置。
|
||||
|
||||
只有当节点上的 pod 需要用到该 secret 时,该 secret 才会被发送到该节点上。它不会被写入磁盘,而是存储在 tmpfs 中。一旦依赖于它的 pod 被删除,它就被删除。
|
||||
|
||||
在大多数 Kubernetes 项目维护的发行版中,用户与 API server 之间的通信以及从 API server 到 kubelet 的通信都受到 SSL/TLS 的保护。通过这些通道传输时,secret 受到保护。
|
||||
|
||||
节点上的 secret 数据存储在 tmpfs 卷中,因此不会传到节点上的其他磁盘。
|
||||
|
||||
同一节点上的很多个 pod 可能拥有多个 secret。但是,只有 pod 请求的 secret 在其容器中才是可见的。因此,一个 pod 不能访问另一个 Pod 的 secret。
|
||||
|
||||
Pod 中有多个容器。但是,pod 中的每个容器必须请求其挂载卷中的 secret 卷才能在容器内可见。这可以用于 [在 Pod 级别构建安全分区](#使用案例secret-仅对-pod-中的一个容器可见)。
|
||||
|
||||
### 风险
|
||||
|
||||
- API server 的 secret 数据以纯文本的方式存储在 etcd 中,因此:
|
||||
- 管理员应该限制 admin 用户访问 etcd;
|
||||
- API server 中的 secret 数据位于 etcd 使用的磁盘上;管理员可能希望在不再使用时擦除/粉碎 etcd 使用的磁盘
|
||||
- 如果您将 secret 数据编码为 base64 的清单(JSON 或 YAML)文件,共享该文件或将其检入代码库,这样的话该密码将会被泄露。 Base64 编码不是一种加密方式,一样也是纯文本。
|
||||
- 应用程序在从卷中读取 secret 后仍然需要保护 secret 的值,例如不会意外记录或发送给不信任方。
|
||||
- 可以创建和使用 secret 的 pod 的用户也可以看到该 secret 的值。即使 API server 策略不允许用户读取 secret 对象,用户也可以运行暴露 secret 的 pod。
|
||||
- 如果运行了多个副本,那么这些 secret 将在它们之间共享。默认情况下,etcd 不能保证与 SSL/TLS 的对等通信,尽管可以进行配置。
|
||||
- 目前,任何节点的 root 用户都可以通过模拟 kubelet 来读取 API server 中的任何 secret。只有向实际需要它们的节点发送 secret 才能限制单个节点的根漏洞的影响,该功能还在计划中。
|
||||
@@ -0,0 +1,464 @@
|
||||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- kevin-wangzefeng
|
||||
- bsalamat
|
||||
cn-approvers:
|
||||
- linyouchong
|
||||
title: Taint 和 Toleration
|
||||
content_template: templates/concept
|
||||
weight: 40
|
||||
---
|
||||
|
||||
<!--
|
||||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- kevin-wangzefeng
|
||||
- bsalamat
|
||||
title: Taints and Tolerations
|
||||
content_template: templates/concept
|
||||
weight: 40
|
||||
---
|
||||
-->
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
{{% capture overview %}}
|
||||
<!--
|
||||
Node affinity, described [here](/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature),
|
||||
is a property of *pods* that *attracts* them to a set of nodes (either as a
|
||||
preference or a hard requirement). Taints are the opposite -- they allow a
|
||||
*node* to *repel* a set of pods.
|
||||
-->
|
||||
节点亲和性(详见[这里](/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature)),是 *pod* 的一种属性(偏好或硬性要求),它使 *pod* 被吸引到一类特定的节点。Taint 则相反,它使 *节点* 能够 *排斥* 一类特定的 pod。
|
||||
|
||||
<!--
|
||||
Taints and tolerations work together to ensure that pods are not scheduled
|
||||
onto inappropriate nodes. One or more taints are applied to a node; this
|
||||
marks that the node should not accept any pods that do not tolerate the taints.
|
||||
Tolerations are applied to pods, and allow (but do not require) the pods to schedule
|
||||
onto nodes with matching taints.
|
||||
-->
|
||||
Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
<!--
|
||||
|
||||
## Concepts
|
||||
|
||||
-->
|
||||
|
||||
## 概念
|
||||
|
||||
<!--
|
||||
You add a taint to a node using [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint).
|
||||
For example,
|
||||
-->
|
||||
您可以使用命令 [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint) 给节点增加一个 taint。比如,
|
||||
|
||||
```shell
|
||||
kubectl taint nodes node1 key=value:NoSchedule
|
||||
```
|
||||
|
||||
<!--
|
||||
places a taint on node `node1`. The taint has key `key`, value `value`, and taint effect `NoSchedule`.
|
||||
This means that no pod will be able to schedule onto `node1` unless it has a matching toleration.
|
||||
You specify a toleration for a pod in the PodSpec. Both of the following tolerations "match" the
|
||||
taint created by the `kubectl taint` line above, and thus a pod with either toleration would be able
|
||||
to schedule onto `node1`:
|
||||
-->
|
||||
给节点 `node1` 增加一个 taint,它的 key 是 `key`,value 是 `value`,effect 是 `NoSchedule`。这表示只有拥有和这个 taint 相匹配的 toleration 的 pod 才能够被分配到 `node1` 这个节点。您可以在 PodSpec 中定义 pod 的 toleration。下面两个 toleration 均与上面例子中使用 `kubectl taint` 命令创建的 taint 相匹配,因此如果一个 pod 拥有其中的任何一个 toleration 都能够被分配到 `node1` :
|
||||
|
||||
<!--
|
||||
To remove the taint added by the command above, you can run:
|
||||
-->
|
||||
想删除上述命令添加的 taint ,您可以运行:
|
||||
```shell
|
||||
kubectl taint nodes kube11 key:NoSchedule-
|
||||
```
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key"
|
||||
operator: "Equal"
|
||||
value: "value"
|
||||
effect: "NoSchedule"
|
||||
```
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key"
|
||||
operator: "Exists"
|
||||
effect: "NoSchedule"
|
||||
```
|
||||
|
||||
<!--
|
||||
A toleration "matches" a taint if the keys are the same and the effects are the same, and:
|
||||
|
||||
* the `operator` is `Exists` (in which case no `value` should be specified), or
|
||||
* the `operator` is `Equal` and the `value`s are equal
|
||||
|
||||
`Operator` defaults to `Equal` if not specified.
|
||||
-->
|
||||
一个 toleration 和一个 taint 相“匹配”是指它们有一样的 key 和 effect ,并且:
|
||||
|
||||
* 如果 `operator` 是 `Exists` (此时 toleration 不能指定 `value`),或者
|
||||
* 如果 `operator` 是 `Equal` ,则它们的 `value` 应该相等
|
||||
|
||||
{{< note >}}
|
||||
<!--
|
||||
**Note:** There are two special cases:
|
||||
|
||||
* An empty `key` with operator `Exists` matches all keys, values and effects which means this
|
||||
will tolerate everything.
|
||||
-->
|
||||
|
||||
**注意:** 存在两种特殊情况:
|
||||
|
||||
* 如果一个 toleration 的 `key` 为空且 operator 为 `Exists` ,表示这个 toleration 与任意的 key 、 value 和 effect 都匹配,即这个 toleration 能容忍任意 taint。
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- operator: "Exists"
|
||||
```
|
||||
|
||||
<!--
|
||||
|
||||
* An empty `effect` matches all effects with key `key`.
|
||||
-->
|
||||
* 如果一个 toleration 的 `effect` 为空,则 `key` 值与之相同的相匹配 taint 的 `effect` 可以是任意值。
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key"
|
||||
operator: "Exists"
|
||||
```
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
The above example used `effect` of `NoSchedule`. Alternatively, you can use `effect` of `PreferNoSchedule`.
|
||||
This is a "preference" or "soft" version of `NoSchedule` -- the system will *try* to avoid placing a
|
||||
pod that does not tolerate the taint on the node, but it is not required. The third kind of `effect` is
|
||||
`NoExecute`, described later.
|
||||
-->
|
||||
上述例子使用到的 `effect` 的一个值 `NoSchedule`,您也可以使用另外一个值 `PreferNoSchedule`。这是“优化”或“软”版本的 `NoSchedule` ——系统会*尽量*避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。`effect` 的值还可以设置为 `NoExecute` ,下文会详细描述这个值。
|
||||
|
||||
<!--
|
||||
You can put multiple taints on the same node and multiple tolerations on the same pod.
|
||||
The way Kubernetes processes multiple taints and tolerations is like a filter: start
|
||||
with all of a node's taints, then ignore the ones for which the pod has a matching toleration; the
|
||||
remaining un-ignored taints have the indicated effects on the pod. In particular,
|
||||
-->
|
||||
您可以给一个节点添加多个 taint ,也可以给一个 pod 添加多个 toleration。Kubernetes 处理多个 taint 和 toleration 的过程就像一个过滤器:从一个节点的所有 taint 开始遍历,过滤掉那些 pod 中存在与之相匹配的 toleration 的 taint。余下未被过滤的 taint 的 effect 值决定了 pod 是否会被分配到该节点,特别是以下情况:
|
||||
|
||||
<!--
|
||||
|
||||
* if there is at least one un-ignored taint with effect `NoSchedule` then Kubernetes will not schedule
|
||||
the pod onto that node
|
||||
* if there is no un-ignored taint with effect `NoSchedule` but there is at least one un-ignored taint with
|
||||
effect `PreferNoSchedule` then Kubernetes will *try* to not schedule the pod onto the node
|
||||
* if there is at least one un-ignored taint with effect `NoExecute` then the pod will be evicted from
|
||||
the node (if it is already running on the node), and will not be
|
||||
scheduled onto the node (if it is not yet running on the node).
|
||||
-->
|
||||
* 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoSchedule` 的 taint,则 Kubernetes 不会将 pod 分配到该节点。
|
||||
* 如果未被过滤的 taint 中不存在 effect 值为 `NoSchedule` 的 taint,但是存在 effect 值为 `PreferNoSchedule` 的 taint,则 Kubernetes 会*尝试*将 pod 分配到该节点。
|
||||
* 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoExecute` 的 taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)。
|
||||
|
||||
<!--
|
||||
For example, imagine you taint a node like this
|
||||
-->
|
||||
例如,假设您给一个节点添加了如下的 taint
|
||||
|
||||
```shell
|
||||
kubectl taint nodes node1 key1=value1:NoSchedule
|
||||
kubectl taint nodes node1 key1=value1:NoExecute
|
||||
kubectl taint nodes node1 key2=value2:NoSchedule
|
||||
```
|
||||
|
||||
<!--
|
||||
And a pod has two tolerations:
|
||||
-->
|
||||
然后存在一个 pod,它有两个 toleration
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key1"
|
||||
operator: "Equal"
|
||||
value: "value1"
|
||||
effect: "NoSchedule"
|
||||
- key: "key1"
|
||||
operator: "Equal"
|
||||
value: "value1"
|
||||
effect: "NoExecute"
|
||||
```
|
||||
|
||||
<!--
|
||||
In this case, the pod will not be able to schedule onto the node, because there is no
|
||||
toleration matching the third taint. But it will be able to continue running if it is
|
||||
already running on the node when the taint is added, because the third taint is the only
|
||||
one of the three that is not tolerated by the pod.
|
||||
-->
|
||||
在这个例子中,上述 pod 不会被分配到上述节点,因为其没有 toleration 和第三个 taint 相匹配。但是如果在给节点添加 上述 taint 之前,该 pod 已经在上述节点运行,那么它还可以继续运行在该节点上,因为第三个 taint 是三个 taint 中唯一不能被这个 pod 容忍的。
|
||||
|
||||
<!--
|
||||
Normally, if a taint with effect `NoExecute` is added to a node, then any pods that do
|
||||
not tolerate the taint will be evicted immediately, and any pods that do tolerate the
|
||||
taint will never be evicted. However, a toleration with `NoExecute` effect can specify
|
||||
an optional `tolerationSeconds` field that dictates how long the pod will stay bound
|
||||
to the node after the taint is added. For example,
|
||||
-->
|
||||
通常情况下,如果给一个节点添加了一个 effect 值为 `NoExecute` 的 taint,则任何不能忍受这个 taint 的 pod 都会马上被驱逐,任何可以忍受这个 taint 的 pod 都不会被驱逐。但是,如果 pod 存在一个 effect 值为 `NoExecute` 的 toleration 指定了可选属性 `tolerationSeconds` 的值,则表示在给节点添加了上述 taint 之后,pod 还能继续在节点上运行的时间。例如,
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key1"
|
||||
operator: "Equal"
|
||||
value: "value1"
|
||||
effect: "NoExecute"
|
||||
tolerationSeconds: 3600
|
||||
```
|
||||
|
||||
<!--
|
||||
means that if this pod is running and a matching taint is added to the node, then
|
||||
the pod will stay bound to the node for 3600 seconds, and then be evicted. If the
|
||||
taint is removed before that time, the pod will not be evicted.
|
||||
-->
|
||||
这表示如果这个 pod 正在运行,然后一个匹配的 taint 被添加到其所在的节点,那么 pod 还将继续在节点上运行 3600 秒,然后被驱逐。如果在此之前上述 taint 被删除了,则 pod 不会被驱逐。
|
||||
|
||||
<!--
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
-->
|
||||
|
||||
## 使用例子
|
||||
|
||||
<!--
|
||||
Taints and tolerations are a flexible way to steer pods *away* from nodes or evict
|
||||
pods that shouldn't be running. A few of the use cases are
|
||||
-->
|
||||
通过 taint 和 toleration ,可以灵活地让 pod *避开*某些节点或者将 pod 从某些节点驱逐。下面是几个使用例子:
|
||||
|
||||
<!--
|
||||
|
||||
* **Dedicated Nodes**: If you want to dedicate a set of nodes for exclusive use by
|
||||
a particular set of users, you can add a taint to those nodes (say,
|
||||
`kubectl taint nodes nodename dedicated=groupName:NoSchedule`) and then add a corresponding
|
||||
toleration to their pods (this would be done most easily by writing a custom
|
||||
[admission controller](/docs/reference/access-authn-authz/admission-controllers/)).
|
||||
The pods with the tolerations will then be allowed to use the tainted (dedicated) nodes as
|
||||
well as any other nodes in the cluster. If you want to dedicate the nodes to them *and*
|
||||
ensure they *only* use the dedicated nodes, then you should additionally add a label similar
|
||||
to the taint to the same set of nodes (e.g. `dedicated=groupName`), and the admission
|
||||
controller should additionally add a node affinity to require that the pods can only schedule
|
||||
onto nodes labeled with `dedicated=groupName`.
|
||||
-->
|
||||
* **专用节点**:如果您想将某些节点专门分配给特定的一组用户使用,您可以给这些节点添加一个 taint(即,
|
||||
`kubectl taint nodes nodename dedicated=groupName:NoSchedule`),然后给这组用户的 pod 添加一个相对应的 toleration(通过编写一个自定义的[admission controller](/docs/admin/admission-controllers/),很容易就能做到)。拥有上述 toleration 的 pod 就能够被分配到上述专用节点,同时也能够被分配到集群中的其它节点。如果您希望这些 pod 只能被分配到上述专用节点,那么您还需要给这些专用节点另外添加一个和上述 taint 类似的 label (例如:`dedicated=groupName`),同时 还要在上述 admission controller 中给 pod 增加节点亲和性要求上述 pod 只能被分配到添加了 `dedicated=groupName` 标签的节点上。
|
||||
|
||||
<!--
|
||||
|
||||
* **Nodes with Special Hardware**: In a cluster where a small subset of nodes have specialized
|
||||
hardware (for example GPUs), it is desirable to keep pods that don't need the specialized
|
||||
hardware off of those nodes, thus leaving room for later-arriving pods that do need the
|
||||
specialized hardware. This can be done by tainting the nodes that have the specialized
|
||||
hardware (e.g. `kubectl taint nodes nodename special=true:NoSchedule` or
|
||||
`kubectl taint nodes nodename special=true:PreferNoSchedule`) and adding a corresponding
|
||||
toleration to pods that use the special hardware. As in the dedicated nodes use case,
|
||||
it is probably easiest to apply the tolerations using a custom
|
||||
[admission controller](/docs/eference/access-authn-authz/admission-controllers/)).
|
||||
For example, it is recommended to use [Extended
|
||||
Resources](/docs/concepts/configuration/manage-compute-resources-container/#extended-resources)
|
||||
to represent the special hardware, taint your special hardware nodes with the
|
||||
extended resource name and run the
|
||||
[ExtendedResourceToleration](/docs/reference/access-authn-authz/admission-controllers/#extendedresourcetoleration)
|
||||
admission controller. Now, because the nodes are tainted, no pods without the
|
||||
toleration will schedule on them. But when you submit a pod that requests the
|
||||
extended resource, the `ExtendedResourceToleration` admission controller will
|
||||
automatically add the correct toleration to the pod and that pod will schedule
|
||||
on the special hardware nodes. This will make sure that these special hardware
|
||||
nodes are dedicated for pods requesting such hardware and you don't have to
|
||||
manually add tolerations to your pods.
|
||||
-->
|
||||
* **配备了特殊硬件的节点**:在部分节点配备了特殊硬件(比如 GPU)的集群中,我们希望不需要这类硬件的 pod 不要被分配到这些特殊节点,以便为后继需要这类硬件的 pod 保留资源。要达到这个目的,可以先给配备了特殊硬件的节点添加 taint(例如 `kubectl taint nodes nodename special=true:NoSchedule` or `kubectl taint nodes nodename special=true:PreferNoSchedule`),然后给使用了这类特殊硬件的 pod 添加一个相匹配的 toleration。和专用节点的例子类似,添加这个 toleration 的最简单的方法是使用自定义 [admission controller](/docs/reference/access-authn-authz/admission-controllers/)。比如,我们推荐使用 [Extended Resources](/docs/concepts/configuration/manage-compute-resources-container/#extended-resources) 来表示特殊硬件,给配置了特殊硬件的节点添加 taint 时包含 extended resource 名称,然后运行一个 [ExtendedResourceToleration](/docs/reference/access-authn-authz/admission-controllers/#extendedresourcetoleration) admission controller。此时,因为节点已经被 taint 了,没有对应 toleration 的 Pod 会被调度到这些节点。但当你创建一个使用了 extended resource 的 Pod 时,`ExtendedResourceToleration` admission controller 会自动给 Pod 加上正确的 toleration ,这样 Pod 就会被自动调度到这些配置了特殊硬件件的节点上。这样就能够确保这些配置了特殊硬件的节点专门用于运行 需要使用这些硬件的 Pod,并且您无需手动给这些 Pod 添加 toleration。
|
||||
|
||||
<!--
|
||||
|
||||
* **Taint based Evictions (alpha feature)**: A per-pod-configurable eviction behavior
|
||||
when there are node problems, which is described in the next section.
|
||||
-->
|
||||
* **基于 taint 的驱逐 (alpha 特性)**: 这是在每个 pod 中配置的在节点出现问题时的驱逐行为,接下来的章节会描述这个特性
|
||||
|
||||
<!--
|
||||
|
||||
## Taint based Evictions
|
||||
|
||||
-->
|
||||
|
||||
## 基于 taint 的驱逐
|
||||
|
||||
<!--
|
||||
Earlier we mentioned the `NoExecute` taint effect, which affects pods that are already
|
||||
running on the node as follows
|
||||
|
||||
* pods that do not tolerate the taint are evicted immediately
|
||||
* pods that tolerate the taint without specifying `tolerationSeconds` in
|
||||
their toleration specification remain bound forever
|
||||
* pods that tolerate the taint with a specified `tolerationSeconds` remain
|
||||
bound for the specified amount of time
|
||||
-->
|
||||
前文我们提到过 taint 的 effect 值 `NoExecute` ,它会影响已经在节点上运行的 pod
|
||||
* 如果 pod 不能忍受effect 值为 `NoExecute` 的 taint,那么 pod 将马上被驱逐
|
||||
* 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,但是在 toleration 定义中没有指定 `tolerationSeconds`,则 pod 还会一直在这个节点上运行。
|
||||
* 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,而且指定了 `tolerationSeconds`,则 pod 还能在这个节点上继续运行这个指定的时间长度。
|
||||
|
||||
<!--
|
||||
In addition, Kubernetes 1.6 introduced alpha support for representing node
|
||||
problems. In other words, the node controller automatically taints a node when
|
||||
certain condition is true. The following taints are built in:
|
||||
|
||||
* `node.kubernetes.io/not-ready`: Node is not ready. This corresponds to
|
||||
the NodeCondition `Ready` being "`False`".
|
||||
* `node.kubernetes.io/unreachable`: Node is unreachable from the node
|
||||
controller. This corresponds to the NodeCondition `Ready` being "`Unknown`".
|
||||
* `node.kubernetes.io/out-of-disk`: Node becomes out of disk.
|
||||
* `node.kubernetes.io/memory-pressure`: Node has memory pressure.
|
||||
* `node.kubernetes.io/disk-pressure`: Node has disk pressure.
|
||||
* `node.kubernetes.io/network-unavailable`: Node's network is unavailable.
|
||||
* `node.kubernetes.io/unschedulable`: Node is unschedulable.
|
||||
* `node.cloudprovider.kubernetes.io/uninitialized`: When the kubelet is started
|
||||
with "external" cloud provider, this taint is set on a node to mark it
|
||||
as unusable. After a controller from the cloud-controller-manager initializes
|
||||
this node, the kubelet removes this taint.
|
||||
-->
|
||||
此外,Kubernetes 1.6 已经支持(alpha阶段)节点问题的表示。换句话说,当某种条件为真时,node controller会自动给节点添加一个 taint。当前内置的 taint 包括:
|
||||
* `node.kubernetes.io/not-ready`:节点未准备好。这相当于节点状态 `Ready` 的值为 "`False`"。
|
||||
* `node.kubernetes.io/unreachable`:node controller 访问不到节点. 这相当于节点状态 `Ready` 的值为 "`Unknown`"。
|
||||
* `node.kubernetes.io/out-of-disk`:节点磁盘耗尽。
|
||||
* `node.kubernetes.io/memory-pressure`:节点存在内存压力。
|
||||
* `node.kubernetes.io/disk-pressure`:节点存在磁盘压力。
|
||||
* `node.kubernetes.io/network-unavailable`:节点网络不可用。
|
||||
* `node.kubernetes.io/unschedulable`: 节点不可调度。
|
||||
* `node.cloudprovider.kubernetes.io/uninitialized`:如果 kubelet 启动时指定了一个 "外部" cloud provider,它将给当前节点添加一个 taint 将其标志为不可用。在 cloud-controller-manager 的一个 controller 初始化这个节点后,kubelet 将删除这个 taint。
|
||||
|
||||
<!--
|
||||
When the `TaintBasedEvictions` alpha feature is enabled (you can do this by
|
||||
including `TaintBasedEvictions=true` in `--feature-gates` for Kubernetes controller manager,
|
||||
such as `--feature-gates=FooBar=true,TaintBasedEvictions=true`), the taints are automatically
|
||||
added by the NodeController (or kubelet) and the normal logic for evicting pods from nodes
|
||||
based on the Ready NodeCondition is disabled.
|
||||
-->
|
||||
在启用了 `TaintBasedEvictions` 这个 alpha 功能特性后(在 Kubernetes controller manager 的 `--feature-gates` 参数中包含`TaintBasedEvictions=true` 开启这个功能特性,例如:`--feature-gates=FooBar=true,TaintBasedEvictions=true`),NodeController (或 kubelet)会自动给节点添加这类 taint,上述基于节点状态 Ready 对 pod 进行驱逐的逻辑会被禁用。
|
||||
|
||||
{{< note >}}
|
||||
<!--
|
||||
**Note:** To maintain the existing [rate limiting](/docs/concepts/architecture/nodes/)
|
||||
behavior of pod evictions due to node problems, the system actually adds the taints
|
||||
in a rate-limited way. This prevents massive pod evictions in scenarios such
|
||||
as the master becoming partitioned from the nodes.
|
||||
-->
|
||||
注意:为了保证由于节点问题引起的 pod 驱逐[rate limiting](/docs/concepts/architecture/nodes/)行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master 和 node 通讯中断等场景下,这避免了 pod 被大量驱逐。
|
||||
{{< /note >}}
|
||||
|
||||
<!--
|
||||
This alpha feature, in combination with `tolerationSeconds`, allows a pod
|
||||
to specify how long it should stay bound to a node that has one or both of these problems.
|
||||
-->
|
||||
使用这个 alpha 功能特性,结合 `tolerationSeconds` ,pod 就可以指定当节点出现一个或全部上述问题时还将在这个节点上运行多长的时间。
|
||||
|
||||
<!--
|
||||
For example, an application with a lot of local state might want to stay
|
||||
bound to node for a long time in the event of network partition, in the hope
|
||||
that the partition will recover and thus the pod eviction can be avoided.
|
||||
The toleration the pod would use in that case would look like
|
||||
-->
|
||||
比如,一个使用了很多本地状态的应用程序在网络断开时,仍然希望停留在当前节点上运行一段较长的时间,愿意等待网络恢复以避免被驱逐。在这种情况下,pod 的 toleration 可能是下面这样的:
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "node.alpha.kubernetes.io/unreachable"
|
||||
operator: "Exists"
|
||||
effect: "NoExecute"
|
||||
tolerationSeconds: 6000
|
||||
```
|
||||
|
||||
<!--
|
||||
Note that Kubernetes automatically adds a toleration for
|
||||
`node.kubernetes.io/not-ready` with `tolerationSeconds=300`
|
||||
unless the pod configuration provided
|
||||
by the user already has a toleration for `node.kubernetes.io/not-ready`.
|
||||
Likewise it adds a toleration for
|
||||
`node.alpha.kubernetes.io/unreachable` with `tolerationSeconds=300`
|
||||
unless the pod configuration provided
|
||||
by the user already has a toleration for `node.alpha.kubernetes.io/unreachable`.
|
||||
-->
|
||||
注意,Kubernetes 会自动给 pod 添加一个 key 为 `node.kubernetes.io/not-ready` 的 toleration 并配置 `tolerationSeconds=300`,除非用户提供的 pod 配置中已经已存在了 key 为 `node.kubernetes.io/not-ready` 的 toleration。同样,Kubernetes 会给 pod 添加一个 key 为 `node.kubernetes.io/unreachable` 的 toleration 并配置 `tolerationSeconds=300`,除非用户提供的 pod 配置中已经已存在了 key 为 `node.kubernetes.io/unreachable` 的 toleration。
|
||||
|
||||
<!--
|
||||
These automatically-added tolerations ensure that
|
||||
the default pod behavior of remaining bound for 5 minutes after one of these
|
||||
problems is detected is maintained.
|
||||
The two default tolerations are added by the [DefaultTolerationSeconds
|
||||
admission controller](https://git.k8s.io/kubernetes/plugin/pkg/admission/defaulttolerationseconds).
|
||||
-->
|
||||
这种自动添加 toleration 机制保证了在其中一种问题被检测到时 pod 默认能够继续停留在当前节点运行 5 分钟。这两个默认 toleration 是由 [DefaultTolerationSeconds
|
||||
admission controller](https://git.k8s.io/kubernetes/plugin/pkg/admission/defaulttolerationseconds)添加的。
|
||||
|
||||
<!--
|
||||
[DaemonSet](/docs/concepts/workloads/controllers/daemonset/) pods are created with
|
||||
`NoExecute` tolerations for the following taints with no `tolerationSeconds`:
|
||||
|
||||
* `node.alpha.kubernetes.io/unreachable`
|
||||
* `node.kubernetes.io/not-ready`
|
||||
|
||||
This ensures that DaemonSet pods are never evicted due to these problems,
|
||||
which matches the behavior when this feature is disabled.
|
||||
-->
|
||||
[DaemonSet](/docs/concepts/workloads/controllers/daemonset/) 中的 pod 被创建时,针对以下 taint 自动添加的 `NoExecute` 的 toleration 将不会指定 `tolerationSeconds`:
|
||||
|
||||
* `node.alpha.kubernetes.io/unreachable`
|
||||
* `node.kubernetes.io/not-ready`
|
||||
|
||||
这保证了出现上述问题时 DaemonSet 中的 pod 永远不会被驱逐,这和 `TaintBasedEvictions` 这个特性被禁用后的行为是一样的。
|
||||
|
||||
<!--
|
||||
|
||||
## Taint Nodes by Condition
|
||||
|
||||
-->
|
||||
|
||||
## 基于节点状态添加 taint
|
||||
|
||||
<!--
|
||||
Version 1.8 introduces an alpha feature that causes the node controller to create taints corresponding to
|
||||
Node conditions. When this feature is enabled (you can do this by including `TaintNodesByCondition=true` in the `--feature-gates` command line flag to the scheduler, such as
|
||||
`--feature-gates=FooBar=true,TaintNodesByCondition=true`), the scheduler does not check Node conditions; instead the scheduler checks taints. This assures that Node conditions don't affect what's scheduled onto the Node. The user can choose to ignore some of the Node's problems (represented as Node conditions) by adding appropriate Pod tolerations.
|
||||
|
||||
Starting in Kubernetes 1.8, the DaemonSet controller automatically adds the
|
||||
following `NoSchedule` tolerations to all daemons, to prevent DaemonSets from
|
||||
breaking.
|
||||
|
||||
* `node.kubernetes.io/memory-pressure`
|
||||
* `node.kubernetes.io/disk-pressure`
|
||||
* `node.kubernetes.io/out-of-disk` (*only for critical pods*)
|
||||
* `node.kubernetes.io/unschedulable` (1.10 or later)
|
||||
* `node.kubernetes.io/network-unavailable` (*host network only*)
|
||||
-->
|
||||
1.8 版本引入了一个 alpha 特性,让 node controller 根据节点的状态创建 taint。当开启了这个特性时(通过给 scheduler 的 `--feature-gates` 添加 `TaintNodesByCondition=true` 参数,例如:`--feature-gates=FooBar=true,TaintNodesByCondition=true`),scheduler不会去检查节点的状态,而是检查节点的 taint。这确保了节点的状态不影响应该调度哪些 Pod 到节点上。用户可以通过给 Pod 添加 toleration 来选择忽略节点的一些问题(节点状态的形式表示)。
|
||||
从 Kubernetes 1.8 开始,DaemonSet controller 会自动添加如下 `NoSchedule` toleration,以防止 DaemonSet 中断。
|
||||
* `node.kubernetes.io/memory-pressure`
|
||||
* `node.kubernetes.io/disk-pressure`
|
||||
* `node.kubernetes.io/out-of-disk` (*只适合 critical pod*)
|
||||
* `node.kubernetes.io/unschedulable` (1.10 或更高版本)
|
||||
* `node.kubernetes.io/network-unavailable` (*只适合 host network*)
|
||||
|
||||
<!--
|
||||
Adding these tolerations ensures backward compatibility. You can also add
|
||||
arbitrary tolerations to DaemonSets.
|
||||
-->
|
||||
添加上述 toleration 确保了向后兼容,您也可以选择自由的向 DaemonSet 添加 toleration。
|
||||
Reference in New Issue
Block a user