Kubernetes на нескольких континентах: высокодоступные k3s и k8s в дата-центрах по всему миру

Опубликовано 13 мин. чтения

Kubernetes в США, Европе и Азии, в котором допустим отказ целого континента: почему etcd не переносит больших расстояний, кластер k3s в каждом регионе, GitOps с Flux, failover через Geo-DNS, данные между регионами и отличия от kubeadm.

Если приложения должны работать отказоустойчиво и автоматически масштабироваться, стандартом служит Kubernetes. Однако очевидная идея растянуть один-единственный кластер Kubernetes на серверы в США, Европе и Азии разбивается об одну деталь: об etcd, базу данных, в которой Kubernetes хранит всё своё состояние. В этой статье показано, как Kubernetes на нескольких континентах всё же работает, причём так, что допустим отказ целого континента: с одним кластером на регион, единым развёртыванием через GitOps и Geo-DNS, который направляет пользователей в ближайший исправный регион.

Архитектуру мы строим на k3s, лёгком, полностью сертифицированном дистрибутиве Kubernetes, который устанавливается за считаные минуты, а в конце показываем, что меняется с классическим Kubernetes, развёрнутым через kubeadm. Основы доступности, кворума и failover на нескольких площадках подробно разобраны в статье Docker Swarm на трёх континентах; здесь речь идёт о том, что в Kubernetes устроено иначе.

Один кластер на все континенты или по кластеру на регион?

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

Почему etcd не переносит больших расстояний

Kubernetes хранит всё состояние, каждую настройку и каждое изменение в etcd, хранилище «ключ-значение» с консенсусом Raft. Каждая операция записи требует подтверждения от большинства всех участников etcd. По умолчанию etcd работает с интервалом heartbeat 100 миллисекунд и тайм-аутом выборов в одну секунду, а время прохождения пакетов между Европой, Северной Америкой и Азией составляет от 80 до 250 миллисекунд. Эти значения можно увеличить, но тогда медленной становится любая запись в кластере, от планирования пода до сохранения секрета. Документация k3s здесь однозначна: встроенный etcd не поддерживается в кластерах, распределённых по нескольким сетям, и все серверы должны находиться на одной площадке. Да и сам Kubernetes рассчитан на то, что кластер охватывает несколько зон внутри одного региона, а не несколько континентов.

Сравнение трёх схем

СхемаКак это работаетОценка
Один кластер на все континентыУправляющий слой и etcd распределены по нескольким континентамНе рекомендуется: медленная запись, нестабильный etcd, в k3s со встроенным etcd не поддерживается
Управляющий слой в одном регионе, рабочие узлы по всему мируСерверы на одной площадке, агенты на других континентахТехнически работает, но если регион с управляющим слоем выходит из строя, нигде в мире больше ничего нельзя запланировать заново
Один кластер на регионТри независимых кластера, которые вместе выкатываются через GitOps, перед ними Geo-DNSРекомендуется: каждый регион переживает отказ остальных, сбои не выходят за пределы одного региона

У подхода «один кластер на регион» есть второе, часто недооцениваемое преимущество: ошибка в управляющем слое, неудачное изменение в кластере или обновление, которое пошло не так, всегда затрагивают только один регион. Пользователи других регионов ничего не замечают.

k3s или k8s?

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

Характеристикаk3sk8s с kubeadm
УстановкаОдна команда, один бинарный файлСреда выполнения контейнеров, kubeadm, kubelet и сетевой плагин настраиваются по отдельности
Ресурсы для серверного узлаМинимум 2 ядра и 2 ГБ ОЗУЗаметно больше, в зависимости от компонентов
В комплектеIngress-контроллер (Traefik), сеть (Flannel), провижинер хранилища, балансировщик нагрузки для сервисовТолько ядро, всё остальное вы выбираете сами
Высокая доступностьВстроенный etcd на трёх серверахТри узла control plane с балансировщиком нагрузки перед API
Подходит дляБольшинства приложений, небольших команд, одиночных узлов в регионахКоманд, которые хотят сами выбирать каждый компонент

