Соединяем мультиоблачные приложения с помощью Cilium
«Не клади все яйца в одну корзину» — известная пословица, которая как нельзя лучше описывает принцип проектирования современных приложений.
По мере того как Kubernetes становится стандартной плоскостью управления для современных приложений, его независимость от конкретного облака позволяет разворачивать их в нескольких средах и у разных провайдеров. Однако это порождает ключевую проблему: как связать распределённые приложения между кластерами.
В статье рассматривается, как Cilium Cluster Mesh упрощает межкластерное взаимодействие в Kubernetes: разбираются как фундаментальные сложности так называемых Mesh-решений, так и то, как Cilium с ними справляется. Помимо этого, статья содержит практический сценарий, в котором мультиоблачное приложение объединяет нативные сервисы Kubernetes от Amazon Web Services и Google Cloud Platform.
|
Примечание
|
В статье предполагается базовое понимание сетевого стека Kubernetes. В разделе с выводами приведены ресурсы для тех, кто только начинает. |
Мультикластер: мотивация и сложности
Организации переходят на мультикластерные архитектуры ради масштабируемости, изоляции сбоев и операционной автономии. Типичные сценарии развёртывания приложений сразу в нескольких кластерах:
-
Отказоустойчивость / высокая доступность (High Availability): реплики одного и того же приложения работают в кластерах, развёрнутых в разных зонах доступности (AZ), регионах или даже у разных облачных провайдеров. При сбое, затрагивающем приложение или один из его уровней (tiers), трафик перенаправляется на работоспособный кластер.
-
Низкая задержка (Latency): приложения с глобальной аудиторией, как правило, реплицируются по географически распределённым точкам присутствия, чтобы улучшить пользовательский опыт.
-
Мультиарендность (Multi-Tenancy): хотя Kubernetes обеспечивает логическую изоляцию через пространства имён (namespaces), это не защищает от проблем на уровне плоскости управления. Поэтому критически важные приложения нередко выносятся в отдельные кластеры.
-
Общие сервисы (Shared Services): широко распространена практика централизации таких сервисов, как логирование и мониторинг, в выделенных кластерах. Приложения в остальных кластерах организации обращаются к этим сервисам удалённо.
Мультикластерная топология влечёт за собой новые вызовы. Управление конфигурацией становится критически важным по мере роста числа кластеров: одни и те же меры по защите, как правило, нужно применять ко всем инстансам. Эту задачу решает проект Sveltos.
Сетевое взаимодействие — главная тема этой статьи — является ещё одним ключевым вызовом мультикластерной топологии. Рассмотрим схему ниже: приложение, работающее в Cluster-A, должно обращаться к общему сервису в Cluster-B. Первый (и наивный) подход — открыть доступ к общему сервису через LoadBalancer и подключаться к нему из Cluster-B по внешнему IP-адресу.
Такой подход работоспособен, но имеет ряд существенных ограничений, главное из которых — масштабируемость. Выставлять наружу каждый отдельный потребляемый сервис неэффективно с точки зрения затрат. Облачные балансировщики нагрузки стоят денег, а в локальных (On-Prem) средах внешние IP-адреса — дефицитный ресурс. Кроме того, кластеры при этом остаются изолированными с сетевой точки зрения: рабочие нагрузки в удалённых кластерах трактуются как внешние эндпоинты, что ухудшает безопасность и наблюдаемость.
Подход, описанный в этой статье, опирается на дополнительный уровень сетевой инфраструктуры — так называемый Mesh: виртуальную оверлейную сеть, в которой сервисы Cluster-A выглядят как напрямую подключённые к сервисам Cluster-B, образуя единое адресное пространство с единой идентификацией.
Оба подхода — и через LoadBalancer, и через Cluster Mesh — предполагают, что IP-связность между узлами разных кластеров уже обеспечена.
Сетевые соображения
Перед погружением в Cilium Cluster Mesh полезно вспомнить несколько ключевых сетевых концепций многокластерных сред.
Сетевой трафик принято рассматривать в терминах паттернов: трафик «север–юг» (north–south) входит в систему (кластер или дата-центр) или выходит из неё, а трафик «восток–запад» (east–west) остаётся внутри. Mesh-решения сосредоточены на управлении трафиком «восток–запад», опираясь при этом на возможности плагина Container Networking Interface (CNI).
Доступ к кластеру: север–юг
Приложения, реплицированные в нескольких локациях (AZ, регионах, облаках), должны уметь привлекать и маршрутизировать пользовательский трафик. Направление клиентов в нужный кластер — с учётом таких факторов, как здоровье кластера или географическая близость — это преимущественно сетевая задача, в которой Kubernetes, CNI и Mesh практически не участвуют.
Большинство решений основаны на одном из следующих подходов:
-
Маршрутизация на основе Anycast: приложения, реплицированные в нескольких кластерах, открываются через
ServiceтипаLoadBalancer(нередко с использованием ресурсов Gateway API илиIngress). Внешний IP-адрес физического или облачного балансировщика остаётся одинаковым во всех локациях. Маршрутизацию клиентов к одному из кластеров, обслуживающих этот IP, берёт на себя сеть.-
On-Prem: физическая сеть направляет трафик в «ближайший» кластер на основе метрик вроде числа хопов и пропускной способности канала.
-
Облако: провайдеры используют встроенные CDN-решения. Пример — GCP Multi-Cluster Ingress.
-
-
DNS-балансировка нагрузки: реплицированные приложения также открываются через внешний IP, но в этом случае IP-адрес уникален для каждого кластера. Поскольку клиенты используют URL, а не IP-адреса, DNS-сервер разрешает URL в один из доступных внешних IP. В процессе этого «выбора IP» DNS-сервер может учитывать географию клиента или состояние кластера. Традиционные сервисы вроде Route53 предлагают базовую функциональность, тогда как решения типа K8GB обеспечивают более глубокую интеграцию с примитивами Kubernetes для лучшего мониторинга здоровья кластеров.
У обоих подходов есть плюсы и минусы. Anycast-маршрутизацию сложно реализовать, когда кластеры распределены по разным облакам. Главная боль DNS-балансировки — TTL-кэш на стороне клиента, который может затянуть переключение трафика при сбое.
|
Примечание
|
Детальное рассмотрение сценариев трафика «север–юг» выходит за рамки этой статьи. |
Cluster Mesh — восток–запад
Трафик между микросервисами или уровнями приложений, как правило, не выходит за пределы одного кластера Kubernetes. Однако в мультикластерной конфигурации трафик «восток–запад» может проходить и между кластерами.
|
Примечание
|
Mesh-решения, такие как Cilium Cluster Mesh, обеспечивают восточно-западное взаимодействие в мультикластерной топологии. |
Существует несколько сценариев, в которых трафик «восток–запад» выходит за пределы одного кластера. Один из распространённых примеров — высокая доступность, когда уровни приложения реплицируются по регионам или облакам. При переключении (failover) запросы могут обрабатываться эндпоинтами в удалённом кластере, порождая межкластерный трафик. Другой пример — межкластерная репликация данных для stateful-компонентов, таких как базы данных или очереди сообщений.
Трафик «восток–запад» в мультикластерной топологии, по сути, сводится к взаимодействию Pod-to-Pod между рабочими нагрузками в разных кластерах. Такое взаимодействие возможно только при соблюдении следующих условий:
-
Service Discovery (обнаружение сервисов): Mesh синхронизирует информацию о
Servicesи связанных с ними эндпоинтах между кластерами, позволяя каждому кластеру иметь актуальное представление обо всех Pod. Как только этот процесс завершается, принцип Namespace Sameness (одинаковые пространства имён) — согласно которомуServicesс одинаковыми именем иNamespaceв разных кластерах функционально идентичны и трактуются как единая логическая сущность — позволяет Mesh прозрачно представлять удалённые Pod. Рабочие нагрузки могут разрешать имена и подключаться к удалённым Pod, используя стандартныйServiceFQDN вида<service-name>.<namespace>.<cluster-domain>. Плоскость управления Mesh умеет обнаруживать и синхронизироватьServices, существующие только в удалённом кластере, а такжеServices, определённые в нескольких кластерах одновременно. -
Connectivity (связность): как только кластеры обменялись информацией о
Services, Pod из разных кластеров могут общаться по IP. Это обеспечивается совместно CNI кластера и плоскостью управления Mesh. В ландшафте Cluster Mesh выделяют две основные топологии связности:-
Single Network (единая сеть): взаимодействие Pod-to-Pod между кластерами происходит напрямую по IP-адресам, назначенным Pod. Эта топология возможна только при условии, что Pod CIDR уникальны во всех кластерах.
-
Multi-Network (множественная сеть): взаимодействие Pod-to-Pod между кластерами реализуется через дополнительный компонент — так называемый East-West (E/W) шлюз. Эта топология обычно требуется при объединении кластеров с пересекающимися Pod CIDR. E/W-шлюзы, управляемые плоскостью управления Mesh, используют SNI (TLS) или hostname (HTTP) для маршрутизации входящих пакетов.
-
|
Примечание
|
Хотя E/W-шлюзы, как правило, открываются через |
-
Common Trust (общее доверие): многие Cluster Mesh-решения имеют встроенные механизмы безопасности или расширяют уже имеющиеся в CNI. Установка единого доверия позволяет Pod в разных кластерах взаимно аутентифицировать друг друга. Например, взаимная аутентификация по mTLS возможна только тогда, когда сертификаты, которыми обмениваются Pod, подписаны одним и тем же удостоверяющим центром (CA).
Главная цель Cluster Mesh — обеспечить балансировку нагрузки «восток–запад» между кластерами Kubernetes. Технически это выражается в создании так называемых Global Services с общим пулом Pod для балансировки, то есть Service с эндпоинтами сразу в нескольких кластерах.
Помимо этого, Cluster Mesh содействует взаимодействию Pod-to-Pod между кластерами, хотя это и является совместной ответственностью с базовой инфраструктурой. Как будет показано далее, Cluster Mesh-решения сами по себе не могут построить или обеспечить эту связность между узлами кластеров.
Нет связности — нет Mesh
Cluster Mesh-решения не объединяют кластеры по волшебству: они предполагают, что базовая IP-связность между ними уже существует. Область ответственности Cluster Mesh ограничена обнаружением удалённых Services и Pods, а также маршрутизацией трафика внутри узлов. Как только пакет покидает узел, доставку его в узел назначения удалённого кластера обеспечивает сетевая инфраструктура.
Так же как в однокластерных развёртываниях CNI предполагает связность между узлами, в мультикластерной среде Mesh-решение предполагает связность между узлами в разных кластерах.
Прежде чем рассматривать распространённые варианты обеспечения мультикластерной связности, стоит вспомнить режимы маршрутизации, реализованные в большинстве CNI.
Режимы маршрутизации CNI
-
Native Routing (нативная маршрутизация) — предполагает, что трафик Pod-to-Pod может напрямую маршрутизироваться базовой сетью. В локальных развёртываниях это достигается с помощью статических маршрутов или BGP-анонсирования Pod CIDR. В облачных средах требуется, чтобы Pod CIDR были маршрутизируемы внутри облачной сети (например, через вторичные IP-диапазоны на VPC/VNet). Результат одинаков: сетевая инфраструктура осведомлена об IP-адресах Pod.
-
Encapsulation (инкапсуляция) — строит VXLAN- или Geneve-туннели между узлами для транспортировки трафика Pod-to-Pod. Этот режим требует лишь L3-связности между узлами, которая и так необходима для построения кластера Kubernetes. Поскольку дополнительная конфигурация физической или базовой сети не нужна, инкапсуляция является режимом по умолчанию во многих CNI.
Чтобы расширить эту сетевую модель на мультикластерную среду, необходимо выполнить те же требования. Узлы в разных кластерах должны быть достижимы друг для друга, а при нативной маршрутизации IP-адреса Pod должны быть маршрутизируемы в сетях кластеров.
Мультикластерные и мультиоблачные сети
Мультикластерные топологии предполагают объединение отдельных сетей — потенциально через регионы или облачных провайдеров. Для обеспечения этой связности в облачных и гибридных средах обычно применяют следующие инфраструктурные решения:
-
VPC/VNet Peering (пиринг VPC/VNet): эта облачная опция связывает VPC или VNet, позволяя их CIDR взаимодействовать, как если бы они принадлежали одной сети. Это обеспечивает узел-узел связность между кластерами, а при нативной маршрутизации CNI — и Pod-to-Pod. Решение ограничено сетями одного и того же облачного провайдера: VPC Peering или VNet Peering.
-
VPN Tunnels (VPN-туннели): как следует из названия, эта опция строит VPN-туннели между шлюзами в облачных или локальных сетях. Шлюзы анонсируют CIDR сетей своим пирам с помощью статических маршрутов или BGP. В качестве транспорта может использоваться как приватное соединение (Direct Connect/ExpressRoute), так и публичный интернет. Это предпочтительный вариант для связи между облачными провайдерами и локальными кластерами. В зависимости от маршрутизируемых CIDR и анонсов VPN-шлюзов это решение потенциально обеспечивает как Pod-to-Pod, так и узел-узел связность.
|
Примечание
|
При объединении кластеров с CNI в режиме инкапсуляции через VPN-туннели исходный пакет Pod-to-Pod оказывается дважды инкапсулирован: VXLAN или Geneve плюс IPsec. |
Подводя итог: существует целый спектр вариантов обеспечения Pod-to-Pod и узел-узел связности между кластерами. Хотя построение VXLAN-туннелей между узлами нередко является наиболее простым подходом, некоторые приложения не могут мириться с дополнительными накладными расходами на инкапсуляцию и ограничениями MTU.
Архитектура Cilium Cluster Mesh
Как верно отмечают в Isovalent, создатели Cilium: Cilium — это больше, чем CNI. Он решает большинство сетевых задач при управлении кластерами Kubernetes, и построение Cluster Mesh — одна из них. Чтобы понять логику компонентов Cilium Cluster Mesh, сначала полезно вспомнить архитектуру самого Cilium:
-
Cilium Agent — ядро Cilium. Реагирует на события от CNI и Kubernetes API, загружает eBPF-программы в ядро и в конечном счёте обеспечивает связность Pod. Запускается как
DaemonSet. -
Cilium Operator — контроллер, отвечающий за задачи уровня кластера, такие как управление IP-адресами. Запускается как
Deploymentс числом реплик, зависящим от размера кластера. -
Cilium Envoy — прокси на основе CNCF-проекта Envoy. Отвечает за функциональность уровня L7:
CiliumNetworkPoliciesи реализацию Cilium Kubernetes Gateway API. Также запускается какDaemonSet.
|
Примечание
|
Cilium Envoy не имеет отношения к функциональности Cilium Cluster Mesh, однако будет упомянут в практическом разделе. |
Cilium Cluster Mesh
Cilium Cluster Mesh — это решение Cilium для обеспечения восточно-западного взаимодействия между кластерами. Оно позволяет Pod, распределённым по нескольким кластерам, взаимодействовать так, будто они находятся в одном кластере. Для решения фундаментальных задач восточно-западной коммуникации (Service Discovery и Connectivity) Cilium Cluster Mesh придерживается следующих архитектурных принципов:
-
Выделенный Cluster Mesh API: вместо того чтобы разрешать удалённым кластерам запрашивать ресурсы из встроенного Kubernetes API, Cilium предоставляет эту информацию через отдельный компонент — Cluster Mesh API. Этот компонент запускает выделенный экземпляр etcd в контейнере
clustermesh-apiвнутри одноимённого Podclustermesh-api. Cilium Operator отвечает за синхронизацию ресурсов из Kubernetes API и Cluster Mesh API. Компонентclustermesh-apiоткрывается снаружи какLoadBalancerилиNodePort.
|
Примечание
|
Cilium Operator синхронизирует следующие ресурсы Kubernetes: |
-
Локальность данных: кластеры запрашивают информацию из удалённых кластеров через локальный
kvstoremesh— контейнер, работающий в Podclustermesh-api. Такой подход уменьшает количество соединений между кластерами и повышает масштабируемость внутри Cilium Cluster Mesh. В этих условиях Cilium-агенты поддерживают глобальное представлениеPodsиServices, запрашивая как встроенный экземпляр etcd (локальные данные), так и экземплярkvstoremesh(удалённые данные). -
Плоская сеть (Flat networking): Cilium Cluster Mesh ориентирован на топологию с единой сетью (single-network), то есть Pod в разных кластерах могут общаться по своим назначенным IP-адресам. Это требует, чтобы у каждого кластера был уникальный Pod CIDR.
Практика — сборка мультиоблачного приложения
Разобравшись с теорией, пора перейти к практике. В этом разделе показаны развёртывание и настройка мультиоблачного приложения на основе микросервисов, работающего на Kubernetes.
Приложение развёртывается в Amazon Web Services (AWS) и Google Cloud Platform (GCP). Часть уровней реплицируется в обоих облаках для повышения отказоустойчивости — как показано на схеме ниже.
Облачная инфраструктура
Отправная точка — облачная инфраструктура, в которой размещаются и взаимодействуют кластеры Kubernetes в AWS и GCP. Сюда входит настройка сетевого уровня: VPC, таблицы маршрутизации, шлюзы и VPN-туннели, обеспечивающие связь между средами.
Сами кластеры развёртываются с использованием управляемых сервисов Kubernetes каждого из провайдеров: Amazon Elastic Kubernetes Service (EKS) и Google Kubernetes Engine (GKE).
|
Примечание
|
Приведённый Terraform-проект разворачивает облачную инфраструктуру, необходимую для примера мультиоблачного приложения. В нём также есть инструкции по проверке сетевых компонентов. |
На схеме выше показаны основные компоненты каждой облачной среды, обеспечивающие мультиоблачную связность. Ключевые архитектурные элементы описаны ниже:
-
(AWS) Приватные подсети и доступ в интернет — рабочие узлы (инстансы EC2) размещаются в приватных подсетях, выход в интернет обеспечивается через NAT Gateway в публичной подсети, которая соединяется с интернетом через Internet Gateway. Таблицы маршрутизации управляют потоком трафика между подсетями и NAT-шлюзом.
-
(GCP) Подсети и доступ в интернет — рабочие узлы (VM) размещаются в подсетях VPC, выход в интернет обеспечивается Cloud NAT, привязанным к Cloud Router, что позволяет получать доступ в интернет без назначения публичных IP.
-
VPN-шлюзы и IPsec-туннели — AWS VPN Gateway и Cloud VPN Gateway устанавливают два IPsec-туннеля, обеспечивающих зашифрованное соединение с резервированием между сетями AWS и GCP.
-
Межвпс-маршрутизация — статические маршруты в AWS Site-to-Site VPN и Virtual Private Cloud направляют трафик для CIDR-диапазонов удалённого VPC через VPN-туннели.
Эта конфигурация позволяет рабочим узлам обоих кластеров общаться через VPN-туннель. Для упрощения восточно-западной маршрутизации Cilium работает в режиме инкапсуляции с VXLAN, для чего необходимо разрешить входящий VXLAN-трафик между подсетями узлов AWS и GCP.
|
Примечание
|
Полный список сетевых правил, необходимых для Cilium Cluster Mesh, можно найти по ссылке в документации. |
В мультиоблачном развёртывании используются следующие диапазоны подсетей (CIDR):
-
AWS VPC CIDR (рабочие узлы EKS): 192.168.1.0/24 и 192.168.2.0/24
-
GKE VPC CIDR (рабочие узлы GKE): 172.25.1.0/24
-
EKS Pod CIDR: 10.111.0.0/16
-
GKE Pod CIDR: 10.222.0.0/16
Поскольку Cilium работает в режиме инкапсуляции в обоих кластерах, AWS и GCP VPC не осведомлены о Pod CIDR, и маршруты для них в облачных таблицах маршрутизации не нужны.
Инфраструктура Kubernetes с Cilium
Когда облачная инфраструктура готова, следующий шаг — настройка Cilium на кластерах EKS и GKE, а также развёртывание уровней приложения в обоих окружениях. На схеме ниже изображены ресурсы Kubernetes, развёрнутые в каждом окружении.
В кластере EKS работают все уровни вымышленного приложения-книжного магазина (Bookstore), в то время как кластер GKE содержит только уровни reviews и ratings. Цель — настроить сервис reviews как глобальный, чтобы уровень productpage мог обращаться к его инстансам как в локальном кластере EKS, так и в кластере GKE через VPN-туннель.
Для простоты и концентрации исключительно на трафике «восток–запад» приложение открывается только в кластере EKS с помощью Gateway API, который в свою очередь открывается во внешний мир через AWS Network Load Balancer.
|
Примечание
|
Микросервисы приложения изображены как ресурсы Kubernetes |
Предполагая, что кластер развёрнут с помощью AWS CLI или Terraform-проекта, упомянутого ранее, доступ к кластеру EKS получают следующей командой aws CLI для обновления локального kubeconfig:
aws eks update-kubeconfig --region us-east-1 --name eks-cilium
Added new context arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium to /Users/jgomezve/.kube/config
Как уже говорилось, кластер EKS использует Kubernetes Gateway API для открытия приложения Bookstore. Поэтому в кластер устанавливаются необходимые Custom Resource Definitions (CRDs):
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/standard/gateway.networking.k8s.io_gatewayclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/standard/gateway.networking.k8s.io_gateways.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml
Затем Cilium устанавливается с включённой заменой kube-proxy (kube-proxy replacement), поскольку это является обязательным условием для использования Cilium в качестве GatewayClass в спецификации Gateway API. Поэтому перед установкой DaemonSet kube-proxy удаляется из кластера:
kubectl delete ds/kube-proxy -n kube-system
daemonset.apps "kube-proxy" deleted from kube-system namespace
cilium install --version 1.18.5 \
--set gatewayAPI.enabled=true \
--set kubeProxyReplacement=true \
--datapath-mode vxlan \
--set cluster.id=1 \
--set cluster.name=eks-cilium \
--set eni.enabled=false \
--set encapsulation.enabled=true \
--set encapsulation.type=vxlan \
--set ipam.mode=cluster-pool \
--set ipam.operator.clusterPoolIPv4PodCIDRList=10.222.0.0/16 \
--set ipam.operator.clusterPoolIPv4MaskSize=24
🔮 Auto-detected Kubernetes kind: EKS ℹ️ Using Cilium version 1.18.5 ℹ️ Using cluster name "eks-cilium" ℹ️ Custom datapath mode: vxlan 🔥 Patching the "aws-node" DaemonSet to evict its pods...
Эта команда задаёт VXLAN-инкапсуляцию как режим маршрутизации, а также настраивает идентификатор кластера (ID и имя) и CIDR для Pod.
Поскольку ресурс Gateway в Gateway API открывается через LoadBalancer, для интеграции сервисов Kubernetes с инфраструктурой балансировки нагрузки AWS устанавливается AWS Load Balancer Controller:
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=eks-cilium \
--set hostNetwork=true \
--set replicaCount=1
NAME: aws-load-balancer-controller LAST DEPLOYED: Fri Mar 6 17:29:27 2026 NAMESPACE: kube-system STATUS: deployed REVISION: 1 DESCRIPTION: Install complete TEST SUITE: None NOTES: AWS Load Balancer controller installed!
После установки этих компонентов Pod в пространстве имён kube-system кластера EKS обеспечивают работу ключевых платформенных сервисов: AWS Load Balancer Controller, Cilium и CoreDNS.
kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE aws-load-balancer-controller-76bc7cf87c-4xv4x 1/1 Running 0 56s 192.168.1.218 ip-192-168-1-218.ec2.internal cilium-envoy-b7scv 1/1 Running 0 2m10s 192.168.1.218 ip-192-168-1-218.ec2.internal cilium-operator-6655ff99d6-brss5 1/1 Running 0 2m10s 192.168.1.218 ip-192-168-1-218.ec2.internal cilium-pzw64 1/1 Running 0 2m10s 192.168.1.218 ip-192-168-1-218.ec2.internal coredns-789f8477df-ccw96 1/1 Running 0 3m17s 10.222.0.63 ip-192-168-1-218.ec2.internal coredns-789f8477df-gfmcd 1/1 Running 0 3m2s 10.222.0.158 ip-192-168-1-218.ec2.internal
Cilium также устанавливается на GKE, однако без включения функции замены kube-proxy — Gateway API ресурсы в GKE не используются.
Предполагая, что кластер развёрнут с помощью gcloud CLI или Terraform-проекта, для доступа к кластеру GKE локальный kubeconfig обновляется следующей командой:
gcloud container clusters get-credentials gke-cilium --zone us-central1-a --project cilium-mesh-489420
Fetching cluster endpoint and auth data. kubeconfig entry generated for gke-cilium.
Аналогично установке Cilium в EKS, режим маршрутизации задаётся как инкапсуляция с VXLAN. Поскольку конечная цель — объединить кластеры EKS и GKE через Cilium Cluster Mesh, для этого кластера устанавливается другой идентификатор Mesh, имя и Pod CIDR:
cilium install --version 1.18.5 \
--datapath-mode vxlan \
--set encapsulation.enabled=true \
--set encapsulation.type=vxlan \
--set cluster.id=2 \
--set cluster.name=gke-cilium \
--set eni.enabled=false \
--set ipam.mode=cluster-pool \
--set ipam.operator.clusterPoolIPv4PodCIDRList=10.111.0.0/16 \
--set ipam.operator.clusterPoolIPv4MaskSize=24
🔮 Auto-detected Kubernetes kind: GKE ℹ️ Using Cilium version 1.18.5 ℹ️ Using cluster name "gke-cilium" ℹ️ Custom datapath mode: vxlan 🔮 Auto-detected kube-proxy has been installed ✅ Detected GKE native routing CIDR: 10.111.0.0/16
Чтобы не запутаться при работе с клиентом kubectl, его конфигурация изменяется: каждому контексту присваивается удобочитаемое имя:
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO
arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium
* gke_cilium-mesh-489420_us-central1-a_gke-cilium gke_cilium-mesh-489420_us-central1-a_gke-cilium gke_cilium-mesh-489420_us-central1-a_gke-cilium
kubectl config rename-context arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium eks
Context "arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium" renamed to "eks".
kubectl config rename-context gke_cilium-mesh-489420_us-central1-a_gke-cilium gke
Context "gke_cilium-mesh-489420_us-central1-a_gke-cilium" renamed to "gke".
Наконец, ресурсы Kubernetes для приложения Bookstore развёртываются в обоих кластерах:
|
Примечание
|
Манифесты Kubernetes находятся в том же GitHub-проекте, что и файлы конфигурации Terraform для базовой инфраструктуры AWS и GCP. |
kubectl apply -f manifests/bookstore/app_eks.yaml --context eks
kubectl apply -f manifests/bookstore/app_gke.yaml --context gke
kubectl apply -f manifests/bookstore/gateway_api.yaml --context eks
По умолчанию Service типа LoadBalancer, открывающий Cilium Gateway, создаётся в приватной подсети и формирует внутренний AWS Network Load Balancer. Изменив аннотацию service.beta.kubernetes.io/aws-load-balancer-scheme, балансировщик можно перевести в режим internet-facing и получить внешний доступ к приложению:
kubectl patch svc cilium-gateway-bookinfo-gateway \
--context eks \
-p '{"metadata": {"annotations": {"service.beta.kubernetes.io/aws-load-balancer-scheme": "internet-facing"}}}'
service/cilium-gateway-bookinfo-gateway patched
На этом этапе приложение развёрнуто в обоих кластерах и доступно через Network Load Balancer в AWS. Однако весь трафик остаётся в AWS, поскольку плоскость управления EKS не знает о Pods и Services, работающих в GCP.
kubectl get svc --context eks
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE cilium-gateway-bookinfo-gateway LoadBalancer 10.100.74.255 k8s-default-ciliumga-302d831e91-678fd62a6405584d.elb.us-east-1.amazonaws.com 80:32424/TCP 8m38s details ClusterIP 10.100.156.37 <none> 9080/TCP 8m57s kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 51m productpage ClusterIP 10.100.63.105 <none> 9080/TCP 8m55s ratings ClusterIP 10.100.146.32 <none> 9080/TCP 8m57s reviews ClusterIP 10.100.105.6 <none> 9080/TCP 8m56s
Фронтенд productpage, открытый через Gateway API и AWS Load Balancer, показывает, какой Pod reviews обслуживает каждый запрос. Это позволяет легко проверить через браузер или curl, откуда берётся ответ. Pod в EKS следуют паттерну reviews-amazon-eks-, а в GKE — reviews-google-gke-.
LB=$(kubectl get svc cilium-gateway-bookinfo-gateway \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}' \
--context eks)
curl -s http://$LB/productpage | grep served -A 1
<div class="mt-0.5 text-gray-600 font-mono">Reviews served by: reviews-amazon-aws-5c4d6d447c-7g2w8 -- <div class="mt-0.5 text-gray-600 font-mono">Reviews served by: reviews-amazon-aws-5c4d6d447c-7g2w8
На этом этапе весь трафик обрабатывается Pod в кластере EKS.
Развёртывание Mesh с помощью Cilium Cluster Mesh
Cilium Cluster Mesh выделяется среди других решений для мультикластерной связности своей простотой. Для объединения кластеров Kubernetes достаточно всего двух шагов.
Первый шаг — включить компоненты плоскости управления Mesh на EKS и GKE:
cilium clustermesh enable --context eks --service-type LoadBalancer
cilium clustermesh enable --context gke --service-type LoadBalancer
|
Примечание
|
Команда выше создаёт внешний Network Load Balancer в GCP. Его можно настроить как внутренний с помощью следующей команды:
service/clustermesh-apiserver patched |
Конфигурацию компонентов плоскости управления Mesh можно проверить с помощью CLI cilium. Обратите внимание, что LoadBalancer, открывающий clustermesh-apiserver, использует приватный IP-адрес в диапазоне CIDR VPC. В результате kvstoremesh достигает удалённых кластеров через VPN-туннель. Это означает, что VPN-соединение несёт как трафик плоскости управления Cluster Mesh, так и трафик плоскости данных «восток–запад».
cilium clustermesh status --context eks
✅ Service "clustermesh-apiserver" of type "LoadBalancer" found ✅ Cluster access information is available: - 192.168.1.127:2379 ✅ Deployment clustermesh-apiserver is ready ℹ️ KVStoreMesh is enabled 🔌 No cluster connected
cilium clustermesh status --context gke
✅ Service "clustermesh-apiserver" of type "LoadBalancer" found ✅ Cluster access information is available: - 172.25.1.5:2379 ✅ Deployment clustermesh-apiserver is ready ℹ️ KVStoreMesh is enabled 🔌 No cluster connected
Этот шаг также можно проверить, посмотрев на новые компоненты плоскости управления в пространстве имён kube-system. Обратите внимание, что Deployment clustermesh-apiserver запущен и открыт снаружи через LoadBalancer.
|
Примечание
|
Здесь «снаружи» означает за пределами кластера GKE, но не за пределами GCP. |
kubectl get deployment,svc -n kube-system --context gke -l k8s-app=clustermesh-apiserver
NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/clustermesh-apiserver 1/1 1 1 20m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/clustermesh-apiserver LoadBalancer 10.111.250.104 172.25.1.9 2379:32366/TCP 20m service/clustermesh-apiserver-metrics ClusterIP None <none> 9962/TCP,9964/TCP,9963/TCP 20m
Второй шаг — настроить сам Mesh. Это делается одной командой, которая обнаруживает удалённый clustermesh-apiserver и настраивает локальный kvstoremesh для начала синхронизации ресурсов из удалённого кластера:
cilium clustermesh connect --context eks --destination-context gke
✨ Extracting access information of cluster eks-cilium... 🔑 Extracting secrets from cluster eks-cilium... ℹ️ Found ClusterMesh service IPs: [192.168.1.127] ✨ Extracting access information of cluster gke-cilium... 🔑 Extracting secrets from cluster gke-cilium... ℹ️ Found ClusterMesh service IPs: [172.25.1.5] ⚠️ Cilium CA certificates do not match between clusters. Multicluster features will be limited! ℹ️ Configuring Cilium in cluster arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium to connect to cluster gke_cilium-mesh-489420_us-central1-a_gke-cilium ℹ️ Configuring Cilium in cluster gke_cilium-mesh-489420_us-central1-a_gke-cilium to connect to cluster arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium ✅ Connected cluster arn:aws:eks:us-east-1:063089649137:cluster/eks-cilium <=> gke_cilium-mesh-489420_us-central1-a_gke-cilium!
|
Примечание
|
Команда |
При настройке Cluster Mesh Cilium обнаруживает, что кластеры EKS и GKE используют разные удостоверяющие центры (CA). Это намеренно: данный раздел сосредоточен исключительно на сетевых возможностях Cilium Cluster Mesh. Единый CA необходим для включения таких функций, как mTLS и наблюдаемость через Hubble между разными кластерами.
Команда cilium clustermesh status позволяет проверить состояние Mesh в каждом кластере:
cilium clustermesh status --context gke
✅ Service "clustermesh-apiserver" of type "LoadBalancer" found ✅ Cluster access information is available: - 172.25.1.5:2379 ✅ Deployment clustermesh-apiserver is ready ℹ️ KVStoreMesh is enabled ✅ All 1 nodes are connected to all clusters [min:1 / avg:1.0 / max:1] ✅ All 1 KVStoreMesh replicas are connected to all clusters [min:1 / avg:1.0 / max:1] 🔌 Cluster Connections: - eks-cilium: 1/1 configured, 1/1 connected - KVStoreMesh: 1/1 configured, 1/1 connected
cilium clustermesh status --context eks
✅ Service "clustermesh-apiserver" of type "LoadBalancer" found ✅ Cluster access information is available: - 192.168.1.127:2379 ✅ Deployment clustermesh-apiserver is ready ℹ️ KVStoreMesh is enabled ✅ All 1 nodes are connected to all clusters [min:1 / avg:1.0 / max:1] ✅ All 1 KVStoreMesh replicas are connected to all clusters [min:1 / avg:1.0 / max:1] 🔌 Cluster Connections: - gke-cilium: 1/1 configured, 1/1 connected - KVStoreMesh: 1/1 configured, 1/1 connected
Состояние Cluster Mesh также можно проверить изнутри любого из Cilium-агентов с помощью команды cilium-health status. IP-адреса в выводе команды — это адреса рабочих узлов GKE/EKS:
kubectl --context eks -n kube-system exec ds/cilium -- cilium-health status
Cluster health: 2/2 reachable (2026-03-06T22:58:15Z) (Probe interval: 1m36.566274746s) Name IP Node Endpoints eks-cilium/ip-192-168-1-218.ec2.internal (localhost) 192.168.1.218 1/1 1/1 gke-cilium/gke-gke-cilium-gke-cilium-nodes-b5b3d145-hr3k 172.25.1.4 1/1 1/1
Определение глобальных сервисов
Последний шаг для организации восточно-западного трафика между кластерами EKS и GKE — пометить Services как глобальные. Это изменяет поведение балансировки нагрузки Service, включая в пул эндпоинты из обоих кластеров.
В контексте приложения Bookstore пометка микросервиса reviews как глобального позволяет productpage направлять запросы как локально внутри AWS, так и через VPN-туннель к эндпоинтам в GCP.
Как показано ниже, до того как Service reviews обозначен как глобальный, его IP (10.100.105.6) в EKS включает в бэкенд балансировки только локальный Pod IP (10.222.0.132):
kubectl get svc --context eks
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE cilium-gateway-bookinfo-gateway LoadBalancer 10.100.74.255 k8s-default-ciliumga-302d831e91-678fd62a6405584d.elb.us-east-1.amazonaws.com 80:32424/TCP 31m details ClusterIP 10.100.156.37 <none> 9080/TCP 32m kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 75m productpage ClusterIP 10.100.63.105 <none> 9080/TCP 32m ratings ClusterIP 10.100.146.32 <none> 9080/TCP 32m reviews ClusterIP 10.100.105.6 <none> 9080/TCP 32m
kubectl --context eks exec -it -n kube-system -ti ds/cilium -- cilium service list
ID Frontend Service Type Backend 9 10.100.156.37:9080/TCP ClusterIP 1 => 10.222.0.228:9080/TCP (active) 10 10.100.146.32:9080/TCP ClusterIP 1 => 10.222.0.110:9080/TCP (active) 11 10.100.105.6:9080/TCP ClusterIP 1 => 10.222.0.132:9080/TCP (active) 12 10.100.63.105:9080/TCP ClusterIP 1 => 10.222.0.211:9080/TCP (active)
Сервисы помечаются как глобальные установкой аннотации service.cilium.io/global в значение true на всех экземплярах Service в Mesh — в данном случае в кластерах EKS и GKE:
kubectl patch service reviews --context eks \
-p '{"metadata":{"annotations":{"service.cilium.io/global":"true"}}}'
service/reviews patched
kubectl patch service reviews --context gke \
-p '{"metadata":{"annotations":{"service.cilium.io/global":"true"}}}'
service/reviews patched
После этой настройки IP-адрес сервиса (10.100.105.6) микросервиса reviews в EKS включает в бэкенд балансировки как локальный Pod IP (10.222.0.132), так и удалённый Pod IP (10.111.0.228):
kubectl --context eks exec -it -n kube-system -ti ds/cilium -- cilium service list
ID Frontend Service Type Backend
9 10.100.156.37:9080/TCP ClusterIP 1 => 10.222.0.228:9080/TCP (active)
10 10.100.146.32:9080/TCP ClusterIP 1 => 10.222.0.110:9080/TCP (active)
11 10.100.105.6:9080/TCP ClusterIP 1 => 10.111.0.228:9080/TCP (active)
2 => 10.222.0.132:9080/TCP (active)
12 10.100.63.105:9080/TCP ClusterIP 1 => 10.222.0.211:9080/TCP (active)
Открыв приложение Bookstore через IP LoadBalancer — в браузере или с помощью curl — можно увидеть, какой Pod reviews обрабатывает каждый запрос. Повторные запросы показывают, что трафик обслуживается как EKS, так и GKE, подтверждая межкластерную балансировку.
Это распределение можно также проверить скриптом ниже, который показывает равномерную балансировку запросов:
LB=$(kubectl get svc cilium-gateway-bookinfo-gateway \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}' \
--context eks)
for i in {1..100}; do
curl -s http://$LB/productpage \
| grep "Reviews served by" -A 1 \
| tail -n1 \
| xargs
done | sort | uniq -c
48 reviews-amazon-aws-5c4d6d447c-7kbk4 52 reviews-google-gke-546db757d8-4krjq
Эффективная балансировка нагрузки
В некоторых сценариях балансировка нагрузки «восток–запад» нежелательна по умолчанию. Отправка запросов в удалённый кластер — через зоны доступности, регионы или облака — может повлечь дополнительные сетевые расходы. Например, в приложении Bookstore обращение к уровню, размещённому в GKE, имеет смысл только в случае отказа (failover).
Cilium Cluster Mesh поддерживает сервисное сродство (service affinity) — предпочтение расположения для межкластерного трафика. По умолчанию у сервисов нет сродства, и трафик распределяется по всем кластерам.
Сродство можно задать как local (локальное) или remote (удалённое). Установив аннотацию service.cilium.io/affinity=local на Service reviews, кластер EKS всегда предпочитает локальные эндпоинты и направляет трафик в GKE только в случае недоступности локальных Pod.