Эта статья для тех, кто ищет простое и понятное введение в организацию и управление кластерами Kubernetes или же хочет оптимизировать свой проект. Мы поговорим о тонкостях сетевых технологий Kubernetes и рассмотрим некоторые принципы и те механизмы, которые управляют взаимодействием между подами. Сетевую модель мы будем рассматривать, используя схему VirtualBox. Изучив настройки этого решения, предлагаемого пользователям по умолчанию, вы получите ясное представление о том, как осуществляется связь между подами в среде Kubernetes и сможете применить полученные знания на практике, так всё написанное будет подкреплено примерами. Но сначала немного теории.
Вместо жесткой сетевой реализации в Kubernetes используются стандарты CRI и CNI, предлагающие собственные плагины с множеством вариантов настройки кластера Kubernetes. Таким образом вместо единого инфраструктурного решения предлагается весьма широкий набор альтернативных. И каждое такое решение позволяет реализовать уникальную структуру кластерной сети. Это позволяет выбрать тот подход, который лучше всего соответствует вашим требованиям с учетом масштабируемости, производительности, отказоустойчивости, а также совместимости с вашей инфраструктурой. Конечно, такая вариативность несет с собой и ряд проблем с конкретными сетевыми решениями. Но при правильной настройке вы обеспечите оптимальную производительность своей сети, надежную связь и удобное управление своими кластерами.
Добавим, что оба стандарта предлагают несколько популярных решений. Если говорить о CRI, то это прежде всего containerd и cri-o, а у CNI есть Calico и Flannel. Все они предоставляют необходимые функции для сред выполнения контейнеров, позволяя вам выбирать параметры, которые лучше всего соответствуют вашим требованиям и предпочтениям. При этом данные плагины чаще всего не исключают, а дополняют друг друга. Разумеется, такие сочетания требуют некоторых усилий в плане конфигурирования, чтобы гарантировать стабильную работу всей сборки. И эту задачу существенно облегчают дистрибутивы, в которых чаще всего плагины CRI и CNI уже настроены должным образом для того, чтобы пользователь мог сразу же приступить непосредственно к настройке приложений Kubernetes.
Из платных дистрибутивов можно отметить, например, Red Hat Openshift, но есть и достаточно функциональные бесплатные продукты, и прежде всего это OKD, minikube, а также areguera-k8s-lab, на примере которого мы и будем учиться отслеживать межподовый трафик.
В vagrant-k8-lab
вшиты containerd
и Flannel на каждой ноде, что обеспечивает такую структуру:
Источник изображения: medium.com
Здесь следует отметить, что к каждому узлу в данном случае подключено сразу 4 интерфейса, eth0
, eth1
, cni0
и lo
. Каждый из них имеет свою цель, и сейчас мы их подробно разберем. А еще вы наверняка заметили, что в кластере уже развернуты несколько подов, которые также понадобятся нам для проведения последующих тестов.
Чтобы иметь возможность загружать образы контейнеров извне, плагину CRI требуется исходящий трафик. Менеджеру пакетов ОС также нужно получать доступ к удаленным репозиториям. Когда ноды Kubernetes развертываются с помощью VirtualBox, то eth0
там подключается по умолчанию в режиме NAT. Гостевая ОС получает IP 10.0.2.15 и обменивается данными с VirtualBox через IP 10.0.2.3. Это настройки по умолчанию, которые обеспечивают взаимодействие виртуальных машин с «внешним миром» при условии, что у хоста с работающим VirtualBox, есть необходимое подключение. Вот как это выглядит схематично:
Источник изображения: medium.com
Конечно, схема сети VirtualBox по умолчанию может показаться не совсем логичной, но только до тех пор, пока вы не поймете, что виртуальные машины подключены к разным сетям, даже если все они используют одно и то же адресное пространство. Этот выбор конструкции VirtualBox позволяет осуществлять связь с внешними ресурсами, используя согласованную схему IP-адресации на всех виртуальных машинах.
В сетевой схеме VirtualBox по умолчанию соединения между виртуальными машинами обрабатываются индивидуально. Каждая виртуальная машина подключена к собственной изолированной сети 10.0.2.0/24 внутри VirtualBox, используя уникальный виртуальный канал для каждой внутренней сети. Таким образом, виртуальные машины взаимодействуют с внешним миром, но не могут взаимодействовать между собой.
Теперь давайте создадим под с использованием образа:
[vagrant@node-1 ~]$ kubectl run nginx --image=nginx:latest
Затем посмотрим на его статус:
[vagrant@node-1 ~]$ kubectl get pods/nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 10m
Если статус Running, значит, всё в порядке и под активен на ноде 1, если, конечно, эта нода была выбрана в планировщике Kubernetes. Чтобы проверить это, вводим последовательно:
[vagrant@node-1 ~]$ kubectl describe pods/nginx
[vagrant@node-1 ~]$ journalctl -f -u containerd
Для подключения нод к одному внешнему каналу необходимо их прямое соединение. Поэтому eth0
не подходит для этой цели, и нужно использовать другой тип сетевого подключения. Здесь нас выручает eth1
, и реализуется вот такая простая и эффективная схема:
Источник изображения: medium.com
Как видим, для каждой ноды задан свой IP в определенном диапазоне, начиная с 192.168.56.10/24 для главной, 192.168.56.11/24 для первой рабочей ноды и 192.168.56.12/24 — для второй.
Теперь давайте проверим параметры подключения для обеих рабочих нод (в терминологии Kubernetes они называются workers), последовательно вводя следующие команды:
[vagrant@controlplane ~]$ traceroute -n 192.168.56.11
[vagrant@controlplane ~]$ traceroute -n 192.168.56.12
В случае успешного подключения вы увидите количество переданных пакетов и время их передачи в миллисекундах.
Межподовый трафик возникает при запуске приложений Kubernetes на одном узле. В этом случае подам для обмена данными необходимо иметь уникальные IP. При этом вы знаете, что поды имеют определенный срок существования и уничтожаются так же легко, как и создаются. Это реализуется с помощью плагина CNI, а схематично выглядит так:
Источник изображения: medium.com
Теперь давайте создадим под из образа:
[vagrant@node-1 ~]$ kubectl run httpd --image=httpd
Далее нам нужно узнать IP созданного пода, что делается при помощи:
[vagrant@controlplane ~]$ kubectl get pods -o wide
Теперь через образ busybox
мы создаем новый под, подставив вместо IP полученное значение:
[vagrant@node-1 ~]$ kubectl run traceroute --image=busybox -- traceroute IP
И, наконец, проверяем параметры подключения, введя следующую команду для вывода лога:
[vagrant@node-1 ~]$ kubectl logs traceroute
Если в логе будет указан только один переход при определении маршрутизации (traceroute
), значит, мы имеем дело с cni0
, то есть трафик между подами осуществляется в пределах одной ноды.
Одноузловые кластеры Kubernetes хороши в тестировании, однако при использовании в реальных проектах они не обеспечивают должного уровня отказоустойчивости. Ведь стоит единственной ноде отключиться, как рушится и всё приложение. Поэтому разработчики создают многоузловые кластеры, в которых нагрузка между нодами нередко распределяется равномерно. Для этой цели используется плагин Flanel, обеспечивающий «умную» маршрутизацию трафика без необходимости контролировать процесс маршрутизации вручную. А вот как выглядит многоузловой кластер:
Источник изображения: medium.com
Создаем под из образа и при этом проверяем, что под будет размещен на соответствующей ноде (в нашем случае на первой рабочей):
[vagrant@controlplane ~]$ kubectl run httpd --image=httpd \
--overrides= '{"spec": { "nodeSelector": {"kubernetes.io/hostname": "node-1"}}}'
Далее вводим еще одну знакомую команду:
[vagrant@controlplane ~]$ kubectl get pods -o wide
Теперь, снова как в прошлом примере, через образ busybox
мы создаем новый под, только на второй рабочей ноде, подставив вместо IP полученное значение:
[vagrant@controlplane ~]$ kubectl run traceroute --image=busybox \
--overrides='{"spec": { "nodeSelector": {"kubernetes.io/hostname": "node-2"}}}' \
-- traceroute IP
И в завершение выполняем команду для отслеживания маршрутизации:
[vagrant@controlplane ~]$ kubectl logs traceroute
Если всё работает корректно, то мы увидим 3 перехода, соответствующие схеме cni0
-eth1
-cni0
.
Итак, мы с вами рассмотрели, как с помощью стандартных инструментов Kubernetes и подключаемого дистрибутива можно легко управлять конфигурацией кластера, создавая различные схемы и организуя трафик между подами в пределах одной или нескольких нод, то есть узлов кластера.