Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
+5
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Configuration"
|
||||
weight: 70
|
||||
---
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
- kevin-wangzefeng
|
||||
- bsalamat
|
||||
title: Assigning Pods to Nodes
|
||||
---
|
||||
|
||||
You can constrain a [pod](/docs/concepts/workloads/pods/pod/) to only be able to run on particular [nodes](/docs/concepts/architecture/nodes/) or to prefer to
|
||||
run on particular nodes. There are several ways to do this, and they all use
|
||||
[label selectors](/docs/concepts/overview/working-with-objects/labels/) to make the selection.
|
||||
Generally such constraints are unnecessary, as the scheduler will automatically do a reasonable placement
|
||||
(e.g. spread your pods across nodes, not place the pod on a node with insufficient free resources, etc.)
|
||||
but there are some circumstances where you may want more control on a node where a pod lands, e.g. to ensure
|
||||
that a pod ends up on a machine with an SSD attached to it, or to co-locate pods from two different
|
||||
services that communicate a lot into the same availability zone.
|
||||
|
||||
You can find all the files for these examples [in our docs
|
||||
repo here](https://github.com/kubernetes/website/tree/{{< param "docsbranch" >}}/docs/user-guide/node-selection).
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## nodeSelector
|
||||
|
||||
`nodeSelector` is the simplest form of constraint.
|
||||
`nodeSelector` is a field of PodSpec. It specifies a map of key-value pairs. For the pod to be eligible
|
||||
to run on a node, the node must have each of the indicated key-value pairs as labels (it can have
|
||||
additional labels as well). The most common usage is one key-value pair.
|
||||
|
||||
Let's walk through an example of how to use `nodeSelector`.
|
||||
|
||||
### Step Zero: Prerequisites
|
||||
|
||||
This example assumes that you have a basic understanding of Kubernetes pods and that you have [turned up a Kubernetes cluster](https://github.com/kubernetes/kubernetes#documentation).
|
||||
|
||||
### Step One: Attach label to the node
|
||||
|
||||
Run `kubectl get nodes` to get the names of your cluster's nodes. Pick out the one that you want to add a label to, and then run `kubectl label nodes <node-name> <label-key>=<label-value>` to add a label to the node you've chosen. For example, if my node name is 'kubernetes-foo-node-1.c.a-robinson.internal' and my desired label is 'disktype=ssd', then I can run `kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd`.
|
||||
|
||||
If this fails with an "invalid command" error, you're likely using an older version of kubectl that doesn't have the `label` command. In that case, see the [previous version](https://github.com/kubernetes/kubernetes/blob/a053dbc313572ed60d89dae9821ecab8bfd676dc/examples/node-selection/README.md) of this guide for instructions on how to manually set labels on a node.
|
||||
|
||||
You can verify that it worked by re-running `kubectl get nodes --show-labels` and checking that the node now has a label.
|
||||
|
||||
### Step Two: Add a nodeSelector field to your pod configuration
|
||||
|
||||
Take whatever pod config file you want to run, and add a nodeSelector section to it, like this. For example, if this is my pod config:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
```
|
||||
|
||||
Then add a nodeSelector like so:
|
||||
|
||||
{{< code file="pod.yaml" >}}
|
||||
|
||||
When you then run `kubectl create -f pod.yaml`, the pod will get scheduled on the node that you attached the label to! You can verify that it worked by running `kubectl get pods -o wide` and looking at the "NODE" that the pod was assigned to.
|
||||
|
||||
## Interlude: built-in node labels
|
||||
|
||||
In addition to labels you [attach](#step-one-attach-label-to-the-node), nodes come pre-populated
|
||||
with a standard set of labels. As of Kubernetes v1.4 these labels are
|
||||
|
||||
* `kubernetes.io/hostname`
|
||||
* `failure-domain.beta.kubernetes.io/zone`
|
||||
* `failure-domain.beta.kubernetes.io/region`
|
||||
* `beta.kubernetes.io/instance-type`
|
||||
* `beta.kubernetes.io/os`
|
||||
* `beta.kubernetes.io/arch`
|
||||
|
||||
{{< note >}}
|
||||
**Note:** The value of these labels is cloud provider specific and is not guaranteed to be reliable.
|
||||
For example, the value of `kubernetes.io/hostname` may be the same as the Node name in some environments
|
||||
and a different value in other environments.
|
||||
{{< /note >}}
|
||||
|
||||
## Affinity and anti-affinity
|
||||
|
||||
`nodeSelector` provides a very simple way to constrain pods to nodes with particular labels. The affinity/anti-affinity
|
||||
feature, currently in beta, greatly expands the types of constraints you can express. The key enhancements are
|
||||
|
||||
1. the language is more expressive (not just "AND of exact match")
|
||||
2. you can indicate that the rule is "soft"/"preference" rather than a hard requirement, so if the scheduler
|
||||
can't satisfy it, the pod will still be scheduled
|
||||
3. you can constrain against labels on other pods running on the node (or other topological domain),
|
||||
rather than against labels on the node itself, which allows rules about which pods can and cannot be co-located
|
||||
|
||||
The affinity feature consists of two types of affinity, "node affinity" and "inter-pod affinity/anti-affinity".
|
||||
Node affinity is like the existing `nodeSelector` (but with the first two benefits listed above),
|
||||
while inter-pod affinity/anti-affinity constrains against pod labels rather than node labels, as
|
||||
described in the third item listed above, in addition to having the first and second properties listed above.
|
||||
|
||||
`nodeSelector` continues to work as usual, but will eventually be deprecated, as node affinity can express
|
||||
everything that `nodeSelector` can express.
|
||||
|
||||
### Node affinity (beta feature)
|
||||
|
||||
Node affinity was introduced as alpha in Kubernetes 1.2.
|
||||
Node affinity is conceptually similar to `nodeSelector` -- it allows you to constrain which nodes your
|
||||
pod is eligible to be scheduled on, based on labels on the node.
|
||||
|
||||
There are currently two types of node affinity, called `requiredDuringSchedulingIgnoredDuringExecution` and
|
||||
`preferredDuringSchedulingIgnoredDuringExecution`. You can think of them as "hard" and "soft" respectively,
|
||||
in the sense that the former specifies rules that *must* be met for a pod to be scheduled onto a node (just like
|
||||
`nodeSelector` but using a more expressive syntax), while the latter specifies *preferences* that the scheduler
|
||||
will try to enforce but will not guarantee. The "IgnoredDuringExecution" part of the names means that, similar
|
||||
to how `nodeSelector` works, if labels on a node change at runtime such that the affinity rules on a pod are no longer
|
||||
met, the pod will still continue to run on the node. In the future we plan to offer
|
||||
`requiredDuringSchedulingRequiredDuringExecution` which will be just like `requiredDuringSchedulingIgnoredDuringExecution`
|
||||
except that it will evict pods from nodes that cease to satisfy the pods' node affinity requirements.
|
||||
|
||||
Thus an example of `requiredDuringSchedulingIgnoredDuringExecution` would be "only run the pod on nodes with Intel CPUs"
|
||||
and an example `preferredDuringSchedulingIgnoredDuringExecution` would be "try to run this set of pods in availability
|
||||
zone XYZ, but if it's not possible, then allow some to run elsewhere".
|
||||
|
||||
Node affinity is specified as field `nodeAffinity` of field `affinity` in the PodSpec.
|
||||
|
||||
Here's an example of a pod that uses node affinity:
|
||||
|
||||
{{< code file="pod-with-node-affinity.yaml" >}}
|
||||
|
||||
This node affinity rule says the pod can only be placed on a node with a label whose key is
|
||||
`kubernetes.io/e2e-az-name` and whose value is either `e2e-az1` or `e2e-az2`. In addition,
|
||||
among nodes that meet that criteria, nodes with a label whose key is `another-node-label-key` and whose
|
||||
value is `another-node-label-value` should be preferred.
|
||||
|
||||
You can see the operator `In` being used in the example. The new node affinity syntax supports the following operators: `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, `Lt`.
|
||||
You can use `NotIn` and `DoesNotExist` to achieve node anti-affinity behavior, or use
|
||||
[node taints](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) to repel pods from specific nodes.
|
||||
|
||||
If you specify both `nodeSelector` and `nodeAffinity`, *both* must be satisfied for the pod
|
||||
to be scheduled onto a candidate node.
|
||||
|
||||
If you specify multiple `nodeSelectorTerms` associated with `nodeAffinity` types, then the pod can be scheduled onto a node **if one of** the `nodeSelectorTerms` is satisfied.
|
||||
|
||||
If you specify multiple `matchExpressions` associated with `nodeSelectorTerms`, then the pod can be scheduled onto a node **only if all** `matchExpressions` can be satisfied.
|
||||
|
||||
If you remove or change the label of the node where the pod is scheduled, the pod won't be removed. In other words, the affinity selection works only at the time of scheduling the pod.
|
||||
|
||||
The `weight` field in `preferredDuringSchedulingIgnoredDuringExecution` is in the range 1-100. For each node that meets all of the scheduling requirements (resource request, RequiredDuringScheduling affinity expressions, etc.), the scheduler will compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding MatchExpressions. This score is then combined with the scores of other priority functions for the node. The node(s) with the highest total score are the most preferred.
|
||||
|
||||
For more information on node affinity, see the
|
||||
[design doc](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md).
|
||||
|
||||
### Inter-pod affinity and anti-affinity (beta feature)
|
||||
|
||||
Inter-pod affinity and anti-affinity were introduced in Kubernetes 1.4.
|
||||
Inter-pod affinity and anti-affinity allow you to constrain which nodes your pod is eligible to be scheduled *based on
|
||||
labels on pods that are already running on the node* rather than based on labels on nodes. The rules are of the form "this pod should (or, in the case of
|
||||
anti-affinity, should not) run in an X if that X is already running one or more pods that meet rule Y". Y is expressed
|
||||
as a LabelSelector with an associated list of namespaces (or "all" namespaces); unlike nodes, because pods are namespaced
|
||||
(and therefore the labels on pods are implicitly namespaced),
|
||||
a label selector over pod labels must specify which namespaces the selector should apply to. Conceptually X is a topology domain
|
||||
like node, rack, cloud provider zone, cloud provider region, etc. You express it using a `topologyKey` which is the
|
||||
key for the node label that the system uses to denote such a topology domain, e.g. see the label keys listed above
|
||||
in the section [Interlude: built-in node labels](#interlude-built-in-node-labels).
|
||||
|
||||
**Note:** Inter-pod affinity and anti-affinity require substantial amount of
|
||||
processing which can slow down scheduling in large clusters significantly. We do
|
||||
not recommend using them in clusters larger than several hundred nodes.
|
||||
|
||||
As with node affinity, there are currently two types of pod affinity and anti-affinity, called `requiredDuringSchedulingIgnoredDuringExecution` and
|
||||
`preferredDuringSchedulingIgnoredDuringExecution` which denote "hard" vs. "soft" requirements.
|
||||
See the description in the node affinity section earlier.
|
||||
An example of `requiredDuringSchedulingIgnoredDuringExecution` affinity would be "co-locate the pods of service A and service B
|
||||
in the same zone, since they communicate a lot with each other"
|
||||
and an example `preferredDuringSchedulingIgnoredDuringExecution` anti-affinity would be "spread the pods from this service across zones"
|
||||
(a hard requirement wouldn't make sense, since you probably have more pods than zones).
|
||||
|
||||
Inter-pod affinity is specified as field `podAffinity` of field `affinity` in the PodSpec.
|
||||
And inter-pod anti-affinity is specified as field `podAntiAffinity` of field `affinity` in the PodSpec.
|
||||
|
||||
#### An example of a pod that uses pod affinity:
|
||||
|
||||
{{< code file="pod-with-pod-affinity.yaml" >}}
|
||||
|
||||
The affinity on this pod defines one pod affinity rule and one pod anti-affinity rule. In this example, the
|
||||
`podAffinity` is `requiredDuringSchedulingIgnoredDuringExecution`
|
||||
while the `podAntiAffinity` is `preferredDuringSchedulingIgnoredDuringExecution`. The
|
||||
pod affinity rule says that the pod can be scheduled onto a node only if that node is in the same zone
|
||||
as at least one already-running pod that has a label with key "security" and value "S1". (More precisely, the pod is eligible to run
|
||||
on node N if node N has a label with key `failure-domain.beta.kubernetes.io/zone` and some value V
|
||||
such that there is at least one node in the cluster with key `failure-domain.beta.kubernetes.io/zone` and
|
||||
value V that is running a pod that has a label with key "security" and value "S1".) The pod anti-affinity
|
||||
rule says that the pod prefers not to be scheduled onto a node if that node is already running a pod with label
|
||||
having key "security" and value "S2". (If the `topologyKey` were `failure-domain.beta.kubernetes.io/zone` then
|
||||
it would mean that the pod cannot be scheduled onto a node if that node is in the same zone as a pod with
|
||||
label having key "security" and value "S2".) See the
|
||||
[design doc](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)
|
||||
for many more examples of pod affinity and anti-affinity, both the `requiredDuringSchedulingIgnoredDuringExecution`
|
||||
flavor and the `preferredDuringSchedulingIgnoredDuringExecution` flavor.
|
||||
|
||||
The legal operators for pod affinity and anti-affinity are `In`, `NotIn`, `Exists`, `DoesNotExist`.
|
||||
|
||||
In principle, the `topologyKey` can be any legal label-key. However,
|
||||
for performance and security reasons, there are some constraints on topologyKey:
|
||||
|
||||
1. For affinity and for `requiredDuringSchedulingIgnoredDuringExecution` pod anti-affinity,
|
||||
empty `topologyKey` is not allowed.
|
||||
2. For `requiredDuringSchedulingIgnoredDuringExecution` pod anti-affinity, the admission controller `LimitPodHardAntiAffinityTopology` was introduced to limit `topologyKey` to `kubernetes.io/hostname`. If you want to make it available for custom topologies, you may modify the admission controller, or simply disable it.
|
||||
3. For `preferredDuringSchedulingIgnoredDuringExecution` pod anti-affinity, empty `topologyKey` is interpreted as "all topologies" ("all topologies" here is now limited to the combination of `kubernetes.io/hostname`, `failure-domain.beta.kubernetes.io/zone` and `failure-domain.beta.kubernetes.io/region`).
|
||||
4. Except for the above cases, the `topologyKey` can be any legal label-key.
|
||||
|
||||
In addition to `labelSelector` and `topologyKey`, you can optionally specify a list `namespaces`
|
||||
of namespaces which the `labelSelector` should match against (this goes at the same level of the definition as `labelSelector` and `topologyKey`).
|
||||
If omitted, it defaults to the namespace of the pod where the affinity/anti-affinity definition appears.
|
||||
If defined but empty, it means "all namespaces".
|
||||
|
||||
All `matchExpressions` associated with `requiredDuringSchedulingIgnoredDuringExecution` affinity and anti-affinity
|
||||
must be satisfied for the pod to be scheduled onto a node.
|
||||
|
||||
#### More Practical Use-cases
|
||||
|
||||
Interpod Affinity and AntiAffinity can be even more useful when they are used with higher
|
||||
level collections such as ReplicaSets, StatefulSets, Deployments, etc. One can easily configure that a set of workloads should
|
||||
be co-located in the same defined topology, eg., the same node.
|
||||
|
||||
##### Always co-located in the same node
|
||||
|
||||
In a three node cluster, a web application has in-memory cache such as redis. We want the web-servers to be co-located with the cache as much as possible.
|
||||
Here is the yaml snippet of a simple redis deployment with three replicas and selector label `app=store`. The deployment has `PodAntiAffinity` configured to ensure the scheduler does not co-locate replicas on a single node.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: redis-cache
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: store
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: store
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- store
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
containers:
|
||||
- name: redis-server
|
||||
image: redis:3.2-alpine
|
||||
```
|
||||
|
||||
The below yaml snippet of the webserver deployment has `podAntiAffinity` and `podAffinity` configured. This informs the scheduler that all its replicas are to be co-located with pods that have selector label `app=store`. This will also ensure that each web-server replica does not co-locate on a single node.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: web-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: web-store
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: web-store
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- web-store
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- store
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
containers:
|
||||
- name: web-app
|
||||
image: nginx:1.12-alpine
|
||||
```
|
||||
|
||||
If we create the above two deployments, our three node cluster should look like below.
|
||||
|
||||
| node-1 | node-2 | node-3 |
|
||||
|:--------------------:|:-------------------:|:------------------:|
|
||||
| *webserver-1* | *webserver-2* | *webserver-3* |
|
||||
| *cache-1* | *cache-2* | *cache-3* |
|
||||
|
||||
As you can see, all the 3 replicas of the `web-server` are automatically co-located with the cache as expected.
|
||||
|
||||
```
|
||||
$ kubectl get pods -o wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
redis-cache-1450370735-6dzlj 1/1 Running 0 8m 10.192.4.2 kube-node-3
|
||||
redis-cache-1450370735-j2j96 1/1 Running 0 8m 10.192.2.2 kube-node-1
|
||||
redis-cache-1450370735-z73mh 1/1 Running 0 8m 10.192.3.1 kube-node-2
|
||||
web-server-1287567482-5d4dz 1/1 Running 0 7m 10.192.2.3 kube-node-1
|
||||
web-server-1287567482-6f7v5 1/1 Running 0 7m 10.192.4.3 kube-node-3
|
||||
web-server-1287567482-s330j 1/1 Running 0 7m 10.192.3.2 kube-node-2
|
||||
```
|
||||
|
||||
##### Never co-located in the same node
|
||||
|
||||
The above example uses `PodAntiAffinity` rule with `topologyKey: "kubernetes.io/hostname"` to deploy the redis cluster so that
|
||||
no two instances are located on the same host.
|
||||
See [ZooKeeper tutorial](https://kubernetes.io/docs/tutorials/stateful-application/zookeeper/#tolerating-node-failure)
|
||||
for an example of a StatefulSet configured with anti-affinity for high availability, using the same technique.
|
||||
|
||||
For more information on inter-pod affinity/anti-affinity, see the
|
||||
[design doc](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md).
|
||||
|
||||
You may want to check [Taints](/docs/concepts/configuration/taint-and-toleration/)
|
||||
as well, which allow a *node* to *repel* a set of pods.
|
||||
@@ -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,549 @@
|
||||
---
|
||||
title: Managing Compute Resources for Containers
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
When you specify a [Pod](/docs/concepts/workloads/pods/pod/), you can optionally specify how
|
||||
much CPU and memory (RAM) each Container needs. When Containers have resource
|
||||
requests specified, the scheduler can make better decisions about which nodes to
|
||||
place Pods on. And when Containers have their limits specified, contention for
|
||||
resources on a node can be handled in a specified manner. For more details about
|
||||
the difference between requests and limits, see
|
||||
[Resource QoS](https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Resource types
|
||||
|
||||
*CPU* and *memory* are each a *resource type*. A resource type has a base unit.
|
||||
CPU is specified in units of cores, and memory is specified in units of bytes.
|
||||
|
||||
CPU and memory are collectively referred to as *compute resources*, or just
|
||||
*resources*. Compute
|
||||
resources are measurable quantities that can be requested, allocated, and
|
||||
consumed. They are distinct from
|
||||
[API resources](/docs/concepts/overview/kubernetes-api/). API resources, such as Pods and
|
||||
[Services](/docs/concepts/services-networking/service/) are objects that can be read and modified
|
||||
through the Kubernetes API server.
|
||||
|
||||
## Resource requests and limits of Pod and Container
|
||||
|
||||
Each Container of a Pod can specify one or more of the following:
|
||||
|
||||
* `spec.containers[].resources.limits.cpu`
|
||||
* `spec.containers[].resources.limits.memory`
|
||||
* `spec.containers[].resources.requests.cpu`
|
||||
* `spec.containers[].resources.requests.memory`
|
||||
|
||||
Although requests and limits can only be specified on individual Containers, it
|
||||
is convenient to talk about Pod resource requests and limits. A
|
||||
*Pod resource request/limit* for a particular resource type is the sum of the
|
||||
resource requests/limits of that type for each Container in the Pod.
|
||||
|
||||
## Meaning of CPU
|
||||
|
||||
Limits and requests for CPU resources are measured in *cpu* units.
|
||||
One cpu, in Kubernetes, is equivalent to:
|
||||
|
||||
- 1 AWS vCPU
|
||||
- 1 GCP Core
|
||||
- 1 Azure vCore
|
||||
- 1 *Hyperthread* on a bare-metal Intel processor with Hyperthreading
|
||||
|
||||
Fractional requests are allowed. A Container with
|
||||
`spec.containers[].resources.requests.cpu` of `0.5` is guaranteed half as much
|
||||
CPU as one that asks for 1 CPU. The expression `0.1` is equivalent to the
|
||||
expression `100m`, which can be read as "one hundred millicpu". Some people say
|
||||
"one hundred millicores", and this is understood to mean the same thing. A
|
||||
request with a decimal point, like `0.1`, is converted to `100m` by the API, and
|
||||
precision finer than `1m` is not allowed. For this reason, the form `100m` might
|
||||
be preferred.
|
||||
|
||||
CPU is always requested as an absolute quantity, never as a relative quantity;
|
||||
0.1 is the same amount of CPU on a single-core, dual-core, or 48-core machine.
|
||||
|
||||
## Meaning of memory
|
||||
|
||||
Limits and requests for `memory` are measured in bytes. You can express memory as
|
||||
a plain integer or as a fixed-point integer using one of these suffixes:
|
||||
E, P, T, G, M, K. You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi,
|
||||
Mi, Ki. For example, the following represent roughly the same value:
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
Here's an example.
|
||||
The following Pod has two Containers. Each Container has a request of 0.25 cpu
|
||||
and 64MiB (2<sup>26</sup> bytes) of memory. Each Container has a limit of 0.5
|
||||
cpu and 128MiB of memory. You can say the Pod has a request of 0.5 cpu and 128
|
||||
MiB of memory, and a limit of 1 cpu and 256MiB of memory.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
value: "password"
|
||||
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"
|
||||
```
|
||||
|
||||
## How Pods with resource requests are scheduled
|
||||
|
||||
When you create a Pod, the Kubernetes scheduler selects a node for the Pod to
|
||||
run on. Each node has a maximum capacity for each of the resource types: the
|
||||
amount of CPU and memory it can provide for Pods. The scheduler ensures that,
|
||||
for each resource type, the sum of the resource requests of the scheduled
|
||||
Containers is less than the capacity of the node. Note that although actual memory
|
||||
or CPU resource usage on nodes is very low, the scheduler still refuses to place
|
||||
a Pod on a node if the capacity check fails. This protects against a resource
|
||||
shortage on a node when resource usage later increases, for example, during a
|
||||
daily peak in request rate.
|
||||
|
||||
## How Pods with resource limits are run
|
||||
|
||||
When the kubelet starts a Container of a Pod, it passes the CPU and memory limits
|
||||
to the container runtime.
|
||||
|
||||
When using Docker:
|
||||
|
||||
- The `spec.containers[].resources.requests.cpu` is converted to its core value,
|
||||
which is potentially fractional, and multiplied by 1024. The greater of this number
|
||||
or 2 is used as the value of the
|
||||
[`--cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint)
|
||||
flag in the `docker run` command.
|
||||
|
||||
- The `spec.containers[].resources.limits.cpu` is converted to its millicore value and
|
||||
multiplied by 100. The resulting value is the total amount of CPU time that a container can use
|
||||
every 100ms. A container cannot use more than its share of CPU time during this interval.
|
||||
|
||||
{{< note >}}
|
||||
**Note**: The default quota period is 100ms. The minimum resolution of CPU quota is 1ms.
|
||||
{{< /note >}}
|
||||
|
||||
- The `spec.containers[].resources.limits.memory` is converted to an integer, and
|
||||
used as the value of the
|
||||
[`--memory`](https://docs.docker.com/engine/reference/run/#/user-memory-constraints)
|
||||
flag in the `docker run` command.
|
||||
|
||||
If a Container exceeds its memory limit, it might be terminated. If it is
|
||||
restartable, the kubelet will restart it, as with any other type of runtime
|
||||
failure.
|
||||
|
||||
If a Container exceeds its memory request, it is likely that its Pod will
|
||||
be evicted whenever the node runs out of memory.
|
||||
|
||||
A Container might or might not be allowed to exceed its CPU limit for extended
|
||||
periods of time. However, it will not be killed for excessive CPU usage.
|
||||
|
||||
To determine whether a Container cannot be scheduled or is being killed due to
|
||||
resource limits, see the
|
||||
[Troubleshooting](#troubleshooting) section.
|
||||
|
||||
## Monitoring compute resource usage
|
||||
|
||||
The resource usage of a Pod is reported as part of the Pod status.
|
||||
|
||||
If [optional monitoring](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/cluster-monitoring/README.md)
|
||||
is configured for your cluster, then Pod resource usage can be retrieved from
|
||||
the monitoring system.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### My Pods are pending with event message failedScheduling
|
||||
|
||||
If the scheduler cannot find any node where a Pod can fit, the Pod remains
|
||||
unscheduled until a place can be found. An event is produced each time the
|
||||
scheduler fails to find a place for the Pod, like this:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
In the preceding example, the Pod named "frontend" fails to be scheduled due to
|
||||
insufficient CPU resource on the node. Similar error messages can also suggest
|
||||
failure due to insufficient memory (PodExceedsFreeMemory). In general, if a Pod
|
||||
is pending with a message of this type, there are several things to try:
|
||||
|
||||
- Add more nodes to the cluster.
|
||||
- Terminate unneeded Pods to make room for pending Pods.
|
||||
- Check that the Pod is not larger than all the nodes. For example, if all the
|
||||
nodes have a capacity of `cpu: 1`, then a Pod with a request of `cpu: 1.1` will
|
||||
never be scheduled.
|
||||
|
||||
You can check node capacities and amounts allocated with the
|
||||
`kubectl describe nodes` command. For example:
|
||||
|
||||
```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%)
|
||||
```
|
||||
|
||||
In the preceding output, you can see that if a Pod requests more than 1120m
|
||||
CPUs or 6.23Gi of memory, it will not fit on the node.
|
||||
|
||||
By looking at the `Pods` section, you can see which Pods are taking up space on
|
||||
the node.
|
||||
|
||||
The amount of resources available to Pods is less than the node capacity, because
|
||||
system daemons use a portion of the available resources. The `allocatable` field
|
||||
[NodeStatus](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#nodestatus-v1-core)
|
||||
gives the amount of resources that are available to Pods. For more information, see
|
||||
[Node Allocatable Resources](https://git.k8s.io/community/contributors/design-proposals/node/node-allocatable.md).
|
||||
|
||||
The [resource quota](/docs/concepts/policy/resource-quotas/) feature can be configured
|
||||
to limit the total amount of resources that can be consumed. If used in conjunction
|
||||
with namespaces, it can prevent one team from hogging all the resources.
|
||||
|
||||
### My Container is terminated
|
||||
|
||||
Your Container might get terminated because it is resource-starved. To check
|
||||
whether a Container is being killed because it is hitting a resource limit, call
|
||||
`kubectl describe pod` on the Pod of interest:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
In the preceding example, the `Restart Count: 5` indicates that the `simmemleak`
|
||||
Container in the Pod was terminated and restarted five times.
|
||||
|
||||
You can call `kubectl get pod` with the `-o go-template=...` option to fetch the status
|
||||
of previously terminated Containers:
|
||||
|
||||
```shell
|
||||
[13:59:01] $ kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-hra99
|
||||
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]]
|
||||
```
|
||||
|
||||
You can see that the Container was terminated because of `reason:OOM Killed`,
|
||||
where `OOM` stands for Out Of Memory.
|
||||
|
||||
## Local ephemeral storage
|
||||
{{< feature-state state="beta" >}}
|
||||
|
||||
Kubernetes version 1.8 introduces a new resource, _ephemeral-storage_ for managing local ephemeral storage. In each Kubernetes node, kubelet's root directory (/var/lib/kubelet by default) and log directory (/var/log) are stored on the root partition of the node. This partition is also shared and consumed by pods via EmptyDir volumes, container logs, image layers and container writable layers.
|
||||
|
||||
This partition is “ephemeral” and applications cannot expect any performance SLAs (Disk IOPS for example) from this partition. Local ephemeral storage management only applies for the root partition; the optional partition for image layer and writable layer is out of scope.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** If an optional runtime partition is used, root partition will not hold any image layer or writable layers.
|
||||
{{< /note >}}
|
||||
|
||||
### Requests and limits setting for local ephemeral storage
|
||||
Each Container of a Pod can specify one or more of the following:
|
||||
|
||||
* `spec.containers[].resources.limits.ephemeral-storage`
|
||||
* `spec.containers[].resources.requests.ephemeral-storage`
|
||||
|
||||
Limits and requests for `ephemeral-storage` are measured in bytes. You can express storage as
|
||||
a plain integer or as a fixed-point integer using one of these suffixes:
|
||||
E, P, T, G, M, K. You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi,
|
||||
Mi, Ki. For example, the following represent roughly the same value:
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
For example, the following Pod has two Containers. Each Container has a request of 2GiB of local ephemeral storage. Each Container has a limit of 4GiB of local ephemeral storage. Therefore, the Pod has a request of 4GiB of local ephemeral storage, and a limit of 8GiB of storage.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
value: "password"
|
||||
resources:
|
||||
requests:
|
||||
ephemeral-storage: "2Gi"
|
||||
limits:
|
||||
ephemeral-storage: "4Gi"
|
||||
- name: wp
|
||||
image: wordpress
|
||||
resources:
|
||||
requests:
|
||||
ephemeral-storage: "2Gi"
|
||||
limits:
|
||||
ephemeral-storage: "4Gi"
|
||||
```
|
||||
|
||||
### How Pods with ephemeral-storage requests are scheduled
|
||||
|
||||
When you create a Pod, the Kubernetes scheduler selects a node for the Pod to
|
||||
run on. Each node has a maximum amount of local ephemeral storage it can provide for Pods. (For more information, see ["Node Allocatable"](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable) The scheduler ensures that the sum of the resource requests of the scheduled Containers is less than the capacity of the node.
|
||||
|
||||
### How Pods with ephemeral-storage limits run
|
||||
|
||||
For container-level isolation, if a Container's writable layer and logs usage exceeds its storage limit, the pod will be evicted. For pod-level isolation, if the sum of the local ephemeral storage usage from all containers and also the pod's EmptyDir volumes exceeds the limit, the pod will be evicted.
|
||||
|
||||
## Extended Resources
|
||||
|
||||
Extended Resources are fully-qualified resource names outside the
|
||||
`kubernetes.io` domain. They allow cluster operators to advertise and users to
|
||||
consume the non-Kubernetes-built-in resources.
|
||||
|
||||
There are two steps required to use Extended Resources. First, the cluster
|
||||
operator must advertise an Extended Resource. Second, users must request the
|
||||
Extended Resource in Pods.
|
||||
|
||||
### Managing extended resources
|
||||
|
||||
#### Node-level extended resources
|
||||
|
||||
Node-level extended resources are tied to nodes.
|
||||
|
||||
##### Device plugin managed resources
|
||||
See [Device
|
||||
Plugin](https://kubernetes.io/docs/concepts/cluster-administration/device-plugins/)
|
||||
for how to advertise device plugin managed resources on each node.
|
||||
|
||||
##### Other resources
|
||||
To advertise a new node-level extended resource, the cluster operator can
|
||||
submit a `PATCH` HTTP request to the API server to specify the available
|
||||
quantity in the `status.capacity` for a node in the cluster. After this
|
||||
operation, the node's `status.capacity` will include a new resource. The
|
||||
`status.allocatable` field is updated automatically with the new resource
|
||||
asynchronously by the kubelet. Note that because the scheduler uses the node
|
||||
`status.allocatable` value when evaluating Pod fitness, there may be a short
|
||||
delay between patching the node capacity with a new resource and the first pod
|
||||
that requests the resource to be scheduled on that node.
|
||||
|
||||
**Example:**
|
||||
|
||||
Here is an example showing how to use `curl` to form an HTTP request that
|
||||
advertises five "example.com/foo" resources on node `k8s-node-1` whose master
|
||||
is `k8s-master`.
|
||||
|
||||
```shell
|
||||
curl --header "Content-Type: application/json-patch+json" \
|
||||
--request PATCH \
|
||||
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
|
||||
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
**Note**: In the preceding request, `~1` is the encoding for the character `/`
|
||||
in the patch path. The operation path value in JSON-Patch is interpreted as a
|
||||
JSON-Pointer. For more details, see
|
||||
[IETF RFC 6901, section 3](https://tools.ietf.org/html/rfc6901#section-3).
|
||||
{{< /note >}}
|
||||
|
||||
#### Cluster-level extended resources
|
||||
|
||||
Cluster-level extended resources are not tied to nodes. They are usually managed
|
||||
by scheduler extenders, which handle the resource comsumption, quota and so on.
|
||||
|
||||
You can specify the extended resources that are handled by scheduler extenders
|
||||
in [scheduler policy
|
||||
configuration](https://github.com/kubernetes/kubernetes/blob/release-1.10/pkg/scheduler/api/v1/types.go#L31).
|
||||
|
||||
**Example:**
|
||||
|
||||
The following configuration for a scheduler policy indicates that the
|
||||
cluster-level extended resource "example.com/foo" is handled by scheduler
|
||||
extender.
|
||||
- The scheduler sends a pod to the scheduler extender only if the pod requests
|
||||
"example.com/foo".
|
||||
- The `ignoredByScheduler` field specifies that the scheduler does not check
|
||||
the "example.com/foo" resource in its `PodFitsResources` predicate.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Policy",
|
||||
"apiVersion": "v1",
|
||||
"extenders": [
|
||||
{
|
||||
"urlPrefix":"<extender-endpoint>",
|
||||
"bindVerb": "bind",
|
||||
"ManagedResources": [
|
||||
{
|
||||
"name": "example.com/foo",
|
||||
"ignoredByScheduler": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Consuming extended resources
|
||||
|
||||
Users can consume Extended Resources in Pod specs just like CPU and memory.
|
||||
The scheduler takes care of the resource accounting so that no more than the
|
||||
available amount is simultaneously allocated to Pods.
|
||||
|
||||
The API server restricts quantities of Extended Resources to whole numbers.
|
||||
Examples of _valid_ quantities are `3`, `3000m` and `3Ki`. Examples of
|
||||
_invalid_ quantities are `0.5` and `1500m`.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Extended Resources replace Opaque Integer Resources.
|
||||
Users can use any domain name prefix other than "`kubernetes.io`" which is reserved.
|
||||
{{< /note >}}
|
||||
|
||||
To consume an Extended Resource in a Pod, include the resource name as a key
|
||||
in the `spec.containers[].resources.limits` map in the container spec.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Extended resources cannot be overcommitted, so request and limit
|
||||
must be equal if both are present in a container spec.
|
||||
{{< /note >}}
|
||||
|
||||
A Pod is scheduled only if all of the resource requests are satisfied, including
|
||||
CPU, memory and any Extended Resources. The Pod remains in the `PENDING` state
|
||||
as long as the resource request cannot be satisfied.
|
||||
|
||||
**Example:**
|
||||
|
||||
The Pod below requests 2 CPUs and 1 "example.com/foo" (an extended resource).
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: my-container
|
||||
image: myimage
|
||||
resources:
|
||||
requests:
|
||||
cpu: 2
|
||||
example.com/foo: 1
|
||||
limits:
|
||||
example.com/foo: 1
|
||||
```
|
||||
|
||||
## Planned Improvements
|
||||
|
||||
Kubernetes version 1.5 only allows resource quantities to be specified on a
|
||||
Container. It is planned to improve accounting for resources that are shared by
|
||||
all Containers in a Pod, such as
|
||||
[emptyDir volumes](/docs/concepts/storage/volumes/#emptydir).
|
||||
|
||||
Kubernetes version 1.5 only supports Container requests and limits for CPU and
|
||||
memory. It is planned to add new resource types, including a node disk space
|
||||
resource, and a framework for adding custom
|
||||
[resource types](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/scheduling/resources.md).
|
||||
|
||||
Kubernetes supports overcommitment of resources by supporting multiple levels of
|
||||
[Quality of Service](http://issue.k8s.io/168).
|
||||
|
||||
In Kubernetes version 1.5, one unit of CPU means different things on different
|
||||
cloud providers, and on different machine types within the same cloud providers.
|
||||
For example, on AWS, the capacity of a node is reported in
|
||||
[ECUs](http://aws.amazon.com/ec2/faqs/), while in GCE it is reported in logical
|
||||
cores. We plan to revise the definition of the cpu resource to allow for more
|
||||
consistency across providers and platforms.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* Get hands-on experience [assigning Memory resources to containers and pods](/docs/tasks/configure-pod-container/assign-memory-resource/).
|
||||
|
||||
* Get hands-on experience [assigning CPU resources to containers and pods](/docs/tasks/configure-pod-container/assign-cpu-resource/).
|
||||
|
||||
* [Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core)
|
||||
|
||||
* [ResourceRequirements](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#resourcerequirements-v1-core)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
title: Organizing Cluster Access Using kubeconfig Files
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
Use kubeconfig files to organize information about clusters, users, namespaces, and
|
||||
authentication mechanisms. The `kubectl` command-line tool uses kubeconfig files to
|
||||
find the information it needs to choose a cluster and communicate with the API server
|
||||
of a cluster.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** A file that is used to configure access to clusters is called
|
||||
a *kubeconfig file*. This is a generic way of referring to configuration files.
|
||||
It does not mean that there is a file named `kubeconfig`.
|
||||
{{< /note >}}
|
||||
|
||||
By default, `kubectl` looks for a file named `config` in the `$HOME/.kube` directory.
|
||||
You can specify other kubeconfig files by setting the `KUBECONFIG` environment
|
||||
variable or by setting the
|
||||
[`--kubeconfig`](/docs/reference/generated/kubectl/kubectl/) flag.
|
||||
|
||||
For step-by-step instructions on creating and specifying kubeconfig files, see
|
||||
[Configure Access to Multiple Clusters](/docs/tasks/access-application-cluster/configure-access-multiple-clusters).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Supporting multiple clusters, users, and authentication mechanisms
|
||||
|
||||
Suppose you have several clusters, and your users and components authenticate
|
||||
in a variety of ways. For example:
|
||||
|
||||
- A running kubelet might authenticate using certificates.
|
||||
- A user might authenticate using tokens.
|
||||
- Administrators might have sets of certificates that they provide to individual users.
|
||||
|
||||
With kubeconfig files, you can organize your clusters, users, and namespaces.
|
||||
You can also define contexts to quickly and easily switch between
|
||||
clusters and namespaces.
|
||||
|
||||
## Context
|
||||
|
||||
A *context* element in a kubeconfig file is used to group access parameters
|
||||
under a convenient name. Each context has three parameters: cluster, namespace, and user.
|
||||
By default, the `kubectl` command-line tool uses parameters from
|
||||
the *current context* to communicate with the cluster.
|
||||
|
||||
To choose the current context:
|
||||
```
|
||||
kubectl config use-context
|
||||
```
|
||||
|
||||
## The KUBECONFIG environment variable
|
||||
|
||||
The `KUBECONFIG` environment variable holds a list of kubeconfig files.
|
||||
For Linux and Mac, the list is colon-delimited. For Windows, the list
|
||||
is semicolon-delimited. The `KUBECONFIG` environment variable is not
|
||||
required. If the `KUBECONFIG` environment variable doesn't exist,
|
||||
`kubectl` uses the default kubeconfig file, `$HOME/.kube/config`.
|
||||
|
||||
If the `KUBECONFIG` environment variable does exist, `kubectl` uses
|
||||
an effective configuration that is the result of merging the files
|
||||
listed in the `KUBECONFIG` environment variable.
|
||||
|
||||
## Merging kubeconfig files
|
||||
|
||||
To see your configuration, enter this command:
|
||||
|
||||
```shell
|
||||
kubectl config view
|
||||
```
|
||||
|
||||
As described previously, the output might be from a single kubeconfig file,
|
||||
or it might be the result of merging several kubeconfig files.
|
||||
|
||||
Here are the rules that `kubectl` uses when it merges kubeconfig files:
|
||||
|
||||
1. If the `--kubeconfig` flag is set, use only the specified file. Do not merge.
|
||||
Only one instance of this flag is allowed.
|
||||
|
||||
Otherwise, if the `KUBECONFIG` environment variable is set, use it as a
|
||||
list of files that should be merged.
|
||||
Merge the files listed in the `KUBECONFIG` environment variable
|
||||
according to these rules:
|
||||
|
||||
* Ignore empty filenames.
|
||||
* Produce errors for files with content that cannot be deserialized.
|
||||
* The first file to set a particular value or map key wins.
|
||||
* Never change the value or map key.
|
||||
Example: Preserve the context of the first file to set `current-context`.
|
||||
Example: If two files specify a `red-user`, use only values from the first file's `red-user`.
|
||||
Even if the second file has non-conflicting entries under `red-user`, discard them.
|
||||
|
||||
For an example of setting the `KUBECONFIG` environment variable, see
|
||||
[Setting the KUBECONFIG environment variable](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#set-the-kubeconfig-environment-variable).
|
||||
|
||||
Otherwise, use the default kubeconfig file, `$HOME/.kube/config`, with no merging.
|
||||
|
||||
1. Determine the context to use based on the first hit in this chain:
|
||||
|
||||
1. Use the `--context` command-line flag if it exits.
|
||||
1. Use the `current-context` from the merged kubeconfig files.
|
||||
|
||||
An empty context is allowed at this point.
|
||||
|
||||
1. Determine the cluster and user. At this point, there might or might not be a context.
|
||||
Determine the cluster and user based on the first hit in this chain,
|
||||
which is run twice: once for user and once for cluster:
|
||||
|
||||
1. Use a command-line flag if it exists: `--user` or `--cluster`.
|
||||
1. If the context is non-empty, take the user or cluster from the context.
|
||||
|
||||
The user and cluster can be empty at this point.
|
||||
|
||||
1. Determine the actual cluster information to use. At this point, there might or
|
||||
might not be cluster information.
|
||||
Build each piece of the cluster information based on this chain; the first hit wins:
|
||||
|
||||
1. Use command line flags if they exist: `--server`, `--certificate-authority`, `--insecure-skip-tls-verify`.
|
||||
1. If any cluster information attributes exist from the merged kubeconfig files, use them.
|
||||
1. If there is no server location, fail.
|
||||
|
||||
1. Determine the actual user information to use. Build user information using the same
|
||||
rules as cluster information, except allow only one authentication
|
||||
technique per user:
|
||||
|
||||
1. Use command line flags if they exist: `--client-certificate`, `--client-key`, `--username`, `--password`, `--token`.
|
||||
1. Use the `user` fields from the merged kubeconfig files.
|
||||
1. If there are two conflicting techniques, fail.
|
||||
|
||||
1. For any information still missing, use default values and potentially
|
||||
prompt for authentication information.
|
||||
|
||||
## File references
|
||||
|
||||
File and path references in a kubeconfig file are relative to the location of the kubeconfig file.
|
||||
File references on the command line are relative to the current working directory.
|
||||
In `$HOME/.kube/config`, relative paths are stored relatively, and absolute paths
|
||||
are stored absolutely.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [Configure Access to Multiple Clusters](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)
|
||||
* [`kubectl config`](/docs/reference/generated/kubectl/kubectl-commands#config)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
reviewers:
|
||||
- mikedanese
|
||||
title: Configuration Best Practices
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
This document highlights and consolidates configuration best practices that are introduced throughout the user guide, Getting Started documentation, and examples.
|
||||
|
||||
This is a living document. If you think of something that is not on this list but might be useful to others, please don't hesitate to file an issue or submit a PR.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
## General Configuration Tips
|
||||
|
||||
- When defining configurations, specify the latest stable API version.
|
||||
|
||||
- Configuration files should be stored in version control before being pushed to the cluster. This allows you to quickly roll back a configuration change if necessary. It also aids cluster re-creation and restoration.
|
||||
|
||||
- Write your configuration files using YAML rather than JSON. Though these formats can be used interchangeably in almost all scenarios, YAML tends to be more user-friendly.
|
||||
|
||||
- Group related objects into a single file whenever it makes sense. One file is often easier to manage than several. See the [guestbook-all-in-one.yaml](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/guestbook/all-in-one/guestbook-all-in-one.yaml) file as an example of this syntax.
|
||||
|
||||
- Note also that many `kubectl` commands can be called on a directory. For example, you can call `kubectl create` on a directory of config files.
|
||||
|
||||
- Don't specify default values unnecessarily: simple, minimal configuration will make errors less likely.
|
||||
|
||||
- Put object descriptions in annotations, to allow better introspection.
|
||||
|
||||
|
||||
## "Naked" Pods vs ReplicaSets, Deployments, and Jobs
|
||||
|
||||
- Don't use naked Pods (that is, Pods not bound to a [ReplicaSet](/docs/concepts/workloads/controllers/replicaset/) or [Deployment](/docs/concepts/workloads/controllers/deployment/)) if you can avoid it. Naked Pods will not be rescheduled in the event of a node failure.
|
||||
|
||||
A Deployment, which both creates a ReplicaSet to ensure that the desired number of Pods is always available, and specifies a strategy to replace Pods (such as [RollingUpdate](/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment)), is almost always preferable to creating Pods directly, except for some explicit [`restartPolicy: Never`](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) scenarios. A [Job](/docs/concepts/workloads/controllers/jobs-run-to-completion/) may also be appropriate.
|
||||
|
||||
|
||||
## Services
|
||||
|
||||
- Create a [Service](/docs/concepts/services-networking/service/) before its corresponding backend workloads (Deployments or ReplicaSets), and before any workloads that need to access it. When Kubernetes starts a container, it provides environment variables pointing to all the Services which were running when the container was started. For example, if a Service named `foo` exists, all containers will get the following variables in their initial environment:
|
||||
|
||||
```shell
|
||||
FOO_SERVICE_HOST=<the host the Service is running on>
|
||||
FOO_SERVICE_PORT=<the port the Service is running on>
|
||||
```
|
||||
|
||||
If you are writing code that talks to a Service, don't use these environment variables; use the [DNS name of the Service](/docs/concepts/services-networking/dns-pod-service/) instead. Service environment variables are provided only for older software which can't be modified to use DNS lookups, and are a much less flexible way of accessing Services.
|
||||
|
||||
- Don't specify a `hostPort` for a Pod unless it is absolutely necessary. When you bind a Pod to a `hostPort`, it limits the number of places the Pod can be scheduled, because each <`hostIP`, `hostPort`, `protocol`> combination must be unique. If you don't specify the `hostIP` and `protocol` explicitly, Kubernetes will use `0.0.0.0` as the default `hostIP` and `TCP` as the default `protocol`.
|
||||
|
||||
If you only need access to the port for debugging purposes, you can use the [apiserver proxy](/docs/tasks/access-application-cluster/access-cluster/#manually-constructing-apiserver-proxy-urls) or [`kubectl port-forward`](/docs/tasks/access-application-cluster/port-forward-access-application-cluster/).
|
||||
|
||||
If you explicitly need to expose a Pod's port on the node, consider using a [NodePort](/docs/concepts/services-networking/service/#type-nodeport) Service before resorting to `hostPort`.
|
||||
|
||||
- Avoid using `hostNetwork`, for the same reasons as `hostPort`.
|
||||
|
||||
- Use [headless Services](/docs/concepts/services-networking/service/#headless-
|
||||
services) (which have a `ClusterIP` of `None`) for easy service discovery when you don't need `kube-proxy` load balancing.
|
||||
|
||||
## Using Labels
|
||||
|
||||
- Define and use [labels](/docs/concepts/overview/working-with-objects/labels/) that identify __semantic attributes__ of your application or Deployment, such as `{ app: myapp, tier: frontend, phase: test, deployment: v3 }`. You can use these labels to select the appropriate Pods for other resources; for example, a Service that selects all `tier: frontend` Pods, or all `phase: test` components of `app: myapp`. See the [guestbook](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/guestbook/) app for examples of this approach.
|
||||
|
||||
A Service can be made to span multiple Deployments by omitting release-specific labels from its selector. [Deployments](/docs/concepts/workloads/controllers/deployment/) make it easy to update a running service without downtime.
|
||||
|
||||
A desired state of an object is described by a Deployment, and if changes to that spec are _applied_, the deployment controller changes the actual state to the desired state at a controlled rate.
|
||||
|
||||
- You can manipulate labels for debugging. Because Kubernetes controllers (such as ReplicaSet) and Services match to Pods using selector labels, removing the relevant labels from a Pod will stop it from being considered by a controller or from being served traffic by a Service. If you remove the labels of an existing Pod, its controller will create a new Pod to take its place. This is a useful way to debug a previously "live" Pod in a "quarantine" environment. To interactively remove or add labels, use [`kubectl label`](/docs/reference/generated/kubectl/kubectl-commands#label).
|
||||
|
||||
## Container Images
|
||||
|
||||
- The default [imagePullPolicy](/docs/concepts/containers/images/#updating-images) for a container is `IfNotPresent`, which causes the [kubelet](/docs/admin/kubelet/) to pull an image only if it does not already exist locally. If you want the image to be pulled every time Kubernetes starts the container, specify `imagePullPolicy: Always`.
|
||||
|
||||
An alternative, but deprecated way to have Kubernetes always pull the image is to use the `:latest` tag, which will implicitly set the `imagePullPolicy` to `Always`.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** You should avoid using the `:latest` tag when deploying containers in production, because this makes it hard to track which version of the image is running and hard to roll back.
|
||||
{{< /note >}}
|
||||
|
||||
- To make sure the container always uses the same version of the image, you can specify its [digest](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier) (for example `sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2`). This uniquely identifies a specific version of the image, so it will never be updated by Kubernetes unless you change the digest value.
|
||||
|
||||
## Using kubectl
|
||||
|
||||
- Use `kubectl apply -f <directory>` or `kubectl create -f <directory>`. This looks for Kubernetes configuration in all `.yaml`, `.yml`, and `.json` files in `<directory>` and passes it to `apply` or `create`.
|
||||
|
||||
- Use label selectors for `get` and `delete` operations instead of specific object names. See the sections on [label selectors](/docs/concepts/overview/working-with-objects/labels/#label-selectors) and [using labels effectively](/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively).
|
||||
|
||||
- Use `kubectl run` and `kubectl expose` to quickly create single-container Deployments and Services. See [Use a Service to Access an Application in a Cluster](/docs/tasks/access-application-cluster/service-access-application-cluster/) for an example.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
- wojtek-t
|
||||
title: Pod Priority and Preemption
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< feature-state state="alpha" >}}
|
||||
|
||||
[Pods](/docs/user-guide/pods) in Kubernetes 1.8 and later can have priority. Priority
|
||||
indicates the importance of a Pod relative to other Pods. When a Pod cannot be scheduled,
|
||||
the scheduler tries to preempt (evict) lower priority Pods to make scheduling of the
|
||||
pending Pod possible. In Kubernetes 1.9 and later, Priority also affects scheduling
|
||||
order of Pods and out-of-resource eviction ordering on the Node.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## How to use priority and preemption
|
||||
To use priority and preemption in Kubernetes 1.8 and later, follow these steps:
|
||||
|
||||
1. Enable the feature.
|
||||
|
||||
1. Add one or more PriorityClasses.
|
||||
|
||||
1. Create Pods with `priorityClassName` set to one of the added PriorityClasses.
|
||||
Of course you do not need to create the Pods directly; normally you would add
|
||||
`priorityClassName` to the Pod template of a collection object like a Deployment.
|
||||
|
||||
The following sections provide more information about these steps.
|
||||
|
||||
## Enabling priority and preemption
|
||||
|
||||
Pod priority and preemption is disabled by default in Kubernetes 1.8.
|
||||
To enable the feature, set this command-line flag for the API server, scheduler and kubelet:
|
||||
|
||||
```
|
||||
--feature-gates=PodPriority=true
|
||||
```
|
||||
|
||||
Also enable scheduling.k8s.io/v1alpha1 API and Priority [admission controller](/docs/admin/admission-controllers/) in API server:
|
||||
|
||||
|
||||
```
|
||||
--runtime-config=scheduling.k8s.io/v1alpha1=true --enable-admission-plugins=Controller-Foo,Controller-Bar,...,Priority
|
||||
```
|
||||
|
||||
After the feature is enabled, you can create [PriorityClasses](#priorityclass)
|
||||
and create Pods with [`priorityClassName`](#pod-priority) set.
|
||||
|
||||
If you try the feature and then decide to disable it, you must remove the PodPriority
|
||||
command-line flag or set it to false, and then restart the API server and
|
||||
scheduler. After the feature is disabled, the existing Pods keep their priority
|
||||
fields, but preemption is disabled, and priority fields are ignored, and you
|
||||
cannot set `priorityClassName` in new Pods.
|
||||
|
||||
## PriorityClass
|
||||
|
||||
A PriorityClass is a non-namespaced object that defines a mapping from a priority
|
||||
class name to the integer value of the priority. The name is specified in the `name`
|
||||
field of the PriorityClass object's metadata. The value is specified in the required
|
||||
`value` field. The higher the value, the higher the priority.
|
||||
|
||||
A PriorityClass object can have any 32-bit integer value smaller than or equal to
|
||||
1 billion. Larger numbers are reserved for critical system Pods that should not
|
||||
normally be preempted or evicted. A cluster admin should create one PriorityClass
|
||||
object for each such mapping that they want.
|
||||
|
||||
PriorityClass also has two optional fields: `globalDefault` and `description`.
|
||||
The `globalDefault` field indicates that the value of this PriorityClass should
|
||||
be used for Pods without a `priorityClassName`. Only one PriorityClass with
|
||||
`globalDefault` set to true can exist in the system. If there is no PriorityClass
|
||||
with `globalDefault` set, the priority of Pods with no `priorityClassName` is zero.
|
||||
|
||||
The `description` field is an arbitrary string. It is meant to tell users of
|
||||
the cluster when they should use this PriorityClass.
|
||||
|
||||
{{< note >}}
|
||||
**Note 1**: If you upgrade your existing cluster and enable this feature, the priority
|
||||
of your existing Pods will be considered to be zero.
|
||||
{{< /note >}}
|
||||
|
||||
{{< note >}}
|
||||
**Note 2**: Addition of a PriorityClass with `globalDefault` set to true does not
|
||||
change the priorities of existing Pods. The value of such a PriorityClass is used only
|
||||
for Pods created after the PriorityClass is added.
|
||||
{{< /note >}}
|
||||
|
||||
{{< note >}}
|
||||
**Note 3**: If you delete a PriorityClass, existing Pods that use the name of the
|
||||
deleted priority class remain unchanged, but you are not able to create more Pods
|
||||
that use the name of the deleted PriorityClass.
|
||||
{{< /note >}}
|
||||
|
||||
### Example PriorityClass
|
||||
|
||||
```yaml
|
||||
apiVersion: scheduling.k8s.io/v1alpha1
|
||||
kind: PriorityClass
|
||||
metadata:
|
||||
name: high-priority
|
||||
value: 1000000
|
||||
globalDefault: false
|
||||
description: "This priority class should be used for XYZ service pods only."
|
||||
```
|
||||
|
||||
## Pod priority
|
||||
|
||||
After you have one or more PriorityClasses, you can create Pods that specify one
|
||||
of those PriorityClass names in their specifications. The priority admission
|
||||
controller uses the `priorityClassName` field and populates the integer value
|
||||
of the priority. If the priority class is not found, the Pod is rejected.
|
||||
|
||||
The following YAML is an example of a Pod configuration that uses the PriorityClass
|
||||
created in the preceding example. The priority admission controller checks the
|
||||
specification and resolves the priority of the Pod to 1000000.
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
priorityClassName: high-priority
|
||||
```
|
||||
|
||||
### Effect of Pod priority on scheduling order
|
||||
|
||||
In Kubernetes 1.9 and later, when Pod priority is enabled, scheduler orders pending
|
||||
Pods by their priority and a pending Pod is placed ahead of other pending Pods with
|
||||
lower priority in the scheduling queue. As a result, the higher priority Pod may
|
||||
by scheduled sooner that Pods with lower priority if its scheduling requirements
|
||||
are met. If such Pod cannot be scheduled, scheduler will continue and tries to
|
||||
schedule other lower priority Pods.
|
||||
|
||||
## Preemption
|
||||
|
||||
When Pods are created, they go to a queue and wait to be scheduled. The scheduler
|
||||
picks a Pod from the queue and tries to schedule it on a Node. If no Node is found
|
||||
that satisfies all the specified requirements of the Pod, preemption logic is triggered
|
||||
for the pending Pod. Let's call the pending Pod P. Preemption logic tries to find a Node
|
||||
where removal of one or more Pods with lower priority than P would enable P to be scheduled
|
||||
on that Node. If such a Node is found, one or more lower priority Pods get
|
||||
deleted from the Node. After the Pods are gone, P can be scheduled on the Node.
|
||||
|
||||
### User exposed information
|
||||
|
||||
When Pod P preempts one or more Pods on Node N, `nominatedNodeName` field of Pod P's status is set to
|
||||
the name of Node N. This field helps scheduler track resources reserved for Pod P and also gives
|
||||
users information about preemptions in their clusters.
|
||||
|
||||
Please note that Pod P is not necessarily scheduled to the "nominated Node". After victim Pods are
|
||||
preempted, they get their graceful termination period. If another node becomes available while
|
||||
scheduler is waiting for the victim Pods to terminate, scheduler will use the other node to schedule
|
||||
Pod P. As a result `nominatedNodeName` and `nodeName` of Pod spec are not always the same. Also, if
|
||||
scheduler preempts Pods on Node N, but then a higher priority Pod than Pod P arrives, scheduler may
|
||||
give Node N to the new higher priority Pod. In such a case, scheduler clears `nominatedNodeName` of
|
||||
Pod P. By doing this, scheduler makes Pod P eligible to preempt Pods on another Node.
|
||||
|
||||
### Limitations of preemption
|
||||
|
||||
#### Graceful termination of preemption victims
|
||||
|
||||
When Pods are preempted, the victims get their
|
||||
[graceful termination period](https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods).
|
||||
They have that much time to finish their work and exit. If they don't, they are
|
||||
killed. This graceful termination period creates a time gap between the point
|
||||
that the scheduler preempts Pods and the time when the pending Pod (P) can be
|
||||
scheduled on the Node (N). In the meantime, the scheduler keeps scheduling other
|
||||
pending Pods. As victims exit or get terminated, the scheduler tries to schedule
|
||||
Pods in the pending queue. Therefore, there is usually a time gap between the point
|
||||
that scheduler preempts victims and the time that Pod P is scheduled. In order to
|
||||
minimize this gap, one can set graceful termination period of lower priority Pods
|
||||
to zero or a small number.
|
||||
|
||||
#### PodDisruptionBudget is supported, but not guaranteed!
|
||||
|
||||
A [Pod Disruption Budget (PDB)](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/)
|
||||
allows application owners to limit the number Pods of a replicated application that
|
||||
are down simultaneously from voluntary disruptions. Kubernetes 1.9 supports PDB
|
||||
when preempting Pods, but respecting PDB is best effort. The Scheduler tries to
|
||||
find victims whose PDB are not violated by preemption, but if no such victims are
|
||||
found, preemption will still happen, and lower priority Pods will be removed
|
||||
despite their PDBs being violated.
|
||||
|
||||
#### Inter-Pod affinity on lower-priority Pods
|
||||
|
||||
A Node is considered for preemption only when
|
||||
the answer to this question is yes: "If all the Pods with lower priority than
|
||||
the pending Pod are removed from the Node, can the pending Pod be scheduled on
|
||||
the Node?"
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Preemption does not necessarily remove all lower-priority Pods. If the
|
||||
pending Pod can be scheduled by removing fewer than all lower-priority Pods, then
|
||||
only a portion of the lower-priority Pods are removed. Even so, the answer to the
|
||||
preceding question must be yes. If the answer is no, the Node is not considered
|
||||
for preemption.
|
||||
{{< /note >}}
|
||||
|
||||
If a pending Pod has inter-pod affinity to one or more of the lower-priority Pods
|
||||
on the Node, the inter-Pod affinity rule cannot be satisfied in the absence of those
|
||||
lower-priority Pods. In this case, the scheduler does not preempt any Pods on the
|
||||
Node. Instead, it looks for another Node. The scheduler might find a suitable Node
|
||||
or it might not. There is no guarantee that the pending Pod can be scheduled.
|
||||
|
||||
Our recommended solution for this problem is to create inter-Pod affinity only towards
|
||||
equal or higher priority Pods.
|
||||
|
||||
#### Cross node preemption
|
||||
|
||||
Suppose a Node N is being considered for preemption so that a pending Pod P
|
||||
can be scheduled on N. P might become feasible on N only if a Pod on another
|
||||
Node is preempted. Here's an example:
|
||||
|
||||
* Pod P is being considered for Node N.
|
||||
* Pod Q is running on another Node in the same Zone as Node N.
|
||||
* Pod P has Zone-wide anti-affinity with Pod Q
|
||||
(`topologyKey: failure-domain.beta.kubernetes.io/zone`).
|
||||
* There are no other cases of anti-affinity between Pod P and other Pods in the Zone.
|
||||
* In order to schedule Pod P on Node N, Pod Q can be preempted, but scheduler
|
||||
does not perform cross-node preemption. So, Pod P will be deemed unschedulable
|
||||
on Node N.
|
||||
|
||||
If Pod Q were removed from its Node, the Pod anti-affinity violation would be gone,
|
||||
and Pod P could possibly be scheduled on Node N.
|
||||
|
||||
We may consider adding cross Node preemption in future versions if we find an
|
||||
algorithm with reasonable performance. We cannot promise anything at this point,
|
||||
and cross Node preemption will not be considered a blocker for Beta or GA.
|
||||
|
||||
{{% /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,752 @@
|
||||
---
|
||||
reviewers:
|
||||
- mikedanese
|
||||
title: Secrets
|
||||
---
|
||||
|
||||
Objects of type `secret` are intended to hold sensitive information, such as
|
||||
passwords, OAuth tokens, and ssh keys. Putting this information in a `secret`
|
||||
is safer and more flexible than putting it verbatim in a `pod` definition or in
|
||||
a docker image. See [Secrets design document](https://git.k8s.io/community/contributors/design-proposals/auth/secrets.md) for more information.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview of Secrets
|
||||
|
||||
A Secret is an object that contains a small amount of sensitive data such as
|
||||
a password, a token, or a key. Such information might otherwise be put in a
|
||||
Pod specification or in an image; putting it in a Secret object allows for
|
||||
more control over how it is used, and reduces the risk of accidental exposure.
|
||||
|
||||
Users can create secrets, and the system also creates some secrets.
|
||||
|
||||
To use a secret, a pod needs to reference the secret.
|
||||
A secret can be used with a pod in two ways: as files in a [volume](/docs/concepts/storage/volumes/) mounted on one or more of
|
||||
its containers, or used by kubelet when pulling images for the pod.
|
||||
|
||||
### Built-in Secrets
|
||||
|
||||
#### Service Accounts Automatically Create and Attach Secrets with API Credentials
|
||||
|
||||
Kubernetes automatically creates secrets which contain credentials for
|
||||
accessing the API and it automatically modifies your pods to use this type of
|
||||
secret.
|
||||
|
||||
The automatic creation and use of API credentials can be disabled or overridden
|
||||
if desired. However, if all you need to do is securely access the apiserver,
|
||||
this is the recommended workflow.
|
||||
|
||||
See the [Service Account](/docs/tasks/configure-pod-container/configure-service-account/) documentation for more
|
||||
information on how Service Accounts work.
|
||||
|
||||
### Creating your own Secrets
|
||||
|
||||
#### Creating a Secret Using kubectl create secret
|
||||
|
||||
Say that some pods need to access a database. The
|
||||
username and password that the pods should use is in the files
|
||||
`./username.txt` and `./password.txt` on your local machine.
|
||||
|
||||
```shell
|
||||
# Create files needed for rest of example.
|
||||
$ echo -n 'admin' > ./username.txt
|
||||
$ echo -n '1f2d1e2e67df' > ./password.txt
|
||||
```
|
||||
|
||||
The `kubectl create secret` command
|
||||
packages these files into a Secret and creates
|
||||
the object on the Apiserver.
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
|
||||
secret "db-user-pass" created
|
||||
```
|
||||
|
||||
You can check that the secret was created like this:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Note that neither `get` nor `describe` shows the contents of the file by default.
|
||||
This is to protect the secret from being exposed accidentally to someone looking
|
||||
or from being stored in a terminal log.
|
||||
|
||||
See [decoding a secret](#decoding-a-secret) for how to see the contents.
|
||||
|
||||
#### Creating a Secret Manually
|
||||
|
||||
You can also create a secret object in a file first,
|
||||
in json or yaml format, and then create that object.
|
||||
|
||||
Each item must be base64 encoded:
|
||||
|
||||
```shell
|
||||
$ echo -n 'admin' | base64
|
||||
YWRtaW4=
|
||||
$ echo -n '1f2d1e2e67df' | base64
|
||||
MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
Now write a secret object that looks like this:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mysecret
|
||||
type: Opaque
|
||||
data:
|
||||
username: YWRtaW4=
|
||||
password: MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
The data field is a map. Its keys must consist of alphanumeric characters, '-', '_' or '.'. The values are arbitrary data, encoded using base64.
|
||||
|
||||
Create the secret using [`kubectl create`](/docs/reference/generated/kubectl/kubectl-commands#create):
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./secret.yaml
|
||||
secret "mysecret" created
|
||||
```
|
||||
|
||||
**Encoding Note:** The serialized JSON and YAML values of secret data are
|
||||
encoded as base64 strings. Newlines are not valid within these strings and must
|
||||
be omitted. When using the `base64` utility on Darwin/OS X users should avoid
|
||||
using the `-b` option to split long lines. Conversely Linux users *should* add
|
||||
the option `-w 0` to `base64` commands or the pipeline `base64 | tr -d '\n'` if
|
||||
`-w` option is not available.
|
||||
|
||||
#### Decoding a Secret
|
||||
|
||||
Secrets can be retrieved via the `kubectl get secret` command. For example, to retrieve the secret created in the previous section:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Decode the password field:
|
||||
|
||||
```shell
|
||||
$ echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
### Using Secrets
|
||||
|
||||
Secrets can be mounted as data volumes or be exposed as environment variables to
|
||||
be used by a container in a pod. They can also be used by other parts of the
|
||||
system, without being directly exposed to the pod. For example, they can hold
|
||||
credentials that other parts of the system should use to interact with external
|
||||
systems on your behalf.
|
||||
|
||||
#### Using Secrets as Files from a Pod
|
||||
|
||||
To consume a Secret in a volume in a Pod:
|
||||
|
||||
1. Create a secret or use an existing one. Multiple pods can reference the same secret.
|
||||
1. Modify your Pod definition to add a volume under `spec.volumes[]`. Name the volume anything, and have a `spec.volumes[].secret.secretName` field equal to the name of the secret object.
|
||||
1. Add a `spec.containers[].volumeMounts[]` to each container that needs the secret. Specify `spec.containers[].volumeMounts[].readOnly = true` and `spec.containers[].volumeMounts[].mountPath` to an unused directory name where you would like the secrets to appear.
|
||||
1. Modify your image and/or command line so that the program looks for files in that directory. Each key in the secret `data` map becomes the filename under `mountPath`.
|
||||
|
||||
This is an example of a pod that mounts a secret in a volume:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Each secret you want to use needs to be referred to in `spec.volumes`.
|
||||
|
||||
If there are multiple containers in the pod, then each container needs its
|
||||
own `volumeMounts` block, but only one `spec.volumes` is needed per secret.
|
||||
|
||||
You can package many files into one secret, or use many secrets, whichever is convenient.
|
||||
|
||||
**Projection of secret keys to specific paths**
|
||||
|
||||
We can also control the paths within the volume where Secret keys are projected.
|
||||
You can use `spec.volumes[].secret.items` field to change target path of each 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
|
||||
```
|
||||
|
||||
What will happen:
|
||||
|
||||
* `username` secret is stored under `/etc/foo/my-group/my-username` file instead of `/etc/foo/username`.
|
||||
* `password` secret is not projected
|
||||
|
||||
If `spec.volumes[].secret.items` is used, only keys specified in `items` are projected.
|
||||
To consume all keys from the secret, all of them must be listed in the `items` field.
|
||||
All listed keys must exist in the corresponding secret. Otherwise, the volume is not created.
|
||||
|
||||
**Secret files permissions**
|
||||
|
||||
You can also specify the permission mode bits files part of a secret will have.
|
||||
If you don't specify any, `0644` is used by default. You can specify a default
|
||||
mode for the whole secret volume and override per key if needed.
|
||||
|
||||
For example, you can specify a default mode like this:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Then, the secret will be mounted on `/etc/foo` and all the files created by the
|
||||
secret volume mount will have permission `0400`.
|
||||
|
||||
Note that the JSON spec doesn't support octal notation, so use the value 256 for
|
||||
0400 permissions. If you use yaml instead of json for the pod, you can use octal
|
||||
notation to specify permissions in a more natural way.
|
||||
|
||||
You can also use mapping, as in the previous example, and specify different
|
||||
permission for different files like this:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
In this case, the file resulting in `/etc/foo/my-group/my-username` will have
|
||||
permission value of `0777`. Owing to JSON limitations, you must specify the mode
|
||||
in decimal notation.
|
||||
|
||||
Note that this permission value might be displayed in decimal notation if you
|
||||
read it later.
|
||||
|
||||
**Consuming Secret Values from Volumes**
|
||||
|
||||
Inside the container that mounts a secret volume, the secret keys appear as
|
||||
files and the secret values are base-64 decoded and stored inside these files.
|
||||
This is the result of commands
|
||||
executed inside the container from the example above:
|
||||
|
||||
```shell
|
||||
$ ls /etc/foo/
|
||||
username
|
||||
password
|
||||
$ cat /etc/foo/username
|
||||
admin
|
||||
$ cat /etc/foo/password
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
The program in a container is responsible for reading the secrets from the
|
||||
files.
|
||||
|
||||
**Mounted Secrets are updated automatically**
|
||||
|
||||
When a secret being already consumed in a volume is updated, projected keys are eventually updated as well.
|
||||
Kubelet is checking whether the mounted secret is fresh on every periodic sync.
|
||||
However, it is using its local ttl-based cache for getting the current value of the secret.
|
||||
As a result, the total delay from the moment when the secret is updated to the moment when new keys are
|
||||
projected to the pod can be as long as kubelet sync period + ttl of secrets cache in kubelet.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** A container using a Secret as a
|
||||
[subPath](/docs/concepts/storage/volumes#using-subpath) volume mount will not receive
|
||||
Secret updates.
|
||||
{{< /note >}}
|
||||
|
||||
#### Using Secrets as Environment Variables
|
||||
|
||||
To use a secret in an environment variable in a pod:
|
||||
|
||||
1. Create a secret or use an existing one. Multiple pods can reference the same secret.
|
||||
1. Modify your Pod definition in each container that you wish to consume the value of a secret key to add an environment variable for each secret key you wish to consume. The environment variable that consumes the secret key should populate the secret's name and key in `env[].valueFrom.secretKeyRef`.
|
||||
1. Modify your image and/or command line so that the program looks for values in the specified environment variables
|
||||
|
||||
This is an example of a pod that uses secrets from environment variables:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Consuming Secret Values from Environment Variables**
|
||||
|
||||
Inside a container that consumes a secret in an environment variables, the secret keys appear as
|
||||
normal environment variables containing the base-64 decoded values of the secret data.
|
||||
This is the result of commands executed inside the container from the example above:
|
||||
|
||||
```shell
|
||||
$ echo $SECRET_USERNAME
|
||||
admin
|
||||
$ echo $SECRET_PASSWORD
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
#### Using imagePullSecrets
|
||||
|
||||
An imagePullSecret is a way to pass a secret that contains a Docker (or other) image registry
|
||||
password to the Kubelet so it can pull a private image on behalf of your Pod.
|
||||
|
||||
**Manually specifying an imagePullSecret**
|
||||
|
||||
Use of imagePullSecrets is described in the [images documentation](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod)
|
||||
|
||||
### Arranging for imagePullSecrets to be Automatically Attached
|
||||
|
||||
You can manually create an imagePullSecret, and reference it from
|
||||
a serviceAccount. Any pods created with that serviceAccount
|
||||
or that default to use that serviceAccount, will get their imagePullSecret
|
||||
field set to that of the service account.
|
||||
See [Add ImagePullSecrets to a service account](/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account)
|
||||
for a detailed explanation of that process.
|
||||
|
||||
### Automatic Mounting of Manually Created Secrets
|
||||
|
||||
Manually created secrets (e.g. one containing a token for accessing a github account)
|
||||
can be automatically attached to pods based on their service account.
|
||||
See [Injecting Information into Pods Using a PodPreset](/docs/tasks/inject-data-application/podpreset/) for a detailed explanation of that process.
|
||||
|
||||
## Details
|
||||
|
||||
### Restrictions
|
||||
|
||||
Secret volume sources are validated to ensure that the specified object
|
||||
reference actually points to an object of type `Secret`. Therefore, a secret
|
||||
needs to be created before any pods that depend on it.
|
||||
|
||||
Secret API objects reside in a namespace. They can only be referenced by pods
|
||||
in that same namespace.
|
||||
|
||||
Individual secrets are limited to 1MB in size. This is to discourage creation
|
||||
of very large secrets which would exhaust apiserver and kubelet memory.
|
||||
However, creation of many smaller secrets could also exhaust memory. More
|
||||
comprehensive limits on memory usage due to secrets is a planned feature.
|
||||
|
||||
Kubelet only supports use of secrets for Pods it gets from the API server.
|
||||
This includes any pods created using kubectl, or indirectly via a replication
|
||||
controller. It does not include pods created via the kubelets
|
||||
`--manifest-url` flag, its `--config` flag, or its REST API (these are
|
||||
not common ways to create pods.)
|
||||
|
||||
Secrets must be created before they are consumed in pods as environment
|
||||
variables unless they are marked as optional. References to Secrets that do not exist will prevent
|
||||
the pod from starting.
|
||||
|
||||
References via `secretKeyRef` to keys that do not exist in a named Secret
|
||||
will prevent the pod from starting.
|
||||
|
||||
Secrets used to populate environment variables via `envFrom` that have keys
|
||||
that are considered invalid environment variable names will have those keys
|
||||
skipped. The pod will be allowed to start. There will be an event whose
|
||||
reason is `InvalidVariableNames` and the message will contain the list of
|
||||
invalid keys that were skipped. The example shows a pod which refers to the
|
||||
default/mysecret that contains 2 invalid keys, 1badkey and 2alsobad.
|
||||
|
||||
```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 and Pod Lifetime interaction
|
||||
|
||||
When a pod is created via the API, there is no check whether a referenced
|
||||
secret exists. Once a pod is scheduled, the kubelet will try to fetch the
|
||||
secret value. If the secret cannot be fetched because it does not exist or
|
||||
because of a temporary lack of connection to the API server, kubelet will
|
||||
periodically retry. It will report an event about the pod explaining the
|
||||
reason it is not started yet. Once the secret is fetched, the kubelet will
|
||||
create and mount a volume containing it. None of the pod's containers will
|
||||
start until all the pod's volumes are mounted.
|
||||
|
||||
## Use cases
|
||||
|
||||
### Use-Case: Pod with ssh keys
|
||||
|
||||
Create a secret containing some ssh keys:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
**Security Note:** think carefully before sending your own ssh keys: other users of the cluster may have access to the secret. Use a service account which you want to be accessible to all the users with whom you share the Kubernetes cluster, and can revoke if they are compromised.
|
||||
|
||||
|
||||
Now we can create a pod which references the secret with the ssh key and
|
||||
consumes it in a volume:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
When the container's command runs, the pieces of the key will be available in:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/ssh-publickey
|
||||
/etc/secret-volume/ssh-privatekey
|
||||
```
|
||||
|
||||
The container is then free to use the secret data to establish an ssh connection.
|
||||
|
||||
### Use-Case: Pods with prod / test credentials
|
||||
|
||||
This example illustrates a pod which consumes a secret containing prod
|
||||
credentials and another pod which consumes a secret with test environment
|
||||
credentials.
|
||||
|
||||
Make the secrets:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Now make the pods:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
Both containers will have the following files present on their filesystems with the values for each container's environment:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/username
|
||||
/etc/secret-volume/password
|
||||
```
|
||||
|
||||
Note how the specs for the two pods differ only in one field; this facilitates
|
||||
creating pods with different capabilities from a common pod config template.
|
||||
|
||||
You could further simplify the base pod specification by using two Service Accounts:
|
||||
one called, say, `prod-user` with the `prod-db-secret`, and one called, say,
|
||||
`test-user` with the `test-db-secret`. Then, the pod spec can be shortened to, for example:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Use-case: Dotfiles in secret volume
|
||||
|
||||
In order to make piece of data 'hidden' (i.e., in a file whose name begins with a dot character), simply
|
||||
make that key begin with a dot. For example, when the following secret is mounted into a volume:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
|
||||
The `secret-volume` will contain a single file, called `.secret-file`, and
|
||||
the `dotfile-test-container` will have this file present at the path
|
||||
`/etc/secret-volume/.secret-file`.
|
||||
|
||||
**NOTE**
|
||||
|
||||
Files beginning with dot characters are hidden from the output of `ls -l`;
|
||||
you must use `ls -la` to see them when listing directory contents.
|
||||
|
||||
|
||||
### Use-case: Secret visible to one container in a pod
|
||||
|
||||
Consider a program that needs to handle HTTP requests, do some complex business
|
||||
logic, and then sign some messages with an HMAC. Because it has complex
|
||||
application logic, there might be an unnoticed remote file reading exploit in
|
||||
the server, which could expose the private key to an attacker.
|
||||
|
||||
This could be divided into two processes in two containers: a frontend container
|
||||
which handles user interaction and business logic, but which cannot see the
|
||||
private key; and a signer container that can see the private key, and responds
|
||||
to simple signing requests from the frontend (e.g. over localhost networking).
|
||||
|
||||
With this partitioned approach, an attacker now has to trick the application
|
||||
server into doing something rather arbitrary, which may be harder than getting
|
||||
it to read a file.
|
||||
|
||||
<!-- TODO: explain how to do this while still using automation. -->
|
||||
|
||||
## Best practices
|
||||
|
||||
### Clients that use the secrets API
|
||||
|
||||
When deploying applications that interact with the secrets API, access should be
|
||||
limited using [authorization policies](
|
||||
https://kubernetes.io/docs/admin/authorization/) such as [RBAC](
|
||||
https://kubernetes.io/docs/admin/authorization/rbac/).
|
||||
|
||||
Secrets often hold values that span a spectrum of importance, many of which can
|
||||
cause escalations within Kubernetes (e.g. service account tokens) and to
|
||||
external systems. Even if an individual app can reason about the power of the
|
||||
secrets it expects to interact with, other apps within the same namespace can
|
||||
render those assumptions invalid.
|
||||
|
||||
For these reasons `watch` and `list` requests for secrets within a namespace are
|
||||
extremely powerful capabilities and should be avoided, since listing secrets allows
|
||||
the clients to inspect the values of all secrets that are in that namespace. The ability to
|
||||
`watch` and `list` all secrets in a cluster should be reserved for only the most
|
||||
privileged, system-level components.
|
||||
|
||||
Applications that need to access the secrets API should perform `get` requests on
|
||||
the secrets they need. This lets administrators restrict access to all secrets
|
||||
while [white-listing access to individual instances](
|
||||
https://kubernetes.io/docs/admin/authorization/rbac/#referring-to-resources) that
|
||||
the app needs.
|
||||
|
||||
For improved performance over a looping `get`, clients can design resources that
|
||||
reference a secret then `watch` the resource, re-requesting the secret when the
|
||||
reference changes. Additionally, a ["bulk watch" API](
|
||||
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/bulk_watch.md)
|
||||
to let clients `watch` individual resources has also been proposed, and will likely
|
||||
be available in future releases of Kubernetes.
|
||||
|
||||
## Security Properties
|
||||
|
||||
### Protections
|
||||
|
||||
Because `secret` objects can be created independently of the `pods` that use
|
||||
them, there is less risk of the secret being exposed during the workflow of
|
||||
creating, viewing, and editing pods. The system can also take additional
|
||||
precautions with `secret` objects, such as avoiding writing them to disk where
|
||||
possible.
|
||||
|
||||
A secret is only sent to a node if a pod on that node requires it. It is not
|
||||
written to disk. It is stored in a tmpfs. It is deleted once the pod that
|
||||
depends on it is deleted.
|
||||
|
||||
On most Kubernetes-project-maintained distributions, communication between user
|
||||
to the apiserver, and from apiserver to the kubelets, is protected by SSL/TLS.
|
||||
Secrets are protected when transmitted over these channels.
|
||||
|
||||
Secret data on nodes is stored in tmpfs volumes and thus does not come to rest
|
||||
on the node.
|
||||
|
||||
There may be secrets for several pods on the same node. However, only the
|
||||
secrets that a pod requests are potentially visible within its containers.
|
||||
Therefore, one Pod does not have access to the secrets of another pod.
|
||||
|
||||
There may be several containers in a pod. However, each container in a pod has
|
||||
to request the secret volume in its `volumeMounts` for it to be visible within
|
||||
the container. This can be used to construct useful [security partitions at the
|
||||
Pod level](#use-case-secret-visible-to-one-container-in-a-pod).
|
||||
|
||||
### Risks
|
||||
|
||||
- In the API server secret data is stored as plaintext in etcd; therefore:
|
||||
- Administrators should limit access to etcd to admin users
|
||||
- Secret data in the API server is at rest on the disk that etcd uses; admins may want to wipe/shred disks
|
||||
used by etcd when no longer in use
|
||||
- If you configure the secret through a manifest (JSON or YAML) file which has
|
||||
the secret data encoded as base64, sharing this file or checking it in to a
|
||||
source repository means the secret is compromised. Base64 encoding is not an
|
||||
encryption method and is considered the same as plain text.
|
||||
- Applications still need to protect the value of secret after reading it from the volume,
|
||||
such as not accidentally logging it or transmitting it to an untrusted party.
|
||||
- A user who can create a pod that uses a secret can also see the value of that secret. Even
|
||||
if apiserver policy does not allow that user to read the secret object, the user could
|
||||
run a pod which exposes the secret.
|
||||
- If multiple replicas of etcd are run, then the secrets will be shared between them.
|
||||
By default, etcd does not secure peer-to-peer communication with SSL/TLS, though this can be configured.
|
||||
- Currently, anyone with root on any node can read any secret from the apiserver,
|
||||
by impersonating the kubelet. It is a planned feature to only send secrets to
|
||||
nodes that actually require them, to restrict the impact of a root exploit on a
|
||||
single node.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** As of 1.7 [encryption of secret data at rest is supported](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).
|
||||
{{< /note >}}
|
||||
@@ -0,0 +1,280 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
- kevin-wangzefeng
|
||||
- bsalamat
|
||||
title: Taints and Tolerations
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Concepts
|
||||
|
||||
You add a taint to a node using [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint).
|
||||
For example,
|
||||
|
||||
```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.
|
||||
|
||||
To remove the taint added by the command above, you can run:
|
||||
```shell
|
||||
kubectl taint nodes node1 key:NoSchedule-
|
||||
```
|
||||
|
||||
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`:
|
||||
|
||||
```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.
|
||||
|
||||
**NOTE:** There are two special cases:
|
||||
|
||||
* An empty `key` with operator `Exists` matches all keys, values and effects which means this
|
||||
will tolerate everything.
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- operator: "Exists"
|
||||
```
|
||||
|
||||
* An empty `effect` matches all effects with key `key`.
|
||||
|
||||
```yaml
|
||||
tolerations:
|
||||
- key: "key"
|
||||
operator: "Exists"
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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,
|
||||
|
||||
* 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).
|
||||
|
||||
For example, imagine you taint a node like this
|
||||
|
||||
```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:
|
||||
|
||||
```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.
|
||||
|
||||
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,
|
||||
|
||||
```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.
|
||||
|
||||
## 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
|
||||
|
||||
* **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/admin/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`.
|
||||
|
||||
* **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/admin/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/admin/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.
|
||||
|
||||
* **Taint based Evictions (alpha feature)**: A per-pod-configurable eviction behavior
|
||||
when there are node problems, which is described in the next section.
|
||||
|
||||
## Taint based Evictions
|
||||
|
||||
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
|
||||
|
||||
In addition, Kubernetes 1.6 has alpha
|
||||
support for representing node problems. In other words, the node controller
|
||||
automatically taints a node when certain condition is true. The built-in taints
|
||||
currently include:
|
||||
|
||||
* `node.kubernetes.io/not-ready`: Node is not ready. This corresponds to
|
||||
the NodeCondition `Ready` being "`False`".
|
||||
* `node.alpha.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.cloudprovider.kubernetes.io/uninitialized`: When kubelet is started
|
||||
with "external" cloud provider, it sets this taint on a node to mark it
|
||||
as unusable. When a controller from the cloud-controller-manager initializes
|
||||
this node, kubelet removes this 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.
|
||||
(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.)
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
```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`.
|
||||
|
||||
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).
|
||||
|
||||
[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.
|
||||
|
||||
## Taint Nodes by Condition
|
||||
|
||||
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.
|
||||
|
||||
To make sure that turning on this feature doesn't break DaemonSets, starting in version 1.8, the DaemonSet controller automatically adds the following `NoSchedule` tolerations to all daemons:
|
||||
|
||||
* `node.kubernetes.io/memory-pressure`
|
||||
* `node.kubernetes.io/disk-pressure`
|
||||
* `node.kubernetes.io/out-of-disk` (*only for critical pods*)
|
||||
|
||||
The above settings ensure backward compatibility, but we understand they may not fit all user's needs, which is why
|
||||
cluster admin may choose to add arbitrary tolerations to DaemonSets.
|
||||
Reference in New Issue
Block a user