Для архитектуры «один кластер на регион» мы рекомендуем k3s: эксплуатировать три кластера удобно лишь тогда, когда каждый из них прост. Если у вас уже есть опыт работы с kubeadm, вы можете применить эту архитектуру без изменений, а различия показаны в разделе о kubeadm ниже.

Архитектура: три региона, три кластера, одна точка входа

КомпонентЗадачаОт какого отказа защищает
Кластер k3s в каждом регионеЗапускает приложение рядом с пользователямиОтказ целого региона
Три сервера на регион (этап расширения)Обеспечивает высокую доступность etcd и управляющего слоя внутри регионаОтказ отдельных серверов в регионе
Git-репозиторий и Flux в каждом кластереКаждый кластер сам забирает своё желаемое состояние из GitНет центрального сервера развёртывания, который стал бы точкой отказа
Ingress с сертификатами через DNS-challengeПринимает запросы пользователейСертификаты работают независимо от переключения DNS
Geo-DNS с проверками доступностиНаправляет пользователей в ближайший исправный регионНедоступные регионы
Реплицируемое хранение данных и резервные копииХранит данные в нескольких регионахПотеря данных при отказе региона

Начальный этап и расширение

На начальном этапе нужны три сервера, по одному в США, Европе и Азии, и каждый работает как отдельный кластер из одного узла. Если сервер выходит из строя, вместе с ним отказывает и его регион, а Geo-DNS направляет пользователей этого региона в соседний. Уже этот этап рассчитан на отказ целого континента. При расширении каждый регион получает три сервера на одной площадке; тогда каждый регион и сам по себе переживает отказ одного сервера, без перенаправления пользователей.

Какие локации KernelHost подходят

KernelHost эксплуатирует серверы в дата-центре maincubes во Франкфурте-на-Майне и предлагает виртуальные серверы в других локациях в Европе, Северной Америке и Азиатско-Тихоокеанском регионе, в том числе в трёх локациях в США, а также в Канаде, Лондоне, Страсбурге, Варшаве, Хельсинки, Сингапуре, Японии, Сиднее и Мумбаи. Полный список приведён на странице Локации серверов. В примере этой статьи используются Франкфурт-на-Майне для Европы, восточное побережье США для Северной Америки и Сингапур для Азии.

Руководство: Kubernetes на k3s в трёх регионах

В примере используются три сервера с Debian 12 или 13: k3s-eu, k3s-us и k3s-asia. Публичные адреса взяты из диапазона для документации 203.0.113.0/24, в качестве домена выступает example.com. Замените и то, и другое своими значениями.

Шаг 1: подготовить серверы в трёх регионах

Закажите три сервера в трёх регионах, минимум с 2 vCPU и 4 ГБ ОЗУ, чтобы помимо k3s хватило места и для вашего приложения. Выполните базовую защиту по чек-листу для новых root-серверов и задайте понятные имена хостов. etcd заметно выигрывает от быстрых SSD, и NVMe-накопители серверов KernelHost этому требованию отвечают.

Шаг 2: установить k3s

На каждый из трёх серверов установите k3s одной командой. После этого каждый сервер становится полноценным кластером Kubernetes из одного узла:

curl -sfL https://get.k3s.io | sh -
kubectl get nodes

Примерно через минуту kubectl get nodes покажет узел в состоянии Ready. В комплект входят Traefik в качестве Ingress-контроллера, Flannel для сети и провижинер для локальных томов.

Шаг 3: расширение до трёх серверов на регион

Если высокодоступным должен стать и сам регион, разместите три сервера на одной площадке. Первый сервер запускает встроенный etcd, два других присоединяются к нему с общим токеном. etcd требует нечётного числа серверов, и при трёх серверах регион выдерживает отказ одного из них:

curl -sfL https://get.k3s.io | K3S_TOKEN=СЕКРЕТНЫЙ_ТОКЕН sh -s - server \
    --cluster-init \
    --tls-san=api.eu.example.com
