Сети в Kubernetes: глубокое погружение
Это перевод оригинальной статьи Kubernetes Networking: A Deep Dive.
Подписывайтесь на телеграм-канал usr_bin, где я публикую много полезного по Linux, в том числе ссылки на статьи в этом блоге.
Введение:
Сетевое взаимодействие в Kubernetes на первый взгляд кажется простым. Когда вы начинаете глубже изучать сетевое взаимодействие Kubernetes, всё становится сложнее. Сначала вам кажется, что вы понимаете, как работает сетевое взаимодействие Kubernetes.
Чтобы успешно сдать CKA и CKAD и хорошо разбираться в облачных технологиях, вы должны понимать, как поды взаимодействуют между собой.
Kubernetes обеспечивает выполнение трёх базовых принципов сетевого взаимодействия, которые являются основой всего остального:
- Взаимодействие Pod-to-Pod: каждый под может напрямую взаимодействовать с любым другим подом на любых узлах — без NAT.
- Взаимодействие Node-to-Pod: узлы могут обращаться к любому поду, а поды могут обращаться к узлам — также без NAT.
- Согласованность IP-адреса Pod: собственный IP-адрес пода совпадает с тем IP-адресом, который другие подмы видят извне — без трансляции IP-адресов.
Это создаёт плоскую маршрутизируемую сеть уровня L3, в которой каждый под является полноценным сетевым объектом. Приложения взаимодействуют с использованием обычных IP-адресов — без необходимости трансляции портов. Это значительно упрощает взаимодействие микросервисов и позволяет применять сетевые политики на уровне подов.
Пять типов сетевого взаимодействия Kubernetes
Сетевое взаимодействие Kubernetes охватывает пять отдельных направлений, каждое из которых решает свою задачу взаимодействия.
Взаимодействие между контейнерами
Контейнеры, находящиеся внутри пода, имеют одну общую особенность. Все они используют одно и то же сетевое пространство имён. Это означает, что все контейнеры внутри пода видят одинаковые сетевые интерфейсы, и все они используют один и тот же IP-адрес. Они также совместно используют пространство портов. Когда контейнерам внутри пода необходимо взаимодействовать друг с другом, сделать это очень просто. Контейнеры внутри пода могут использовать localhost для взаимодействия друг с другом.
- Общее сетевое пространство имён: контейнеры внутри пода используют один IP-адрес и взаимодействуют через localhost.
- Общие тома: контейнеры обмениваются данными, читая и записывая данные в общее хранилище
- Межпроцессное взаимодействие: контейнеры используют такие механизмы, как общая память и семафоры, для взаимодействия друг с другом.
Как работает общее пространство имен:
Каждый под получает специальный pause-контейнер (также называемый sandbox или infra container), единственная задача которого — удерживать сетевое пространство имён. Все контейнеры приложения присоединяются к этому пространству имён с помощью функции Linux setns(). Такая архитектура означает, что контейнеры могут перезапускаться независимо друг от друга без потери общей сетевой идентичности.
Сетевые интерфейсы внутри пода:
- lo. Интерфейс обратной связи: это виртуальный интерфейс. Он помогает контейнерам взаимодействовать друг с другом на компьютере, используя адрес 127.0.0.1. Он есть в каждой сетевой подсистеме Linux. Всё, что использует этот интерфейс, доступно только внутри пода.
- eth0. Интерфейс пода: сетевой интерфейс пода. Он получает IP-адрес, например 10.244.1.5. Он обрабатывает весь входящий и исходящий трафик пода, включая обращения к сервисам, доступ к веб-сайтам и выход в интернет.
- VETH_P. VETH на стороне пода: это один конец виртуального Ethernet-кабеля. Он находится внутри пода. Когда трафик покидает под, он проходит через eth0. Этот интерфейс подключён к интерфейсу veth.
- VETH_H. VETH на стороне хоста: это другой конец виртуального Ethernet-кабеля. Он находится на узле, где работает под. Он помогает передавать трафик подов в CNI-плагин, например в мост cni0. Он также помогает выполнять маршрутизацию на узле.
ПРИМЕЧАНИЕ: Интерфейс loopback делает взаимодействие внутри пода чрезвычайно быстрым — трафик никогда не покидает ядро. Интерфейс eth0 обрабатывает всё остальное. Два контейнера внутри одного пода не могут использовать один и тот же номер порта, поскольку они совместно используют пространство портов.
Взаимодействие Pod-to-Pod
Каждый Kubernetes под получает свой специальный адрес в сети, поэтому поды могут напрямую взаимодействовать друг с другом. Это означает, что поды Kubernetes не должны использовать Network Address Translation.
Модель IP-адреса для каждого пода упрощает работу с сетью. Она помогает Kubernetes подам находить и взаимодействовать с другими Kubernetes подами в кластере.
Трафик внутри одного узла и трафик между узлами:
Когда у вас есть два пода, которые находятся на одном узле, трафик остается в локальном мосте cni0. Это похоже на работу коммутатора уровня 2. Когда поды находятся на разных узлах, трафик должен пройти через базовую сеть. Для этого используется overlay-сеть CNI. Поды по-прежнему смогут взаимодействовать друг с другом, даже если они находятся на разных узлах, благодаря механизму CNI overlay.
kube-proxy — оркестратор трафика:
Kube-proxy работает на каждом узле как DaemonSet. Он следит за Kubernetes API server, чтобы видеть, есть ли какие-либо изменения в сервисах и Endpoint. Когда он обнаруживает изменение, он обновляет сетевые правила, чтобы трафик направлялся туда, куда необходимо. Kube-proxy выполняет свою работу тремя способами:
Взаимодействие Pod-to-Service
Поды эфемерны. Они выходят из строя, а затем постоянно запускаются заново. Их IP-адреса динамически меняются.
Это решается с помощью сервисов, где используется стабильный виртуальный IP (ClusterIP), который не изменяется, даже когда backend-поды появляются и исчезают.
Пошаговый сценарий:
- Под клиента, выполняющий поиск DNS для my-service, получает в ответ ClusterIP (10.96.0.10).
- Трафик направляется на ClusterIP (виртуальный IP-адрес — здесь ничего не прослушивается).
- Правила iptables/IPVS в kube-proxy перехватывают трафик и изменяют адрес назначения на реальный IP-адрес пода (DNAT).
- Пакеты беспрепятственно достигают бэкэнд-пода.
- Ответный трафик формируется с учетом отслеживания соединений (но клиент никогда не видит IP-адреса подов-бэкендов).
Сервисы Kubernetes:
Сервис — это абстракция, определяющая логический набор подов и политику доступа к ним. Он предоставляет стабильную конечную точку доступа к подам, которые могут подключаться и отключаться. Ниже приведены примеры.
Внешний доступ к сервису: Ingress-сеть
Трафик извне в кластер — это совсем другая история. В Kubernetes существует 4 основных пути, и Ingress предоставляет наиболее полный набор функций для HTTP/HTTPS.
Ingress и Gateway API: сравнение
Сообщество Kubernetes поддержало Gateway API как модель следующего поколения. API Ingress является функционально замороженным (но не устаревшим), а инновации теперь происходят исключительно в Gateway API.
Pod-to-External: Egress Networking
Egress — это способ, с помощью которого контейнеры внутри пода получают доступ к внешнему миру — внешним API, базам данных, реестрам контейнеров и интернету. Вам необходимо понимать egress для безопасности (для контроля исходящего трафика) и по функциональным причинам (чтобы поды могли получать свои зависимости).
Распространенные сценарии использования Egress:
ПРИМЕЧАНИЕ: Контролируйте egress с помощью NetworkPolicies. По умолчанию весь egress разрешен. Используйте правила NetworkPolicy policyTypes: [Egress], чтобы ограничить исходящий трафик к определенным назначениям, реализуя zero-trust исходящую сетевую модель.Сетевое взаимодействие контейнеров и плагины CNI
Kubernetes не предоставляет сетевое взаимодействие самостоятельно. Container Network Interface (CNI) — это стандартный API, который позволяет сетевым плагинам настраивать сетевые интерфейсы в контейнерах. Без плагина CNI поды не получают IP-адреса и не могут взаимодействовать.
- Создают сетевые пространства имен подов.
- Подключают пары veth между подом и хостом.
- Назначают уникальные IP-адреса подам.
- Настраивают таблицы маршрутизации, чтобы IP-адреса подов были доступны.
- Включают overlay networking для взаимодействия между узлами.
- Применяют правила NetworkPolicy в поддерживаемых CNI.
Выбор подходящего CNI:
DNS в Kubernetes
Kubernetes использует CoreDNS в качестве встроенного DNS-сервера (по умолчанию начиная с K8s 1.13). Каждый под получает предварительно настроенный /etc/resolv.conf для использования CoreDNS, что позволяет обнаруживать сервисы по имени.
Сетевые политики: обеспечение безопасности взаимодействия подов
По умолчанию всё взаимодействие pod-to-pod в Kubernetes полностью открыто. Любой под может обращаться к любому другому поду. Network Policies позволяют реализовать zero-trust сетевое взаимодействие, определяя точные правила межсетевого экрана на уровне подов.
ПРИМЕЧАНИЕ: Network Policies применяются CNI-плагином — а не самим Kubernetes. Если ваш CNI не поддерживает NetworkPolicy (например, стандартный Flannel), политики будут молча игнорироваться. Используйте Calico, Cilium или облачный CNI для применения правил.
Сквозной поток трафика Kubernetes
Давайте проследим полный запрос от браузера, обращающегося к вашему приложению, до пода, который его обрабатывает, и обратно.
- Разрешение DNS:
myapp.comпреобразуется во внешний публичный IP-адрес облачного балансировщика нагрузки через внешний DNS. - Облачный балансировщик нагрузки: публичный IP принадлежит облачному балансировщику нагрузки. Он перенаправляет трафик к подам Ingress Controller, используя проверки состояния (health probes), чтобы только работоспособные узлы получали трафик.
- Контроллер Ingress: анализирует HTTP-запрос, сопоставляет hostname/path с правилами Ingress, а затем определяет целевой Kubernetes сервис. Также он выполняет завершение TLS.
- Сервис (ClusterIP): трафик отправляется на виртуальный ClusterIP. Здесь не прослушивает ни один реальный процесс.
- kube-proxy: правила iptables/IPVS выполняют DNAT, переписывая назначение на реальный IP пода и распределяя нагрузку между работоспособными репликами.
- Обработка подом: Целевой под получает запрос, обрабатывает его и формирует ответ.
- Обратный путь: Ответ проходит тот же путь в обратном направлении, а отслеживание соединений гарантирует корректное возвращение пакетов.
Заключительные мысли:
Освоение этих основ помогает не только при подготовке к сертификациям, таким как CKA и CKAD, но и создает прочную основу для проектирования масштабируемых, безопасных и готовых к промышленной эксплуатации cloud-native приложений.
На этом все! Спасибо за внимание! Если статья была интересна, подпишитесь на телеграм-канал usr_bin, где будет еще больше полезной информации.