Внутреннее устройство сети Kubernetes

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

В документации кластера Kubernetes указано, что основные требования сети Kubernetes таковы:

  • все контейнеры могут связываться со всеми другими контейнерами без NAT.
  • все ноды могут связываться со всеми контейнерами (и наоборот) без NAT.
  • контейнер видит свой IP-адрес так же, как и другие.

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

Кроме того, вы узнаете, как сервис Kubernetes может предоставлять единый статический IP-адрес и DNS запись для приложения, ослабляя связь с сервисами, которые можнораспределить между несколькими постоянно масштабируемыми и перемещающимися подами.

Если вы не знакомы с терминологией Kubernetes, ознакомьтесь с общей архитектурой и компонентами в статье Краткий обзор Kubernetes.

Сначала мы рассмотрим ситуацию в сети в рамках одного контейнера.

Сетевые процессы внутри пода

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

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

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

Сетевые процессы между подами

Большинство кластеров Kubernetes обслуживает несколько подов в рамках одной ноды. Связь между двумя подами может происходить на одной ноде или между двумя разными нодами.

Взаимодействие между подами в рамках одной ноды

На одной ноде может быть несколько подов, которые должны связываться друг с другом напрямую. Прежде чем мы проследим маршрут пакета между ними, давайте ознакомимся с сетевой настройкой ноды.

Каждая нода имеет сетевой интерфейс – например, eth0. Он подключен к сети кластера Kubernetes. Этот интерфейс находится в root пространстве имен ноды. Это пространство имен по умолчанию для сетевых устройств в Linux.

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

Пространства имен пода соединяются с root пространством имен через виртуальную ethernet-пару – это такой канал между двумя пространствами имен с интерфейсом на каждом конце (например, такая пара может называться veth1 в root пространстве и eth0 внутри пода).

Наконец, поды подключаются друг к другу и к интерфейсу eth0 ноды через мост, br0 (также ноды используют для них имена типа cbr0 или docker0). Мост, по существу, работает как физический коммутатор Ethernet, используя для поиска других локальных интерфейсов для передачи трафика ARP (протокол разрешения адресов) или маршрутизацию на основе IP.

Давайте отследим пакет от pod1 до pod2:

  • pod1 создает пакет с IP-адресом пода pod2 (это адресат).
  • Пакет перемещается по виртуальной Ethernet-паре в корневое сетевое пространство имен.
  • Пакет попадает на мост br0.
  • Поскольку целевой под находится на той же ноде, мост отправляет пакет в виртуальную ethernet пару пода pod2.
  • Паке проходит через виртуальную пару в пространство имен pod2 и сетевой интерфейс eth0.

Теперь вы знаете маршрут пакета между двумя подами в рамках одной ноды.

Взаимодействие между подами на разных нодах

Поскольку каждый под в кластере имеет уникальный IP-адрес и может напрямую связываться со всеми другими подами, пакет, перемещающийся между контейнерами на двух разных нодах, движется по очень похожему на предыдущий маршруту.

Давайте проследим путь пакета от pod1 до pod3, который находится на другой ноде кластера:

  • pod1 создает пакет и указывает IP-адрес целевого пода pod3э
  • Пакет перемещается по виртуальной ethernet-паре в корневое сетевое пространство имен.
  • Пакет попадает к мосту br0.
  • Мост не находит локального интерфейса для маршрутизации, поэтому пакет отправляется по eth0 по умолчанию.
  • Опционально: если кластеру необходим оверлей для правильной маршрутизации пакетов на ноды, пакет может быть заключен в VXLAN (или инкапсулирован с помощью другой технологии сетевой виртуализации) перед тем, как отправиться в сеть. В качестве альтернативы, сама сеть может быть настроена с указанием правильных статических маршрутов (в этом случае пакет перемещается в eth0 и выходит из сети без изменений).
  • Пакет входит в кластерную сеть и направляется на правильную ноду.
  • Пакет входит на целевую ноду по eth0.
  • Опционально: если ваш пакет был инкапсулирован, в этот момент он будет распакован.
  • Пакет продолжает путь до моста br0.
  • Мост направляет пакет в виртуальную пару целевого пода.
  • Пакет проходит через виртуальную ethernet пару к интерфейсу eth0 целевого пода.

Теперь вы знакомы с тем, как пакеты маршрутизируются между подами на разных нодах. Давайте познакомимся с сервисами Kubernetes и их местом в этой инфраструктуре.

Взаимодействие между подами и сервисами

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

Kubernetes устраняет эту проблему с помощью так называемых сервисов. В терминологии Kubernetes сервис – это объект API, который соединяет единый виртуальный IP (VIP) с набором IP-адресов пода. Кроме того, Kubernetes предоставляет DNS-запись для имени и IP-адреса каждого сервиса, потому на сервис легко сослаться по имени.

Связь виртуальных IP-адресов с IP-адресами подов внутри кластера координируется процессом kube-proxy на каждой ноде. Этот процесс настраивает либо iptables, либо IPVS, чтобы автоматически переводить VIP-адреса в IP пода перед отправкой пакета в сеть кластера.

Читайте также: Архитектура Iptables и Netfilter

Индивидуальные соединения отслеживаются, поэтому пакеты могут быть преобразованы надлежащим образом. IPVS и iptables могут выполнять балансировку нагрузки одного виртуального IP между несколькими IP-адресами подов, хотя IPVS обладает гораздо большей гибкостью в алгоритмах балансировки нагрузки.

Примечание: Этот процесс отслеживания преобразования и подключения полностью происходит в ядре Linux. Процесс kube-proxy читает API Kubernetes и обновляет Iptables ip IPVS, но его нет в пути данных отдельных пакетов. Это обеспечивает более высокую эффективность и производительность, чем предыдущие версии kube-proxy, которые функционировали как пользовательский прокси-сервер.

Давайте подробно рассмотрим маршрут, который проходит пакет с пода pod1 до сервиса service1:

  • pod1 создает пакет с IP-адресом целевого сервиса service1.
  • Пакет перемещается по виртуальной ethernet-паре в корневое сетевое пространство имен.
  • Пакет продолжает путь до моста br0.
  • Мост не находит локального интерфейса для маршрутизации пакета, поэтому пакет по умолчанию отправляется по пути eth0.
  • Iptables или IPVS, настроенные с помощью kube-proxy, отслеживают целевой IP-адрес пакета и переводят его с виртуального IP на один из IP-адресов пода сервиса, используя любые доступные алгоритмы балансировки нагрузки.
  • Опционально: на этом этапе пакет может быть инкапсулирован, как описано в предыдущем разделе.
  • Пакет входит в кластерную сеть и направляется на правильную ноду.
  • Пакет попадает на целевую ноду по eth0.
  • Опционально: если пакет инкапсулирован, сейчас он будет распакован.
  • Пакет доходит до моста br0.
  • Пакет отправляется в виртуальную ethernet-пару через veth1
  • Пакет проходит через виртуальную ethernet-пару и входит в пространство имен сети по сетевому интерфейсу eth0.

Когда пакет возвращается к ноде node1, преобразование адреса VIP в IP пода будет отменено, и пакет вернется через мост и виртуальный интерфейс к правильному контейнеру.

Заключение

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

Больше информации о Kubernetes можно найти в официальной документацией Kubernetes или в нашем Информатории.

Tags: