[Перевод] Как отследить pod-to-pod-трафик Kubernetes

В этой статье мы рассмотрим тонкости сетевого взаимодействия Kubernetes и углубимся в фундаментальные принципы и механизмы, которые управляют связью между подами. 

2f0ac089f953209b99a13d869cd66c88.png

В этой статье сосредоточимся на сетевой модели Kubernetes в контексте стандартной сетевой схемы VirtualBox. Вы сможете получить полное представление о том, как работает связь между подами в среде Kubernetes. В публикации мы рассмотрим основные концепции и механизмы, обеспечивающие бесперебойную связь между блоками в кластере.

Сетевое взаимодействие Kubernetes

Что касается сетевого взаимодействия Kubernetes, важно отметить, что он не поставляется в комплекте с собственной сетевой реализацией. Вместо этого используется гибкий подход, отделяющий реализацию сети кластера с помощью стандартов Container Runtime Interface (CRI) и Container Network Interface (CNI). Эти стандарты служат шлюзами для сторонних провайдеров, предлагающих свои собственные плагины для реализации сетевых технологий Kubernetes.

Не существует единого предписанного сетевого решения, а скорее богатый набор альтернатив, доступных пользователям Kubernetes. Каждый вариант в этом обширном списке имеет свои тонкости, которые могут существенно повлиять на итоговую реализацию кластерной сети. Такой широкий спектр вариантов гарантирует, что организации смогут выбрать сетевой подход, который наилучшим образом соответствует их конкретным требованиям, учитывая масштабируемость, производительность, безопасность и совместимость с существующей инфраструктурой.

Разнообразные варианты сетевого взаимодействия Kubernetes позволяют точно настроить сетевую конфигурацию кластера в соответствии со индивидуальными потребностями компаний. Однако такое разнообразие может создавать и проблемы, поскольку процесс выбора требует тщательной оценки компромиссов и факторов, связанных с каждым сетевым решением.

Когда речь идет о плагинах Kubernetes CRI и CNI, то можно говорить о нескольких распространенных вариантов сетевого взаимодействия. Со стороны CRI двумя популярными вариантами являются containerd и cri-o, а со стороны CNI популярными альтернативами являются Calico и Flannel. Эти плагины обеспечивают необходимую функциональность и возможности для запуска контейнеров и управления сетью в кластерах Kubernetes.

Дистрибутивы Kubernetes

Функциональный кластер Kubernetes подразумевает гармоничное сосуществование плагинов CRI и CNI. Такое взаимодействие между плагинами требует дополнительных усилий по настройке. Поэтому дистрибутивы Kubernetes появились как альтернативный способ упростить использование Kubernetes для массового пользователя.

Дистрибутив Kubernetes устанавливает и настраивает все компоненты Kubernetes, включая плагины CRI и CNI. Вам не нужно беспокоиться о деталях низкоуровневой конфигурации платформы. Все, что вам нужно сделать, это выполнить команду, подождать пару минут, пока платформа развернет все ресурсы, и получить доступ к API Kubernetes, предоставленному вам по завершении процесса развертывания.

Вы можете использовать коммерческие дистрибутивы, такие как Red Hat Openshift, AWS EKS, Google GKS, и дистрибутивы с открытым исходным кодом, такие как OKD и minikube.

В этой статье вы изучите трафик pod-to-pod с помощью vagrant-k8s-lab. Этот небольшой дистрибутив Kubernetes с открытым исходным кодом запускает кластер локально, используя Vagrant с провайдером VirtualBox и роли Ansible для настройки  кластера.

Архитектура кластера Kubernetes

Проект vagrant-k8-lab устанавливает и настраивает плагины containerd CRI и flannel CNI на всех узлах кластера. Архитектура кластера выглядит следующим образом:

047174224a6de27fc2d552447a0146d7.png

Обратите внимание, что у кластера есть четыре сетевых интерфейса, подключенных к каждому узлу. Сетевые интерфейсы — это lo, eth0, eth1 и cni0. Каждый интерфейс имеет свое назначение. Кроме того, в кластере уже развернута пара подов для тестирования.

Kubernetes Node-to-Internet Traffic (eth0)

Плагину CRI необходим исходящий трафик в кластере Kubernetes для загрузки образов контейнеров из внешних хранилищ контейнеров. Диспетчер пакетов операционной системы также должен обращаться к удаленным репозиториям пакетов для загрузки обновлений системы. Эти два действия требуют, чтобы узлы Kubernetes поддерживали исходящий трафик.

Например, когда Kubernetes Scheduler дает команду Kubelet, запущенному на узле, развернуть pod, плагин CRI этого узла отвечает за связь с внешними хранилищами контейнеров для загрузки образа контейнера, определенного в манифесте pod, который Kubernetes Scheduler дал команду развернуть. Если узел не может связаться с внешним хранилищем контейнеров, создать под не получится. 

