- PVSM.RU - https://www.pvsm.ru -
Прим. перев.: эта статья, написанная SRE-инженером из LinkedIn, в деталях рассказывает о той «внутренней магии» в Kubernetes — точнее, взаимодействии CRI, CNI и kube-apiserver, — что происходит, когда очередному pod'у требуется назначить IP-адрес.
Одно из базовых требований сетевой модели Kubernetes [1] состоит в том, что у каждого pod'а должен быть свой собственный IP-адрес и любой другой pod в кластере должен иметь возможность связаться с ним по этому адресу. Есть множество сетевых «провайдеров» (Flannel, Calico, Canal и т.п.), которые помогают реализовать данную сетевую модель.
Когда я только начинал работать с Kubernetes, мне было не совсем ясно, как именно pod'ы получают свои IP-адреса. Даже с пониманием, как функционируют отдельные компоненты, было сложно представить их совместную работу. Например, я знал, для чего нужны плагины CNI, но не представлял, как именно они вызываются. Поэтому решил написать эту статью, чтобы поделиться знаниями о различных сетевых компонентах и их совместной работе в кластере Kubernetes, которая и позволяет каждому pod'у получить свой уникальный IP-адрес.
Существуют различные способы организации сетевого взаимодействия в Kubernetes — аналогично тому, как и различные варианты исполняемых сред (runtime) для контейнеров. В этой публикации будет использоваться Flannel [2] для организации сети в кластере, а в качестве исполняемой среды — Containerd [3]. Также я исхожу из предположения, что вы знаете, как устроено сетевое взаимодействие между контейнерами, поэтому лишь вкратце затрону его, исключительно для контекста.
В интернете достаточно отличных публикаций, объясняющих, как контейнеры связываются друг с другом по сети. Поэтому проведу лишь общий обзор основных понятий и ограничусь одним подходом, подразумевающим создание Linux-моста и инкапсуляцию пакетов. Подробности опущены, поскольку сама тема сетевого взаимодействия контейнеров заслуживает отдельной статьи. Ссылки на некоторые особенно содержательные и познавательные публикации будут приведены ниже.
Один из способов организации связи по IP-адресам между контейнерами, работающими на одном и том же хосте, предполагает создание Linux-моста. Для этого в Kubernetes (и Docker) создаются виртуальные устройства veth (virtual ethernet) [4]. Один конец veth-устройства подключается к сетевому пространству имен контейнера, другой — к Linux-мосту [5] в сети хоста.
У всех контейнеров на одном хосте один из концов veth подключен к мосту, через который они могут связываться друг с другом по IP-адресам. У Linux-моста также имеется IP-адрес, и он выступает в качестве шлюза для исходящего (egress) трафика из pod'ов, предназначенного для других узлов.
Инкапсуляция пакетов — один из способов, позволяющий контейнерам на разных узлах связываться друг с другом по IP-адресам. Во Flannel за эту возможность отвечает технология vxlan [6], которая «упаковывает» исходный пакет в пакет UDP и затем отправляет его по назначению.
В кластере Kubernetes Flannel создает устройство vxlan и соответствующим образом дополняет таблицу маршрутов на каждом из узлов. Каждый пакет, предназначенный для контейнера на другом хосте, проходит через устройство vxlan и инкапсулируется в пакет UDP. В пункте назначения вложенный пакет извлекается и перенаправляется на нужный pod.
Примечание: Это лишь один из способов организации сетевого взаимодействия между контейнерами.
CRI (Container Runtime Interface) [7] — это плагин, позволяющий kubelet'у использовать разные исполняемые среды контейнеров. API CRI встроен в различные исполняемые среды, поэтому пользователи могут выбирать runtime по своему усмотрению.
Проект CNI [8] представляет собой спецификацию [9] для организации универсального сетевого решения для Linux-контейнеров. Кроме того, он включает в себя плагины [10], отвечающие за различные функции при настройке сети pod'а. Плагин CNI — это исполняемый файл, соответствующи спецификации (некоторые плагины мы обсудим ниже).
Поскольку каждый pod кластера должен иметь IP-адрес, важно убедиться в том, чтобы этот адрес был уникальным. Это достигается путем выделения каждому узлу уникальной подсети, из которой затем pod'ам на этом узле назначаются IP-адреса.
Когда nodeipam
передается в качестве параметра флага --controllers
kube-controller-manager'а [11], он каждому узлу выделяет отдельную подсеть (podCIDR) из CIDR кластера (т.е. диапазона IP-адресов для сети кластера). Поскольку эти podCIDR'ы не пересекаются, становится возможным каждому pod'у выделить уникальный IP-адрес.
Узлу Kubernetes присваивается podCIDR в момент его начальной регистрации в кластере. Чтобы изменить podCIDR у узлов, необходимо их дерегистрировать и затем повторно зарегистрировать, в промежутке внеся соответствующие изменения в конфигурацию управляющего слоя Kubernetes. Вывести podCIDR узла можно с помощью следующей команды:
$ kubectl get no <nodeName> -o json | jq '.spec.podCIDR'
10.244.0.0/24
Планирование pod'а на узел связано с выполнением множества подготовительных действий. В этом разделе я сконцентрируюсь только на тех из них, которые непосредственно связаны с настройкой сети pod'а.
Планирование pod'а на некий узел запускает следующую цепочку событий:
Справка: Архитектура CRI-плагинов Containerd [12].
У каждого сетевого провайдера имеется свой плагин CNI. Runtime контейнера запускает его, чтобы сконфигурировать сеть для pod'a в процессе его запуска. В случае containerd запуском CNI-плагина занимается плагин Containerd CRI [13].
При этом у каждого провайдера есть свой агент. Он устанавливается во все узлы Kubernetes и отвечает за сетевую настройку pod'ов. Этот агент идет либо в комплекте с конфигом CNI, либо самостоятельно создает его на узле. Конфиг помогает CRI-плагину установить, какой плагин CNI вызывать.
Местонахождение конфига CNI можно настроить; по умолчанию он лежит в /etc/cni/net.d/<config-file>
. Администраторы кластера также отвечают за установку плагинов CNI на каждый узел кластера. Их местонахождение также настраивается; директория по умолчанию — /opt/cni/bin
.
При использовании containerd пути для конфига и бинарников плагина можно задать в разделе [plugins.«io.containerd.grpc.v1.cri».cni]
в файле конфигурации containerd [14].
Поскольку мы используем Flannel в качестве сетевого провайдера, давайте немного поговорим о его настройке:
install-cni
в качестве init-контейнера [15]. Install-cni
создает файл конфигурации CNI [16] (/etc/cni/net.d/10-flannel.conflist
) на каждом узле.Для получения более подробной информации о работе Flannel рекомендую воспользоваться ссылками в конце статьи.
Вот схема взаимодействия между плагином Containerd CRI и плагинами CNI:
Как видно выше, kubelet вызывает плагин Containerd CRI, чтобы создать pod, а тот уже вызывает плагин CNI для настройки сети pod'а. При этом CNI-плагин сетевого провайдера вызывает другие базовые плагины CNI для настройки различных аспектов сети.
Существуют различные плагины CNI, задача которых — помочь настроить сетевое взаимодействие между контейнерами на хосте. В этой статье речь пойдет о трех из них.
При использовании Flannel в качестве сетевого провайдера компонент Containerd CRI вызывает CNI-плагин Flannel [17], используя конфигурационный файл CNI /etc/cni/net.d/10-flannel.conflist
.
$ cat /etc/cni/net.d/10-flannel.conflist
{
"name": "cni0",
"plugins": [
{
"type": "flannel",
"delegate": {
"ipMasq": false,
"hairpinMode": true,
"isDefaultGateway": true
}
}
]
}
CNI-плагин Flannel работает совместно с Flanneld. Во время запуска Flanneld извлекает podCIDR и другие связанные с сетью подробности из API-сервера и сохраняет их в файл /run/flannel/subnet.env
.
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false
CNI-плагин Flannel использует данные из /run/flannel/subnet.env
для настройки и вызова CNI-плагина моста (bridge).
Этот плагин вызывается со следующей конфигурацией:
{
"name": "cni0",
"type": "bridge",
"mtu": 1450,
"ipMasq": false,
"isGateway": true,
"ipam": {
"type": "host-local",
"subnet": "10.244.0.0/24"
}
}
При первом вызове он создает Linux-мост с «name»: «cni0»
, что указывается в конфиге. Затем для каждого pod'а создается пара veth. Один ее конец подключается к сетевому пространству имен контейнера, другой входит в Linux-мост в сети хоста. CNI-плагин Bridge [18] подключает все контейнеры хоста к Linux-мосту в сети хоста.
Закончив с настройкой пары veth, плагин Bridge вызывает локальный для хоста (host-local) CNI-плагин IPAM. Тип IPAM-плагина можно настроить в конфиге CNI, который плагин CRI использует для вызова CNI-плагина Flannel.
Bridge CNI вызывает хост-локальный IPAM-плагин CNI [19] со следующей конфигурацией:
{
"name": "cni0",
"ipam": {
"type": "host-local",
"subnet": "10.244.0.0/24",
"dataDir": "/var/lib/cni/networks"
}
}
Host-local IPAM-плагин (IP Address Management — управление IP-адресами) возвращает IP-адрес для контейнера из подсети и сохраняет выделенный IP на хосте в директории, указанной в разделе dataDir
— /var/lib/cni/networks/<network-name=cni0>/<ip>
. В этом файле содержится ID контейнера, которому присвоен данный IP-адрес.
При вызове host-local IPAM-плагина он возвращает следующие данные:
{
"ip4": {
"ip": "10.244.4.2",
"gateway": "10.244.4.3"
},
"dns": {}
}
Kube-controller-manager каждому узлу присваивает podCIDR. Pod'ы каждого узла получают IP-адреса из пространства адресов в выделенном диапазоне podCIDR. Поскольку podCIDR'ы узлов не пересекаются, все pod'ы получают уникальные IP-адреса.
Администратор кластера Kubernetes настраивает и устанавливает kubelet, среду запуска контейнеров, агента сетевого провайдера и копирует плагины CNI на каждый узел. Во время старта агент сетевого провайдера генерирует конфиг CNI. Когда pod планируется на узел, kubelet вызывает CRI-плагин для его создания. Далее, если используется containerd, плагин Containerd CRI вызывает CNI-плагин, указанный в конфиге CNI, для настройки сети pod'а. В результате pod получает IP-адрес.
Мне потребовалось некоторое время, чтобы разобраться во всех тонкостях и нюансах всех этих взаимодействий. Надеюсь, полученный опыт поможет и вам лучше понять, как работает Kubernetes. Если я в чем-то ошибаюсь, пожалуйста, свяжитесь со мной в Twitter [20] или по адресу hello@ronaknathani.com [21]. Не стесняйтесь обращаться, если захотите обсудить аспекты этой статьи или что-нибудь другое. Я с удовольствием пообщаюсь с вами!
Читайте также в нашем блоге:
Автор: Василий Марютенков
Источник [30]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/357471
Ссылки в тексте:
[1] сетевой модели Kubernetes: https://kubernetes.io/docs/concepts/cluster-administration/networking/#the-kubernetes-network-model
[2] Flannel: https://github.com/coreos/flannel
[3] Containerd: https://github.com/containerd/containerd
[4] veth (virtual ethernet): https://man7.org/linux/man-pages/man4/veth.4.html
[5] Linux-мосту: https://wiki.archlinux.org/index.php/Network_bridge
[6] vxlan: https://vincent.bernat.ch/en/blog/2017-vxlan-linux
[7] CRI (Container Runtime Interface): https://github.com/kubernetes/cri-api
[8] Проект CNI: https://github.com/containernetworking/cni
[9] спецификацию: https://github.com/containernetworking/cni/blob/master/SPEC.md
[10] плагины: https://github.com/containernetworking/plugins
[11] kube-controller-manager'а: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/
[12] Архитектура CRI-плагинов Containerd: https://github.com/containerd/cri/blob/v1.11.1/docs/architecture.md
[13] Containerd CRI: https://github.com/containerd/cri
[14] файле конфигурации containerd: https://github.com/containerd/cri/blob/master/docs/config.md
[15] init-контейнера: https://github.com/coreos/flannel/blob/master/Documentation/kube-flannel.yml#L172
[16] файл конфигурации CNI: https://gist.github.com/ronaknnathani/957a56210bd4fbd8e11120273c6b4ede
[17] CNI-плагин Flannel: https://github.com/containernetworking/plugins/tree/master/plugins/meta/flannel
[18] CNI-плагин Bridge: https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge
[19] хост-локальный IPAM-плагин CNI: https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local
[20] Twitter: https://twitter.com/RonakNathani
[21] hello@ronaknathani.com: mailto:hello@ronaknathani.com
[22] A container networking overview: https://jvns.ca/blog/2016/12/22/container-networking/
[23] Demystifying container networking: https://blog.mbrt.dev/2017-10-01-demystifying-container-networking/
[24] Flannel Networking Demystify: https://msazure.club/flannel-networking-demystify/
[25] Kubernetes With Flannel — Understanding The Networking: https://medium.com/@anilkreddyr/kubernetes-with-flannel-understanding-the-networking-part-2-78b53e5364c7
[26] Calico для сети в Kubernetes: знакомство и немного из опыта: https://habr.com/ru/company/flant/blog/485716/
[27] части 1 и 2 (сетевая модель, оверлейные сети): https://habr.com/ru/company/flant/blog/346304/
[28] часть 3 (сервисы и обработка трафика): https://habr.com/ru/company/flant/blog/433382/
[29] Container Networking Interface (CNI) — сетевой интерфейс и стандарт для Linux-контейнеров: https://habr.com/ru/company/flant/blog/329830/
[30] Источник: https://habr.com/ru/post/521406/?utm_source=habrahabr&utm_medium=rss&utm_campaign=521406
Нажмите здесь для печати.