Merge pull request #43368 from flant/ru_docs_assign-pod-node

[ru] Localize assign-pod-node.md, reference/issues-security/*.md. Add examples/pods/*.yaml
pull/45528/head
Kubernetes Prow Robot 2024-03-11 13:11:07 -07:00 committed by GitHub
commit c4dba04d38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 1095 additions and 0 deletions

View File

@ -0,0 +1,503 @@
---
title: Распределение подов по узлам
content_type: concept
weight: 20
---
<!-- overview -->
Можно настроить {{< glossary_tooltip text="под" term_id="pod" >}} так, чтобы тот мог запускаться олько_ на определенном(-ых) {{< glossary_tooltip text="узле(-ах)" term_id="node" >}} или _предпочитал_ определенную группу узлов.
Сделать это можно несколькими способами, при этом все рекомендуемые подходы используют [селекторы лейблов](/ru/docs/concepts/overview/working-with-objects/labels/) для выбора.
Зачастую нужды в подобных ограничениях нет; {{< glossary_tooltip text="планировщик" term_id="kube-scheduler" >}} автоматически размещает поды оптимальным образом (например, распределяет их по узлам, чтобы они не оказались все на одном узле с дефицитом ресурсов).
Однако в некоторых обстоятельствах возможность контролировать, куда именно попадет под, может пригодиться. Например, она поможет запланировать под на узел с быстрым SSD-хранилищем или разместить два активно взаимодействующих друг с другом пода в одной зоне доступности.
<!-- body -->
Для планирования подов на определенные узлы можно использовать любой из методов:
* Поле [nodeSelector](#nodeselector) и [лейблы узлов](#built-in-node-labels);
* Правила [совместного/раздельного существования (affinity и anti-affinity)](#affinity-and-anti-affinity);
* Поле [nodeName](#nodename);
* [Ограничения на топологию распределения подов](#pod-topology-spread-constraints).
## Лейблы узлов {#built-in-node-labels}
Как и у многих других объектов Kubernetes, у узлов есть [лейблы](/ru/docs/concepts/overview/working-with-objects/labels/). Их можно [навешивать вручную](/docs/tasks/configure-pod-container/assign-pods-nodes/#add-a-label-to-a-node).
Kubernetes также навешивает [стандартный набор лейблов](/docs/reference/node/node-labels/) на все узлы кластера.
{{<note>}}
Значения этих лейблов зависят от облачного провайдера, поэтому на них нельзя полагаться.
Например, в одних окружениях значение `kubernetes.io/hostname` может совпадать с именем узла, в других — отличаться.
{{</note>}}
### Изоляция узла/ограничение его использования
Лейблы узлов позволяют размещать поды на определенные узлы или группы узлов. С их помощью можно планировать поды на узлы с определенными требованиями к изоляции, безопасности или соответствию нормативным положениям.
При использовании лейблов для изоляции узлов следует выбирать ключи лейблов, которые {{<glossary_tooltip text="kubelet" term_id="kubelet">}} не может изменить. В этом случае взломанный узел не сможет навесить на себя эти лейблы в надежде, что планировщик разместит на него рабочие нагрузки.
[Admission-плагин NodeRestriction](/docs/reference/access-authn-authz/admission-controllers/#noderestriction) не позволяет kubelet'у устанавливать или изменять лейблы с префиксом `node-restriction.kubernetes.io/`.
Чтобы использовать этот префикс для изоляции узла:
1. Убедитесь, что используется [авторизатор узлов](/docs/reference/access-authn-authz/node/) и _включен_ admission-плагин `NodeRestriction`.
2. Добавьте лейблы с префиксом `node-restriction.kubernetes.io/` к узлам и используйте их в [селекторах узлов](#nodeselector). Например, `example.com.node-restriction.kubernetes.io/fips=true` или `example.com.node-restriction.kubernetes.io/pci-dss=true`.
## nodeSelector
`nodeSelector` — простейшая рекомендуемая форма настроек выбора узлов.
Можно добавить поле `nodeSelector` в спецификацию пода и перечислить в нем [лейблы узлов](#built-in-node-labels), которые подходят для развертывания пода. В этом случае Kubernetes будет планировать под только на узлы со всеми указанными лейблами.
Дополнительную информацию см. в разделе [Размещение подов на узлах](/docs/tasks/configure-pod-container/assign-pods-nodes).
## Правила совместного/раздельного существования (affinity и anti-affinity) {#affinity-and-anti-affinity}
`nodeSelector` — самый простой способ развернуть поды на узлах с определенными лейблами. Правила совместного/раздельного существования расширяют типы ограничений, которые можно накладывать. Вот некоторые из их преимуществ:
* Язык правил affinity/anti-affinity более выразителен. `nodeSelector` выбирает узлы только со всеми указанными лейблами. Правила affinity/anti-affinity расширяют логику выбора и делают ее более гибкой.
* Правило может быть *мягким* (soft) или *предпочтительным* (preferred). В этом случае планировщик все равно запланирует под, даже если подходящего узла для него не найдется.
* При планировании пода планировщик может учитывать лейблы других подов, запущенных на узле (или в иной топологической области), а не только лейблы самого узла. Это позволяет формулировать правила, определяющие сосуществование подов на узле.
Правила совместного существования (affinity) бывают двух типов:
* *Правила для узлов* (node affinity) работают подобно полю `nodeSelector`, но более выразительны. Кроме того, можно задавать мягкие правила.
* *Правила для подов* (inter-pod affinity и anti-affinity) позволяют при планировании учитывать лейблы других подов.
### Правила совместного существования для узлов (node affinity) {#node-affinity}
Правила совместного существования для узлов концептуально похожи на `nodeSelector`. С помощью лейблов они позволяют ограничивать список узлов, на которые может быть запланирован под. Существует два типа таких правил:
* `requiredDuringSchedulingIgnoredDuringExecution`: Планировщик не может запланировать под, если правило не выполнено. Работает как `nodeSelector`, но с более выразительным синтаксисом.
* `preferredDuringSchedulingIgnoredDuringExecution`: Планировщик пытается найти узел, который соответствует правилу. Если подходящий узел не удается найти, планировщик все равно планирует под.
{{<note>}}
В типах выше `IgnoredDuringExecution` означает, что под продолжит свою работу, если лейблы узлов изменятся после того, как Kubernetes запланировал его.
{{</note>}}
Задавать правила совместного существования для узлов можно с помощью поля `.spec.affinity.nodeAffinity` в спецификации пода.
В качестве примера рассмотрим следующую спецификацию пода:
{{< codenew file="pods/pod-with-node-affinity.yaml" >}}
В этом примере применяются следующие правила:
* У узла *должен* быть лейбл с ключом `topology.kubernetes.io/zone`, и значение этого лейбла *должно* быть либо `antarctica-east1`, либо `antarctica-west1`.
* *Предпочтительно*, чтобы у узла был лейбл с ключом `another-node-label-key` и значением `another-node-label-value`.
Можно использовать поле `operator` для указания логического оператора, который Kubernetes будет применять при интерпретации правил. Доступны `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt` и `Lt`.
Узнать больше о том, как они работают, можно в подразделе [Операторы](/#operators).
`NotIn` и `DoesNotExist` позволяют задавать правила раздельного существования (anti-affinity) для узла.
Кроме того, можно использовать [taint'ы узлов](/docs/concepts/scheduling-eviction/taint-and-toleration/), чтобы "отвадить" поды от определенных узлов.
{{<note>}}
Когда указаны и `nodeSelector`, и `nodeAffinity`, под будет запланирован на узел только в том случае, если *оба* этих условия удовлетворены.
Если указать несколько условий `nodeSelectorTerms`, привязанных к типам `nodeAffinity`, то под может быть запланирован на узел, если удовлетворяется одно из указанных условий `nodeSelectorTerms`. К условиям применяется логическое ИЛИ.
Если задать несколько выражений в поле `matchExpressions` для одного условия `nodeSelectorTerms`, под будет запланирован на узел только если удовлетворены все выражения `matchExpressions`. К условиям применяется логическое И.
{{</note>}}
Дополнительную информацию см. в разделе [Размещаем поды на узлы с помощью Node Affinity](/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/).
#### Вес правил совместного существования
Для каждого правила типа `preferredDuringSchedulingIgnoredDuringExecution` можно указать вес `weight` в диапазоне от 1 до 100. Найдя несколько узлов, удовлетворяющих всем остальным требованиям для планирования пода, планировщик перебирает предпочтительные правила, которым удовлетворяет узел, и суммирует их веса.
Итоговая сумма добавляется к оценке, полученной при анализе других параметров, влияющих на приоритет узла. Принимая решение о размещении пода, планировщик отдает предпочтение узлам с наибольшей суммарной оценкой.
В качестве примера рассмотрим следующую спецификацию пода:
{{< codenew file="pods/pod-with-affinity-anti-affinity.yaml" >}}
Если правилу `preferredDuringSchedulingIgnoredDuringExecution` соответствуют два узла (один — с лейблом `label-1:key-1`, другой — с `label-2:key-2`), планировщик считает вес `weight` каждого узла и добавляет его к другим оценкам для этого узла. Под планируется на узел с наивысшей итоговой оценкой.
{{<note>}}
Чтобы Kubernetes смог запланировать поды в этом примере, необходимо, чтобы существовали узлы с лейблом `kubernetes.io/os=linux`.
{{</note>}}
#### Правила совместного существования и профили планирования
{{< feature-state for_k8s_version="v1.20" state="beta" >}}
При настройке нескольких [профилей планирования](/docs/reference/scheduling/config/#multiple-profiles) можно связать профиль с правилами совместного существования для узлов (это удобно, когда профиль применяется к определенному набору узлов). Для этого необходимо добавить `addedAffinity` в поле `args` [плагина `NodeAffinity`](/docs/reference/scheduling/config/#scheduling-plugins) в [конфигурации планировщика](/docs/reference/scheduling/config/). Например:
```yaml
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
- schedulerName: foo-scheduler
pluginConfig:
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: scheduler-profile
operator: In
values:
- foo
```
Правило `addedAffinity` применяется ко всем подам с полем `.spec.schedulerName`, имеющим значение `foo-scheduler`, в дополнение к NodeAffinity, заданному в PodSpec. Таким образом, подходящие для пода узлы должны удовлетворять параметрам `addedAffinity` и правилам `.spec.NodeAffinity` пода.
Поскольку конечные пользователи не видят `addedAffinity`, результат применения этих правил может быть для них неожиданным. Используйте лейблы узлов, которые однозначно соотносятся с именем профиля планировщика.
{{< note >}}
Контроллер DaemonSet, [создающий поды для DaemonSet'ов](/docs/concepts/workloads/controllers/daemonset/#scheduled-by-default-scheduler), не поддерживает профили планирования. Контроллер DaemonSet создает поды, а штатный планировщик Kubernetes, размещая их, следит за соблюдением правил `nodeAffinity`.
{{< /note >}}
### Правила совместного/раздельного существования подов
Правила совместного/раздельного существования подов позволяют выбирать узлы для планирования в зависимости от лейблов **подов**, которые уже на этих узлах работают (вместо лейблов самих узлов).
Алгоритм работы правил совместного/раздельного существования подов можно описать так: "данный под олжен_ (или е должен_ в случае раздельного (anti-affinity) существования) размещаться на X, если на нем уже работает один или несколько подов, удовлетворяющих правилу Y", где X — топологический домен, например, узел, стойка, зона/регион облачного провайдера и т. п., а Y — правило, которое Kubernetes пытается удовлетворить.
Для задания правил Y используются [селекторы лейблов](/ru/docs/concepts/overview/working-with-objects/labels/#селекторы-меток) с необязательным связанным списком пространств имен. Для подов в Kubernetes указываются пространства имен, соответственно, их лейблы также оказываются неявно связаны с этими же пространствами имен. Любые селекторы лейблов для лейблов подов должны содержать пространства имен, в которых Kubernetes должен искать эти лейблы.
Топологический домен X задается с помощью `topologyKey` — ключа для лейбла узла, который система использует для обозначения домена. Примеры см. в разделе [Типичные лейблы, аннотации и taint'ы](/docs/reference/labels-annotations-taints/).
{{< note >}}
Обработка правил совместного/раздельного существования подов требует значительных ресурсов и может значительно замедлить планирование в больших кластерах. Их не рекомендуется использовать в кластерах, число узлов в которых превышает несколько сотен.
{{< /note >}}
{{< note >}}
Правила раздельного существования для подов требуют согласованности лейблов узлов. Другими словами, у каждого узла в кластере должен быть лейбл, относящий его к определенному ключу `topologyKey`. Отсутствие лейблов `topologyKey` у некоторых или всех узлов в кластере может привести к непредсказуемому поведению.
{{< /note >}}
#### Типы правил совместного/раздельного существования подов
По аналогии [c правилами для узлов](#node-affinity) существует два типа правил для подов:
* `requiredDuringSchedulingIgnoredDuringExecution`
* `preferredDuringSchedulingIgnoredDuringExecution`
Например, с помощью правила совместного существования `requiredDuringSchedulingIgnoredDuringExecution` можно заставить планировщик размещать поды, относящиеся к разным сервисам, в одной зоне облачного провайдера, поскольку они активно обмениваются данными друг с другом.
Аналогичным образом можно использовать правило раздельного существования `preferredDuringSchedulingIgnoredDuringExecution` для распределения подов по нескольким зонам облачного провайдера.
Для задания правил совместного существования предназначено поле `affinity.podAffinity` в спецификации пода.
Для задания правил раздельного существования предназначено поле `affinity.podAntiAffinity` в спецификации пода.
#### Планирование группы подов, связанных правилами совместного существования
Если планируемый под — первый в серии подов, связанных правилами совместного существования,
он может быть запланирован, если удовлетворит всем остальным правилам совместного существования. Чтобы подтвердить, что этот под — действительно первый,
проводится проверка, которая должна показать, что пространство имен и селектор этого пода уникальны в кластере (то есть нет других таких подов). Кроме того,
под должен соответствовать своим собственным правилам, а выбранный узел — всем запрошенным топологиям.
Это предотвращает тупиковую ситуацию, когда поды не могут запланироваться из-за того, что все они связаны правилами совместного существования.
#### Пример правил совместного/раздельного существования для пода {#an-example-of-a-pod-that-uses-pod-affinity}
Рассмотрим следующую спецификацию пода:
{{< codenew file="pods/pod-with-pod-affinity.yaml" >}}
В примере задается одно правило совместного существования подов, и одно — раздельного. Для совместного правила используется жесткий тип `requiredDuringSchedulingIgnoredDuringExecution`, для раздельного — мягкий `preferredDuringSchedulingIgnoredDuringExecution`.
Правило совместного существования гласит, что планировщик может разместить под на узел, только если тот находится в зоне с одним или более подами с лейблом `security=S1`.
Например, если есть кластер с выделенной зоной, назовем ее "V",
состоящей из узлов с лейблом `topology.kubernetes.io/zone=V`, планировщик может
назначить под на любой узел зоны V только если в этой зоне уже есть хотя бы один под
с лейблом `security=S1`. И наоборот, если в зоне V нет подов с лейблом `security=S1`,
планировщик не сможет назначить под на какой-либо из узлов в этой зоне.
Правило раздельного существования гласит, что планировщик при возможности не должен размещать под на узел, если тот находится в зоне с одним или более подами с лейблом `security=S2`.
Например, если есть кластер с выделенной зоной, назовем ее "R",
состоящей из узлов с лейблами `topology.kubernetes.io/zone=R`. Планировщик должен избегать
назначать поды на узлы из зоны R, если в ней уже есть по крайней мере один под
с лейблом `security=S2`. Соответственно, если в зоне R нет подов с лейблами `security=S2`,
правило раздельного существования не будет влиять на планирование подов в эту зону.
Больше примеров правил совместного/раздельного существования для подов можно найти в [рабочей документации](https://git.k8s.io/design-proposals-archive/scheduling/podaffinity.md).
Поле `operator` пода поддерживает значения `In`, `NotIn`, `Exists` и `DoesNotExist` при задании правил совместного/раздельного существования.
Узнать больше о том, как они работают, можно в подразделе [Операторы](/#operators).
В принципе, `topologyKey` может быть любым разрешенным лейблом-ключом со следующими исключениями по соображениям производительности и безопасности:
* При задании правил совместного/раздельного существования для подов пустое поле `topologyKey` не допускается как для `requiredDuringSchedulingIgnoredDuringExecution`, так и для `preferredDuringSchedulingIgnoredDuringExecution`.
* Для правил раздельного существования типа `requiredDuringSchedulingIgnoredDuringExecution` admission-контроллер разрешает использовать только `kubernetes.io/hostname` в качестве `topologyKey`. Для работы с кастомными топологиями admission-контроллер можно дополнить или совсем отключить его.
В дополнение к `labelSelector` и `topologyKey` можно опционально указать список пространств имен, которые должен выбирать `labelSelector`, с помощью поля `namespaces` на том же уровне, что `labelSelector` и `topologyKey`. Если поле `namespaces` опущено или пусто, по умолчанию выбирается пространство имен пода, в котором задаются правила совместного/раздельного существования.
#### Селектор пространств имен
{{< feature-state for_k8s_version="v1.24" state="stable" >}}
Подходящие пространства имен также можно выбрать с помощью `namespaceSelector`, который попытается найти лейбл в наборе пространств имен.
Условия совместного существования применяются к пространствам имен, выбранным как селектором `namespaceSelector`, так и полем `namespaces`.
Обратите внимание, что пустой селектор `namespaceSelector` ({}) выбирает все пространства имен, в то время как пустой или null-список `namespaces` и null-селектор `namespaceSelector` выбирает пространство имен пода, в котором правило задано.
#### matchLabelKeys
{{< feature-state feature_gate_name="MatchLabelKeysInPodAffinity" >}}
{{< note >}}
<!-- UPDATE THIS WHEN PROMOTING TO BETA -->
Поле `matchLabelKeys` является полем альфа-уровня и по умолчанию отключено в
Kubernetes {{< skew currentVersion >}}.
Включить его можно с помощью [переключателя функциональности](/docs/reference/command-line-tools-reference/feature-gates/)
(feature gate) `MatchLabelKeysInPodAffinity`.
{{< /note >}}
Kubernetes включает необязательное поле `matchLabelKeys` для правил совместного (раздельного) существования подов.
В нем указываются ключи для лейблов, которые должны совпадать с лейблами входящего пода,
чтобы правила совместного (раздельного) существования выполнялись.
Ключи используются для поиска значений в лейблах подов; эти ключи-лейблы объединяются (с помощью `AND`)
с ограничениями, задаваемыми с помощью поля `labelSelector`. Такая комбинированная фильтрация позволяет отобрать
набор существующих подов, которые приниматься в расчет при обработке правил совместного (раздельного) существования.
Обычно `matchLabelKeys` используется вместе с `pod-template-hash` (задается для подов,
которые управляются как часть деплоймента, где значение уникально для каждой ревизии).
Использование `pod-template-hash` в `matchLabelKeys` позволяет нацеливаться на поды, принадлежащие
к той же ревизии, что и входящий под. Таким образом, что скользящее обновление не нарушит правила совместного существования.
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: application-server
...
spec:
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- database
topologyKey: topology.kubernetes.io/zone
# При расчете affinity подов учитываются только поды из определенного выката.
# При обновлении Deployment'а новые поды будут следовать своим собственным правилам совместного существования
# (если они заданы в новом шаблоне подов)
matchLabelKeys:
- pod-template-hash
```
#### mismatchLabelKeys
{{< feature-state feature_gate_name="MatchLabelKeysInPodAffinity" >}}
{{< note >}}
<!-- UPDATE THIS WHEN PROMOTING TO BETA -->
Поле `mismatchLabelKeys` является полем альфа-уровня и по умолчанию отключено в
Kubernetes {{< skew currentVersion >}}.
Включить его можно с помощью [переключателя функциональности](/docs/reference/command-line-tools-reference/feature-gates/)
(feature gate) `MatchLabelKeysInPodAffinity`.
{{< /note >}}
Kubernetes включает необязательное поле `mismatchLabelKeys` для определения правил совместного (раздельного) существования подов.
В поле указываются ключи для лейблов, которые **не** должны совпадать с лейблами входящего пода,
чтобы правила совместного (раздельного) существования подов удовлетворялись.
Один из примеров использования — размещение подов определенной группы пользователей (tenant'ов) или команды в конкретном топологическом домене (узле, зоне и т. д.).
То есть идея в том, чтобы избежать одновременного запуска подов от разных групп пользователей в одном топологическом домене.
```yaml
apiVersion: v1
kind: Pod
metadata:
labels:
# Assume that all relevant Pods have a "tenant" label set
tenant: tenant-a
...
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# следим за тем, чтобы поды, связанные с этим тенантом, попадали на нужный пул узлов
- matchLabelKeys:
- tenant
topologyKey: node-pool
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# следим за тем, чтобы поды, связанные с этим тенантом, не смогли планироваться на узлы для другого тенанта
- mismatchLabelKeys:
- tenant # значение лейбла "tenant" этого пода будет предотвращать
# планирование на узлы в пулах, на которых работают поды
# другого тенанта
labelSelector:
# Должен быть labelSelector, который выбирает поды с лейблом tenant,
# иначе этот под также будет "ненавидеть" поды из daemonset'ов, например,
# те, у которых нет лейбла tenant.
matchExpressions:
- key: tenant
operator: Exists
topologyKey: node-pool
```
#### Другие примеры использования
Правила совместного/раздельного существования для подов особенно удобны, когда используются совместно с абстракциями более высокого уровня, такими как ReplicaSet, StatefulSet, Deployment и т. д. Эти правила позволяют настроить размещение рабочих нагрузок с учетом имеющейся топологии; например, пара связанных подов будет планироваться на один и тот же узел.
Представьте кластер, состоящий из трех узлов. Он используется для запуска веб-приложения и как in-memory-кэш (например, Redis). Предположим, что задержка между веб-приложением и кэшем должна быть минимальной. Правила совместного/раздельного существования для подов позволяют настроить планировщик так, чтобы тот размещал веб-серверы как можно ближе к кэшу.
В приведенном ниже примере конфигурации деплоймента с Redis его реплики получают лейбл `app=store`. Правило `podAntiAffinity` запрещает планировщику размещать несколько реплик с лейблом `app=store` на одном узле. В результате каждый узел получает по отдельной кэш-реплике.
```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
```
Конфигурация деплоймента, приведенная ниже, создает три реплики веб-сервера с лейблом `app=web-store`.
Правило совместного существования предписывает планировщику размещать каждую реплику на узле, на котором уже имеется под с лейблом `app=store`. В то же время правило раздельного существования запрещает планировщику размещать несколько серверов с лейблом `app=web-store` на одном узле.
```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.16-alpine
```
Развертывание ресурсов в соответствии с приведенными выше конфигурациями приведет к созданию кластера, в котором на каждом узле будет по одному веб-серверу и одной реплике Redis (всего три отдельных узла):
| узел 1 | узел 2 | узел 3 |
|:--------------------:|:-------------------:|:------------------:|
| *webserver-1* | *webserver-2* | *webserver-3* |
| *cache-1* | *cache-2* | *cache-3* |
В итоге к каждому инстансу Redis'а, скорее всего, будет обращаться клиент, который работает с ним на том же узле. Подобный подход позволит минимизировать как перекос (дисбаланс нагрузки), так и задержки.
Правила совместного/раздельного существования для подов можно использовать и в других случаях.
См., например, [руководство по ZooKeeper](/docs/tutorials/stateful-application/zookeeper/#tolerating-node-failure). В нем с помощью правил раздельного существования StatefulSet настраивается так, чтобы обеспечить высокую доступность (используется подход, аналогичный тому, что применен выше).
## nodeName
Поле `nodeName` в спецификации пода — более непосредственный способ выбора узлов по сравнению с правилами совместного существования или селектором `nodeSelector`. Если поле `nodeName` не пустое, планировщик игнорирует под, а kubelet на узле с соответствующим именем пытается разместить под на этом узле. Приоритет поля `nodeName` выше, чем селектора `nodeSelector` или правил совместного/раздельного существования.
Однако у `nodeName` имеются и некоторые недостатки:
- Если узел с заданным именем не существует, под не будет запущен. Кроме того, в некоторых случаях он может быть автоматически удален.
- Если на узле с заданным именем недостаточно ресурсов для работы пода, последний будет остановлен; соответствующая причина (например, OutOfmemory или OutOfcpu) будет указана.
- В облачных окружениях имена узлов не всегда предсказуемы или стабильны.
{{< note >}}
Поле `nodeName` предназначено для использования в кастомных планировщиках или в продвинутых случаях,
когда необходимо обойти настроенные планировщики. Обход планировщиков может привести к тому, что поды не будут запущены,
если целевые узлы окажутся перегруженными. С помощью правила [совместного существования (affinity) узла](#node-affinity) или поля [`nodeselector`](#nodeselector) под можно назначить на определенный узел, не обходя планировщики с помощью `nodeName`.
{{</ note >}}
Ниже приведен пример спецификации пода с полем `nodeName`:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
```
Такой под будет работать только на узле с именем `kube-01`.
## Ограничения на топологию распределения подов
С помощью _ограничений на топологию распределения_ (_topology spread constraints_) можно настроить размещение {{< glossary_tooltip text="подов" term_id="Pod" >}} в кластере по failure-доменам, таким как регионы, зоны, узлы, или любым другим заданным топологическим конфигурациям. Это позволяет повысить производительность, ожидаемую доступность или эффективность использования ресурсов.
Дополнительные сведения о принципах их работы читайте в разделе [Ограничения на топологию распределения подов](/docs/concepts/scheduling-eviction/topology-spread-constraints/).
## Операторы {#operators}
Ниже приведены все логические операторы, которые можно использовать в поле `operator` для `nodeAffinity` и `podAffinity`.
| Оператор | Действие |
| :------------: | :-------------: |
| `In` | Значение лейбла присутствует в предоставленном наборе строк |
| `NotIn` | Значение лейбла отсутствует в предоставленном наборе строк |
| `Exists` | Лейбл с таким ключом существует для объекта |
| `DoesNotExist` | У объекта не существует лейбла с таким ключом |
Следующие операторы могут использоваться только с `nodeAffinity`.
| Оператор | Действие |
| :------------: | :-------------: |
| `Gt` | Введенное значение будет обработано как целое число, и это целое число меньше, чем целое число, полученное в результате обработки значения лейбла, указанного этим селектором |
| `Lt` | Введенное значение будет обработано как целое число, и это целое число больше, чем целое число, полученное в результате обработки значения лейбла, указанного этим селектором |
{{<note>}}
Операторы `Gt` и `Lt` не работают с нецелыми значениями. Если заданное значение
не является целым числом, под не будет запланирован. Кроме того, `Gt` и `Lt`
недоступны для `podAffinity`.
{{</note>}}
## {{% heading "whatsnext" %}}
* Дополнительная информация о [taint'ах и toleration'ах](/docs/concepts/scheduling-eviction/taint-and-toleration/).
* Рабочая документация по правилам [совместного существования для узлов](https://git.k8s.io/design-proposals-archive/scheduling/nodeaffinity.md) и по правилам [совместного/раздельного существования для подов](https://git.k8s.io/design-proposals-archive/scheduling/podaffinity.md).
* [Информация о том](/docs/tasks/administer-cluster/topology-manager/), как менеджер топологии участвует в принятии решений о распределении ресурсов на уровне узлов.
* Подробнее об использовании [селектора nodeSelector](/docs/tasks/configure-pod-container/assign-pods-nodes/).
* Подробнее об использовании правил [совместного/раздельного существования](/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/).

View File

@ -0,0 +1,4 @@
---
title: Проблемы и безопасность Kubernetes
weight: 70
---

View File

@ -0,0 +1,15 @@
---
title: Трекер задач (Issues) Kubernetes
weight: 10
aliases: [/cve/,/cves/]
---
Чтобы сообщить о проблеме в области безопасности, воспользуйтесь процедурой [раскрытия информации о безопасности Kubernetes](/ru/docs/reference/issues-security/security/#report-a-vulnerability).
Механизм [GitHub Issues](https://github.com/kubernetes/kubernetes/issues/) позволяет работать с кодом Kubernetes и отслеживать активные задачи.
* Официальный [список известных CVE](/ru/docs/reference/issues-security/official-cve-feed/)
(уязвимостей в области безопасности), которые были обнародованы [Комитетом по реагированию на угрозы в области безопасности Kubernetes](https://github.com/kubernetes/committee-security-response).
* [Issues на GitHub, связанные с CVE](https://github.com/kubernetes/kubernetes/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Aarea%2Fsecurity+in%3Atitle+CVE)
Связанные с безопасностью анонсы публикуются в рассылке [kubernetes-security-announce@googlegroups.com](https://groups.google.com/forum/#!forum/kubernetes-security-announce).

View File

@ -0,0 +1,47 @@
---
title: Официальный CVE-фид
linkTitle: CVE-фид
weight: 25
outputs:
- json
- html
- rss
layout: cve-feed
---
{{< feature-state for_k8s_version="v1.27" state="beta" >}}
Поддерживаемый сообществом список официальных CVE, анонсированных
Комитетом по реагированию на проблемы безопасности Kubernetes. Подробности см. на странице
[Общие сведения о безопасности Kubernetes и раскрытии информации](/ru/docs/reference/issues-security/security/).
Проект Kubernetes публикует фиды с анонсами проблем в области безопасности в формате [JSON](/docs/reference/issues-security/official-cve-feed/index.json) и [RSS](/docs/reference/issues-security/official-cve-feed/feed.xml), доступные для автоматического считывания. Доступ к ним можно получить, выполнив следующие команды:
{{< tabs name="CVE-фиды" >}}
{{% tab name="JSON-фид" %}}
[Ссылка на JSON-формат](/docs/reference/issues-security/official-cve-feed/index.json)
```shell
curl -Lv https://k8s.io/docs/reference/issues-security/official-cve-feed/index.json
```
{{% /tab %}}
{{% tab name="RSS-фид" %}}
[Ссылка на RSS-формат](/docs/reference/issues-security/official-cve-feed/feed.xml)
```shell
curl -Lv https://k8s.io/docs/reference/issues-security/official-cve-feed/feed.xml
```
{{% /tab %}}
{{< /tabs >}}
{{< cve-feed >}}
<!-- | CVE ID | Краткое описание проблемы | Ссылка на Issue на GitHub'е |
| ----------- | ----------- | --------- |
| [CVE-2021-25741](https://www.cve.org/CVERecord?id=CVE-2021-25741) | Symlink Exchange Can Allow Host Filesystem Access | [#104980](https://github.com/kubernetes/kubernetes/issues/104980) |
| [CVE-2020-8565](https://www.cve.org/CVERecord?id=CVE-2020-8565) | Incomplete fix for CVE-2019-11250 allows for token leak in logs when logLevel >= 9 | [#95623](https://github.com/kubernetes/kubernetes/issues/95623) | -->
Список автоматически обновляется с заметной, но небольшой задержкой (от нескольких минут до нескольких часов)
с момента анонса CVE до момента его появления в этом фиде.
В качестве источника используется набор GitHub Issues, отфильтрованный по контролируемому и
ограниченному лейблу `official-cve-feed`. Исходные данные хранятся в бакете Google Cloud,
право на запись в который есть только у небольшого числа доверенных представителей сообщества.

View File

@ -0,0 +1,55 @@
---
title: Общие сведения о безопасности Kubernetes и раскрытии информации
aliases: [/security/]
reviewers:
- eparis
- erictune
- philips
- jessfraz
content_type: concept
weight: 20
---
<!-- overview -->
На этой странице приводятся общие сведения о безопасности Kubernetes и раскрытии информации, имеющей к ней отношение.
<!-- body -->
## Анонсы в области безопасности
Информация о проблемах в области безопасности и ключевых изменениях API доступна в рассылке [kubernetes-security-announce](https://groups.google.com/forum/#!forum/kubernetes-security-announce).
## Сообщить об уязвимости
Мы искренне признательны исследователям в области безопасности и пользователям, которые передают информацию об уязвимостях в Open Source-сообщество Kubernetes. Все отчеты тщательно изучаются группой добровольцев сообщества.
Чтобы создать отчет, отправьте свою уязвимость в [Bug Bounty-программу Kubernetes](https://hackerone.com/kubernetes). Это позволит отследить и обработать уязвимость в стандартные сроки.
Также можно оправить [стандартное письмо об ошибках Kubernetes](https://github.com/kubernetes/kubernetes/blob/master/.github/ISSUE_TEMPLATE/bug-report.yaml) с описанием проблемы с безопасностью и ее подробностями в закрытый список [security@kubernetes.io](mailto:security@kubernetes.io).
Письмо можно зашифровать, используя GPG-ключи [членов Комитета по безопасности](https://git.k8s.io/security/README.md#product-security-committee-psc). Шифрование с использованием GPG НЕ является обязательным.
### Когда следует сообщать об уязвимости
- Вы думаете, что обнаружили уязвимость в безопасности Kubernetes.
- Вы не уверены, как именно уязвимость повлияет на Kubernetes.
- Вы думаете, что обнаружили уязвимость в другом проекте, от которого зависит работа Kubernetes.
- Если у проекта имеется собственный регламент регистрации и раскрытия информации об уязвимостях, пожалуйста, следуйте ему и пишите сразу в проект.
### Когда НЕ следует сообщать об уязвимости
- Вам нужна помощь в настройке компонентов Kubernetes для обеспечения безопасности.
- Вам нужна помощь в применении обновлений, связанных с безопасностью.
- Проблема не связана с безопасностью.
## Реагирование на уязвимости в области безопасности
Каждый отчет об уязвимости подтверждается и анализируется членами Комитета по реагированию на угрозы безопасности в течение 3 рабочих дней. После этого [запускается соответствующая процедура](https://git.k8s.io/security/security-release-process.md#disclosures).
Любая информация об уязвимостях, переданная Комитету по реагированию на угрозы безопасности, остается внутри проекта Kubernetes и не передается в другие проекты, если только этого не требуется для устранения проблемы.
Автору отчета будет сообщено о результатах триажа и дальнейших шагах по подготовке исправления и планированию релиза.
## Сроки раскрытия информации
Дата публичного раскрытия согласовывается Комитетом по реагированию на угрозы безопасности Kubernetes и автором отчета об уязвимости. Мы предпочитаем полностью раскрывать информацию об обнаруженной проблеме сразу после того, как станет понятно, какие шаги необходимо предпринять для устранения ее последствий. Разумно отложить раскрытие информации, если проблема или порядок дальнейших шагов не до конца понятны, решение плохо протестировано или необходима координация действий вендоров. Срок раскрытия информации варьируется от незамедлительного (особенно если она уже широко известна) до нескольких недель. Для "простых" уязвимостей с момента подачи отчета до даты раскрытия обычно проходит около 7 дней. Комитет по реагированию на угрозы безопасности сохраняет последнее слово при определении даты раскрытия информации.

View File

@ -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

View File

@ -0,0 +1,30 @@
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
# Эти контейнеры запускаются во время инициализации пода
initContainers:
- name: install
image: busybox:1.28
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://info.cern.ch
volumeMounts:
- name: workdir
mountPath: "/work-dir"
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]

View File

@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/echo", "$(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_LEVEL
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_TYPE
restartPolicy: Never

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never

View File

@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL
path: keys
restartPolicy: Never

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# Укажите имя ConfigMap с файлами, которые вы хотите
# добавить в контейнер
name: special-config
restartPolicy: Never

View File

@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

View File

@ -0,0 +1,18 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: foo-node # запланировать под на конкретный узел
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

View File

@ -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

View File

@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault

View File

@ -0,0 +1,23 @@
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
# Задать переменную окружения
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# ConfigMap со значением, которое вы хотите присвоить SPECIAL_LEVEL_KEY
name: special-config
# Укажите ключ, привязанный к значению
key: special.how
restartPolicy: Never

View File

@ -0,0 +1,32 @@
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-anti-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: label-1
operator: In
values:
- key-1
- weight: 50
preference:
matchExpressions:
- key: label-2
operator: In
values:
- key-2
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:2.0

View File

@ -0,0 +1,26 @@
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:2.0

View File

@ -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: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: registry.k8s.io/pause:2.0

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
schedulingGates:
- name: example.com/foo
- name: example.com/bar
containers:
- name: pause
image: registry.k8s.io/pause:3.6

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "example-key"
operator: "Exists"
effect: "NoSchedule"

View File

@ -0,0 +1,8 @@
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: pause
image: registry.k8s.io/pause:3.6

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox:1.28
securityContext:
capabilities:
add:
- SYS_PTRACE
stdin: true
tty: true

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

View File

@ -0,0 +1,27 @@
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
restartPolicy: Never
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: userns
spec:
hostUsers: false
containers:
- name: shell
command: ["sleep", "infinity"]
image: debian