curl -sfL https://get.k3s.io | K3S_TOKEN=СЕКРЕТНЫЙ_ТОКЕН sh -s - server \
    --server https://203.0.113.21:6443 \
    --tls-san=api.eu.example.com

Всем серверам одного региона нужны одинаковые настройки сетевых диапазонов и функций. Между ними должны быть открыты порты от 2379 до 2380/TCP для etcd, 6443/TCP для API, 10250/TCP для kubelet и 8472/UDP для сети Flannel, а снаружи они остаются закрытыми. Токен является секретом: тот, кто его знает, может подключить к кластеру собственные серверы.

Шаг 4: настроить доступ ко всем трём кластерам

k3s сохраняет данные для доступа в файле /etc/rancher/k3s/k3s.yaml. Скопируйте этот файл из каждого кластера на свой рабочий компьютер, замените в нём 127.0.0.1 адресом сервера и назовите контексты по регионам:

kubectl config rename-context default eu
kubectl config use-context eu
kubectl --context us get nodes

API на порту 6443 открывает самый мощный доступ к кластеру. Разрешайте его в файрволе только со своего адреса или через VPN и никогда для всего интернета. Файл k3s.yaml содержит сертификат администратора, и хранить его нужно так же бережно, как пароль root.

Шаг 5: GitOps с Flux в каждом кластере

Чтобы во всех трёх регионах работало одно и то же приложение одной и той же версии, желаемое состояние хранится в Git-репозитории, а в каждом кластере работает Flux, который самостоятельно приводит кластер к этому состоянию. Таким образом, каждый кластер сам забирает свою конфигурацию, и центрального сервера развёртывания, который мог бы выйти из строя, нет. Проверенная структура репозитория:

apps/
  web/            общие манифесты приложения
clusters/
  eu/             настройки и версия для Европы
  us/             настройки и версия для Северной Америки
  asia/           настройки и версия для Азии
flux bootstrap git --url=ssh://git@git.example.com/infra/fleet.git --branch=main --path=clusters/eu

Ту же команду выполните с --path=clusters/us и --path=clusters/asia в соответствующем контексте. Поскольку у каждого региона свой каталог, новую версию можно сначала выкатить в одном регионе и лишь затем в остальных.

Шаг 6: описать приложение с учётом отказоустойчивости

Внутри региона пережить обслуживание и отказы серверов приложению помогают три вещи: несколько реплик, распределённых по разным узлам, проверки, которые распознают неисправные поды, и бюджет, который не даёт обслуживанию убрать все поды одновременно:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: web
      containers:
        - name: web
          image: registry.example.com/web:1.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 10
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: web

Readiness-проба исключает под из обработки трафика, пока он не отвечает, а liveness-проба перезапускает его, если он завис. В кластере из одного узла распределение по нескольким узлам пока не действует, оно включается автоматически, как только в регионе появятся три сервера.

Шаг 7: Ingress и сертификаты

Входящий трафик принимает встроенный Traefik. Поскольку все три региона обслуживают один и тот же домен, получайте TLS-сертификаты с помощью cert-manager через DNS-challenge: такая проверка работает в любом регионе, независимо от того, куда в данный момент указывает DNS-запись. HTTP-challenge, напротив, не проходит в каждом регионе, на который запись в данный момент не указывает. Если вы работаете без Kubernetes Ingress, основы найдёте в статье Настройка nginx как reverse proxy.

Шаг 8: настроить Geo-DNS с failover

DNS-сервис с геомаршрутизацией и проверками доступности направляет пользователей из Европы во Франкфурт-на-Майне, из Америки на восточное побережье США, а из Азии в Сингапур и с интервалом от 30 до 60 секунд проверяет, отвечает ли точка входа каждого региона. Если регион выходит из строя, сервис перестаёт выдавать его адрес. Задайте для записей TTL 60 секунд, тогда переключение обычно завершается через одну-две минуты. Если вы хотите управлять записями прямо из кластера, для этого можно использовать external-dns.