Когда вы развертываете узлы Kubernetes с помощью виртуальных машин VirtualBox, они создаются с уже подключенным сетевым интерфейсом eth0 в режиме NAT. На уровне IP гостевая операционная система получает адрес 10.0.2.15/24 и может взаимодействовать с VirtualBox через адрес 10.0.2.3/24. Эта сетевая схема называется VirtualBox по умолчанию. Она позволяет виртуальным машинам взаимодействовать с внешними ресурсами при условии, что хост, на котором запущен VirtualBox, имеет необходимые условия для подключения.

89db64177ad92279517dcc6004fe31f9.png

Пример:

1. Создайте pod с именем nginx, воспользовавшись образом nginx:

[vagrant@node-1 ~]$ kubectl run nginx --image=nginx:latest

2. Проверьте статус пода

[vagrant@node-1 ~]$ kubectl get pods/nginx
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          10m

Статус пода — Running. Отлично! Это действие потребовало от контейнера связаться с удаленным реестром контейнеров, например, registry.docker.io, и загрузить образ контейнера nginx. Если под запущен, это означает, что эти действия были успешно выполнены на node-1. Вы можете получить дополнительную информацию об этих действиях, запустив следующие команды:

[vagrant@node-1 ~]$ kubectl describe pods/nginx
[vagrant@node-1 ~]$ journalctl -f -u containerd

Трафик между узлами Kubernetes (eth1)

Плагин Flannel CNI, когда настроен с бэкендом host-gw, требует, чтобы узлы Kubernetes имели прямую связь между собой — например, подключение каждого узла к одному и тому же каналу Ethernet. Сетевой интерфейс eth0 не соответствует такому требованию, поскольку он использует тип NAT Network в VirtualBox. Чтобы обеспечить требования плагина Flannel CNI, необходимо подключить другой тип сети ко всем узлам кластера Kubernetes.

VirtualBox имеет разные виды сетей, которые вы можете выбрать при создании новых сетей. В этой статье узлы Kubernetes используют тип сети «Host-only networking». 

Тип сети VirtualBox «только хост» позволяет устанавливать связь между нода внутри кластера. По умолчанию конфигурация плагина Flannel CNI использует сетевой интерфейс eth0 для связи между узлами. В процессе установки кластера, использованном в этой статье, конфигурация плагина CNI по умолчанию была изменена на eth1 — новое значение сетевого интерфейса, используемое для связи между узлами.

Вот изображение кластера с подключенной сетью eth1:

ac55d35cc9a125f73474992553661aa0.png

На рисунке межузловая связь происходит через сетевой адрес 192.168.56.0/24. Каждый узел имеет IP-адрес, назначенный в этом диапазоне.

Пример:

1. Проверьте подключение control-plane node к node-1:

[vagrant@controlplane ~]$ traceroute -n 192.168.56.11
traceroute to 192.168.56.11 (192.168.56.11), 30 hops max, 60 byte packets
 1 192.168.56.11 0.900 ms 0.850 ms 0.717 ms

2. Проверьте подключение control-plane node к node-2:

[vagrant@controlplane ~]$ traceroute -n 192.168.56.12
traceroute to 192.168.56.12 (192.168.56.12), 30 hops max, 60 byte packets
 1 192.168.56.12 1.003 ms 0.837 ms 0.851 ms

Трафик между подами в одном узле (cni0)

Трафик между подами возникает тогда, когда вы запускаете приложения Kubernetes в одном узле. В таком сценарии поды должны иметь возможность обмениваться информацией и IP-адресами. Помните, что поды могут быть уничтожены и созданы в любой момент времени. Сетевая логика, которая делает это возможным, в основном управляется плагином CNI, который вы установили и настроили в кластере.

Визуализируем архитектуру node-1, на которой запущены два пода:

050c77e452457d343be1dcfe98e85a29.png

На рисунке сетевой интерфейс cni0 соединяет все поды на node-1, первом узле, который мы подключили к кластеру после создания control-plane node. Через сетевой интерфейс cni0 плагин CNI управляет назначением IP-адресов сетевых ресурсов Kubernetes, таких как поды. Когда вы создаете сетевой ресурс, он получает динамический IP-адрес, а когда ресурс уничтожается, назначенный IP-адрес освобождается для последующего переназначения. Чтобы сохранить связь между назначенными и неназначенными IP-адресами, плагин Flannel CNI использует etcd — службу хранения Kubernetes.

Пример:

  1. Создайте один под с именем httpd, используя образ httpd:

[vagrant@node-1 ~]$ kubectl run httpd --image=httpd
  1. Проверьте статус пода httpd, чтобы узнать его IP-адрес. Предположим, что это 10.244.1.3/24:

[vagrant@node-1 ~]$ kubectl get pods -o wide
  1. Создайте новый под с помощью образа busybox и выполните команду traceroute для IP-адреса пода httpd:

[vagrant@node-1 ~]$ kubectl run traceroute --image=busybox -- traceroute 10.244.1.3
  1. Проверьте логи:

[vagrant@node-1 ~]$ kubectl logs traceroute
traceroute to 10.244.1.3 (10.244.1.3), 30 hops max, 80 byte packets
 1  10.244.1.3 (10.244.1.3)  0.018 ms  0.009 ms  0.005 ms

Логи показывают один-единственный переход до нужного блока, что вполне ожидаемо, учитывая, что оба блока находятся в одной сети 10.244.1.0/24. На основании этих данных можно сделать вывод, что связь происходит локально через сетевой виртуальный интерфейс cni0, когда поды работают на одном узле. В этих случаях сетевой трафик никогда не выходит за пределы ноды.

Трафик между различными узлами (cni0+eth1+cni0)

Кластер Kubernetes с одной нодой полезен для некоторых тестов, но не дает высоких нагрузок. Если нода перестает работать, ваше приложение выходит из строя. При работе кластера с несколькими узлами понимание того, как трафик проходит от одного ресурса к другому, дает вам мощный инструмент для поиска и устранения неисправностей. Такое понимание существенно зависит от плагина CNI, настроенного в вашем кластере Kubernetes, поскольку каждый плагин CNI имеет свой подход к решению этой проблемы.

Нодам необходимо знать, куда направлять трафик внутри кластера. Для решения этой проблемы при конфигурации с бэкендом host-gw плагин Flannel использует таблицу маршрутизации операционной системы для управления такими сведениями на каждой ноде Вся эта работа выполняется плагином CNI автоматически, когда вы добавляете новые ноды в кластер или удаляете из него старые. Вам не нужно самостоятельно поддерживать таблицы маршрутов. Плагин CNI делает это за вас. 

Давайте рассмотрим три ноды, на каждой из которых запущено по два пода, в трех различных сетях CNI, соединенных через сеть eth1 и сетевые маршруты, уже установленные для операционной системы. Это требуется для того, чтобы знать, куда отправлять файлы внутри кластера:

e9f799661087a926c38688b9fd019cf2.png

Пример:

  1. Создайте один под с именем httpd, используйте образ httpd и убедитесь, что он размещен на node-1:

[vagrant@controlplane ~]$ kubectl run httpd --image=httpd \
 --overrides='{"spec": { "nodeSelector": {"kubernetes.io/hostname": "node-1"}}}'

2. Проверьте статус пода, чтобы получить IP-адрес (например, 10.244.1.3) стручка httpd. Этот под является конечной целью:

[vagrant@controlplane ~]$ kubectl get pods -o wide

3. Создайте один подс именем traceroute, используйте образ busybox и запустите команду traceroute с IP-адресом httpd pod в качестве аргумента. Убедитесь, что этот под расположен на node-2:  

[vagrant@controlplane ~]$ kubectl run traceroute --image=busybox \
 --overrides='{"spec": { "nodeSelector": {"kubernetes.io/hostname": "node-2"}}}' \
 -- traceroute 10.244.1.3

4. Проверьте логи, выданные в блоке traceroute:

[vagrant@controlplane ~]$ kubectl logs traceroute
traceroute to 10.244.1.3 (10.244.1.3), 30 hops max, 46 byte packets
 1  10.244.2.1 (10.244.2.1)  0.007 ms  0.008 ms  0.004 ms
 2  192.168.56.11 (192.168.56.11)  0.575 ms  0.411 ms  0.396 ms
 3  10.244.1.3 (10.244.1.3)  0.614 ms  0.580 ms  0.498 ms

На этот раз вывод traceroute показывает три точки перехода:

  • Первая — 10.244.2.1, адрес шлюза, настроенный в сетевом интерфейсе cni0 на node-2.

  • Вторая — 192.168.56.11, IP-адрес сетевого интерфейса eth1 для node-1.

  • Третья — 10.244.1.3, IP-адрес, подключенный к сети cni0 на node-1 и назначенный для пода, для которого мы хотели проверить соединение.

Когда поды находятся в разных нодах, связь устанавливается между интерфейсами cni0 и eth1, подключенными к каждой ноде.

От редакции

Для тех, кто хочет разобраться в основах K8s, мы подготовили курс «Kubernetes. База». Мы рассмотрим основные компоненты, научим настраивать кластер и запускать в нем приложения.

Курс в формате потока стартует 26 июля. Поток отличается от обычных видеолекций: вы будете учиться вместе с другими студентами, выполнять практику на стендах. В конце каждого модуля мы проводим встречу со спикером курса: он отвечает на все вопросы студентов по инструменту, дает рекомендации и советы.

Ждем вас! Узнать подробнее о курсе вы можете на нашем сайте: https://slurm.io/kubernetes-baza

© Habrahabr.ru