Шаг 9: выкатывать регион за регионом и тестировать отказ

Новую версию сначала пропишите в каталоге одного региона, понаблюдайте за этим регионом несколько минут и только затем перенесите версию в остальные. Так ошибка, которую не распознаёт ни одна проверка, затронет самое большее один регион. Чтобы отрепетировать отказ региона, остановите k3s на его сервере и проверьте, убирает ли Geo-DNS этот регион из своих ответов и берёт ли соседний регион нагрузку на себя:

systemctl stop k3s
systemctl start k3s

В регионе с тремя серверами дополнительно отрепетируйте обслуживание отдельного сервера. kubectl drain переносит поды с учётом бюджета из шага 6, а kubectl uncordon снова вводит сервер в работу:

kubectl drain k3s-eu-2 --ignore-daemonsets --delete-emptydir-data
kubectl uncordon k3s-eu-2

Данные между регионами

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

  • Базы данных реплицируются собственными средствами. Хорошо зарекомендовала себя схема с основным экземпляром в одном регионе и репликами в остальных; операторы баз данных вроде CloudNativePG для PostgreSQL поддерживают такие реплики и через границы кластеров. Между континентами репликация идёт асинхронно, и в случае аварии записи за последние секунды могут быть потеряны. Для записи без потерь по всему миру существуют мультирегиональные базы данных, например CockroachDB или YugabyteDB.
  • Файлы и загрузки должны храниться в S3-совместимом объектном хранилище с репликацией во второй регион.
  • Сессии хранятся в реплицируемой базе данных или реплицируемом кэше, либо приложение использует подписанные токены.
  • Резервные копии остаются обязательными, потому что репликация распространяет ошибки точно так же, как корректные данные. Для объектов и томов Kubernetes подходит Velero, а основы описаны в стратегии резервного копирования для серверов.

Kubernetes с kubeadm вместо k3s

С kubeadm архитектура остаётся прежней: один кластер на регион, GitOps, Geo-DNS. Отличается устройство каждого кластера. На все узлы вы устанавливаете среду выполнения контейнеров вроде containerd, а также kubeadm, kubelet и kubectl, ставите перед API региона балансировщик нагрузки или виртуальный адрес, например с помощью kube-vip, и инициализируете первый узел control plane:

kubeadm init --control-plane-endpoint "api.eu.example.com:6443" --upload-certs

Вывод содержит две команды присоединения: одну с --control-plane --certificate-key для двух дополнительных узлов control plane и одну для рабочих узлов. После этого вы устанавливаете сетевой плагин, например Calico или Cilium, и Ingress-контроллер, который в k3s уже есть в комплекте. Дополнительные усилия оправданы, если вам нужно целенаправленно выбирать отдельные компоненты или держаться как можно ближе к upstream-версии.

Почему KernelHost для Kubernetes на нескольких континентах

ТребованиеПочему это важноВ KernelHost
Локации на нескольких континентахСхеме «один кластер на регион» нужны серверы в каждом регионеФранкфурт-на-Майне, а также локации в Европе, Северной Америке и Азиатско-Тихоокеанском регионе у одного провайдера
Безлимитный трафикЗагрузка образов, репликация баз данных и резервное копирование постоянно создают трафикVPS с безлимитным трафиком без ограничения объёма
Быстрые накопителиetcd чувствителен к медленным дискамNVMe SSD в RAID
Защита от DDoSКаждый Ingress доступен из интернетаВключена в каждой локации, на основной площадке во Франкфурте-на-Майне с фильтрацией Arbor в реальном времени на 3,2 Тбит/с, без null-routing
Полный root-доступДля k3s, файрвола и настроек ядра нужен полный контрольНа каждом KVM root-сервере и выделенном сервере
Без долгосрочного договораУзлы и тестовые кластеры появляются и исчезаютPrePaid, без минимального срока, без платы за подключение
АвтоматизацияНовые узлы должны создаваться скриптомЗаказ и управление через KernelHost API

Обзор всех облачных тарифов и сравнение стоимости с крупными облачными провайдерами вы найдёте на странице Аренда облачного сервера.

Частые ошибки и как их избежать

  • etcd растянут на несколько континентов. Следствием становятся медленная запись и нестабильные выборы лидера, а в k3s со встроенным etcd такая схема не поддерживается. Решение: один кластер на регион.
  • Два сервера в одном регионе. etcd нужно большинство, и два сервера не выдерживают ни одного отказа. Решение: один или три.
  • API открыт для всего интернета. Порт 6443 служит мастер-ключом к кластеру. Решение: доступ только со своего адреса или через VPN.
  • Центральный сервер развёртывания. Если он выходит из строя, выкатить больше ничего нельзя. Решение: Flux в каждом кластере, самостоятельно забирающий всё необходимое из Git.
  • Обновление во всех регионах одновременно. Тогда ошибка затрагивает всех пользователей. Решение: регион за регионом через каталоги в репозитории.
  • Сертификаты через HTTP-challenge. В регионах, на которые DNS-запись в данный момент не указывает, продление не проходит. Решение: DNS-challenge.
  • База данных на локальном томе без репликации. Если узел выходит из строя, данные недоступны. Решение: репликация через оператор базы данных.
  • Ни проб, ни бюджета. Неисправные поды продолжают получать трафик, а обслуживание снимает с сети все поды одновременно. Решение: readiness- и liveness-пробы плюс PodDisruptionBudget.

Коротко о главном

  • Для Kubernetes на нескольких континентах правильно строить по одному кластеру на регион, а единый кластер на все континенты упирается в задержки, которые не переносит etcd.
  • Для начала нужны три сервера, по одному в США, Европе и Азии; уже этот этап переживает отказ целого континента.
  • При расширении каждый регион получает три сервера на одной площадке, и тогда каждый регион переживает также отказы отдельных серверов.
  • Flux в каждом кластере выкатывает приложение из одного и того же Git-репозитория, регион за регионом.
  • Geo-DNS с проверками доступности и коротким TTL направляет пользователей в ближайший исправный регион, а сертификаты выпускаются через DNS-challenge.
  • Kubernetes распределяет поды, а не данные: базам данных нужна собственная репликация, резервные копии остаются обязательными.
  • Для этой архитектуры k3s обычно подходит лучше, чем kubeadm, потому что три простых кластера эксплуатировать легче, чем три сложных.

Частые вопросы

Может ли кластер Kubernetes работать на нескольких континентах?
Технически управляющий слой можно распределить, но делать так не рекомендуется. Kubernetes хранит своё состояние в etcd, и каждая операция записи требует подтверждения от большинства всех участников etcd. Задержка между континентами составляет от 80 до 250 миллисекунд, а etcd по умолчанию работает с интервалом heartbeat 100 миллисекунд. Согласно документации k3s, встроенный etcd в кластерах, распределённых по нескольким сетям, не поддерживается. Правильное решение: один кластер на регион.
Как построить высокодоступный Kubernetes в нескольких регионах?
С отдельным кластером в каждом регионе, например по одному кластеру k3s в США, в Европе и в Азии. Все кластеры выкатываются через GitOps из одного и того же Git-репозитория, скажем с помощью Flux в каждом кластере, а Geo-DNS с проверками доступности направляет пользователей в ближайший исправный регион. Если регион выходит из строя, работу берут на себя остальные, и общее состояние не нужно согласовывать через океан.
Чем k3s отличается от k8s?
Оба варианта представляют собой полноценный Kubernetes с тем же API и теми же манифестами. k3s является лёгким сертифицированным дистрибутивом в виде одного бинарного файла, который устанавливается одной командой и уже включает Ingress-контроллер, сеть и провижинер хранилища; серверу нужно минимум 2 ядра и 2 ГБ ОЗУ. Кластер k8s на kubeadm собирается из отдельных компонентов, даёт больше свободы выбора и требует больше усилий.
Сколько серверов нужно высокодоступному кластеру k3s?
Три серверных узла со встроенным etcd на одной площадке. etcd нужно большинство, поэтому три сервера выдерживают отказ одного из них. Два сервера ничего не дают, потому что отказ любого из двух лишает кластер большинства. Для Kubernetes на нескольких континентах на начальном этапе хватает трёх кластеров из одного узла, по одному на регион, потому что отказ целого региона перехватывает Geo-DNS.
Какие порты нужны k3s?
API Kubernetes и супервизор k3s работают на порту 6443/TCP, kubelet на 10250/TCP, сеть Flannel с VXLAN на 8472/UDP, а с WireGuard на 51820/UDP. При нескольких серверах со встроенным etcd между серверами добавляются порты от 2379 до 2380/TCP. Ни один из этих портов не должен быть открыт в интернет, доступ к API разрешайте только со своего адреса или через VPN.
Как выкатывать приложения в несколько кластеров Kubernetes?
Через GitOps: желаемое состояние всех кластеров хранится в Git-репозитории, а в каждом кластере работает инструмент вроде Flux, который самостоятельно приводит кластер к этому состоянию. У каждого региона свой каталог, поэтому новую версию можно сначала выкатить в одном регионе, а после периода наблюдения в остальных. Центрального сервера развёртывания, который мог бы выйти из строя, при этом нет.
Как работает failover между регионами Kubernetes?
Через DNS-сервис с геомаршрутизацией и проверками доступности. Он направляет пользователей в ближайший регион и с интервалом от 30 до 60 секунд проверяет, отвечает ли Ingress каждого региона. Если регион выходит из строя, сервис перестаёт выдавать его адрес и направляет пользователей в ближайший исправный регион. При TTL 60 секунд переключение обычно завершается через одну-две минуты.
Как сохранить данные при отказе региона?
Kubernetes распределяет поды, а не данные. Поэтому базы данных реплицируются собственными средствами, например PostgreSQL с оператором CloudNativePG, который поддерживает реплики и через границы кластеров. Между континентами репликация идёт асинхронно, и в случае аварии записи за последние секунды могут быть потеряны. Файлы должны храниться в реплицируемом объектном хранилище, а регулярные резервные копии, например с помощью Velero, остаются обязательными.
Kubernetes или Docker Swarm для нескольких континентов?
Docker Swarm можно растянуть одним кластером на три континента, и эксплуатировать его заметно проще. Kubernetes даёт больше автоматизации и более широкую экосистему, но на нескольких континентах его эксплуатируют как отдельный кластер в каждом регионе и объединяют через GitOps. Для небольших команд с несложными приложениями Swarm часто оказывается прагматичным выбором, а для сложных платформ таким выбором будет Kubernetes.
Какие локации KernelHost подходят для Kubernetes на нескольких континентах?
KernelHost предлагает серверы во Франкфурте-на-Майне, а также в других локациях в Европе, Северной Америке и Азиатско-Тихоокеанском регионе, в том числе в трёх локациях в США, в Канаде, Лондоне, Страсбурге, Варшаве, Хельсинки, Сингапуре, Японии, Сиднее и Мумбаи. Проверенная комбинация: Франкфурт-на-Майне, восточное побережье США и Сингапур, в каждом регионе по одному или по три сервера на одной площадке.
Сколько стоит Kubernetes на трёх континентах?
На начальном этапе нужны три сервера, по одному на регион, при расширении девять, плюс DNS-сервис с проверками доступности. Сам k3s бесплатен. Поскольку репликация, резервное копирование и загрузка образов постоянно создают трафик, решающее значение имеют тарифы с безлимитным трафиком. В KernelHost VPS с безлимитным трафиком работают без ограничения объёма, по модели PrePaid без минимального срока и без платы за подключение, поэтому кластеры можно увеличивать или уменьшать по мере необходимости.

Kubernetes k3s k8s kubeadm Высокая доступность Мультирегиональность GitOps Flux Geo-DNS Облако