K3s на колёсах: HA-кластер для автопарка с ARM-агентами, WireGuard и офлайн-режимом
Большинство материалов о Kubernetes на периферии рассматривают относительно стабильную инфраструктуру: узлы находятся в дата-центрах, между ними работает предсказуемая сеть, а разрывы соединения случаются редко. В автопарке ситуация принципиально иная. Control plane размещён в офисе или дата-центре, тогда как worker-узлы установлены непосредственно в транспортных средствах. Машины перемещаются по городу, заезжают в подземные паркинги, теряют VPN и могут оставаться без связи с центральной площадкой десятки минут.
Для такой системы обрыв соединения - не аварийный сценарий, а обычное состояние, которое необходимо учитывать ещё на этапе проектирования. Именно поэтому [K3s-кластер для автопарка](https://habr.com/ru/articles/1079024/?utm_campaign=1079024&utm_source=habrahabr&utm_medium=rss) строится с учётом нестабильной сети, ограниченных ресурсов и разнородного оборудования. В архитектуре используются отказоустойчивый control plane на трёх узлах, виртуальный IP через kube-vip, WireGuard поверх MikroTik, а также агенты на amd64 и ARM, включая модули NVIDIA Jetson.
Почему выбран K3s
Главное преимущество K3s в данном случае заключается не только в простой установке. Это компактный статический бинарник со встроенным containerd, которому не требуется отдельный etcd на каждом агентском узле. Благодаря небольшому потреблению памяти K3s заметно лучше подходит для одноплатных компьютеров и бортовых систем.
На слабом ARM-устройстве разница между обычным Kubernetes и облегчённым дистрибутивом может быть критичной: в одном случае сервисы стабильно работают, в другом kubelet регулярно завершается из-за нехватки памяти, а приложения попадают под действие OOM killer. Поэтому K3s становится практичным выбором для сценария Kubernetes для периферийных устройств, где важны компактность и способность работать на ограниченном железе.
Отказоустойчивый control plane
Центральная часть кластера состоит из трёх серверов K3s с embedded etcd. Нечётное количество узлов необходимо для сохранения кворума: два сервера не дают полноценного запаса по отказоустойчивости, тогда как три позволяют пережить потерю одного участника.
Однако одного HA-кластера недостаточно. Агентам и администраторам нужен единый адрес control plane, а не список из трёх IP-адресов с ручным переключением. Для этого перед серверами используется kube-vip. Компонент назначает виртуальный IP одному из узлов, а при отказе текущего лидера выполняет выборы и переносит адрес на доступный сервер.
В результате для агентов ничего не меняется: они продолжают обращаться к тому же адресу, даже если фактический узел, обслуживающий запросы, сменился. Это особенно важно для удалённых машин, где ручное изменение конфигурации невозможно или требует дорогостоящего выезда.
Развёртывание выполняется с помощью собственных Ansible-ролей `k3s_server` и `k3s_agent`. Такой подход позволяет использовать единый процесс для офисного amd64-сервера и ARM-платы в автомобиле, учитывая различия в версиях K3s, параметрах systemd, доступной памяти и сетевой конфигурации.
WireGuard и MikroTik
Агенты не находятся в одной локальной сети с control plane. Каждый удалённый узел подключается через WireGuard-туннель, который завершается на MikroTik. Поддержка WireGuard появилась в RouterOS 7, поэтому для VPN-концентратора не требуется устанавливать отдельный Linux-сервер на каждой площадке.
Это существенно упрощает эксплуатацию большого числа точек присутствия. Маршрутизатор уже отвечает за сетевую связность, а дополнительный VPN-бокс увеличивал бы количество оборудования, точек отказа и операций технического обслуживания. Такой K3s кластер через WireGuard позволяет объединить центральные серверы и мобильные агенты в единую логическую сеть без необходимости предоставлять им прямой доступ через публичные адреса.
У RouterOS есть и дополнительная возможность: запуск Linux-контейнеров через собственный механизм Container. В перспективе это позволяет разместить на пограничном маршрутизаторе лёгкий `node_exporter`, прокси или вспомогательный сетевой сервис, не добавляя отдельное устройство. В производственной среде такой вариант пока не используется, но он хорошо соответствует принципу минимизации количества компонентов на границе.
Пробы и нестабильный канал
WireGuard обеспечивает защищённый транспорт, но не делает канал стабильным. Задержка между машиной и дата-центром может резко меняться, пакеты теряются, а соединение периодически полностью исчезает. Это напрямую влияет на настройку readiness- и liveness-проб Kubernetes.
Типичная ошибка - использовать liveness-проверку, которая обращается к внешней базе данных, API или сервису через VPN. При кратковременной задержке приложение признаётся неисправным, kubelet перезапускает контейнер, а затем запускает его снова. В итоге временная проблема сети превращается в бесконечный restart loop.
Liveness должна отвечать только на вопрос о жизнеспособности самого процесса. Проверки внешних зависимостей разумнее выносить в readiness или реализовывать отдельной логикой мониторинга. Если приложению временно недоступна центральная система, это ещё не означает, что его необходимо уничтожать.
Readiness также требует аккуратной настройки. Когда control plane или внешний API временно недоступны, приложение может продолжать выполнять локальную работу, но Kubernetes будет считать его неготовым для обслуживания трафика. Поэтому параметры таймаутов, `failureThreshold` и `periodSeconds` следует подбирать с учётом реальных условий мобильной сети, а не типичных значений для дата-центра.
ARM, Jetson и cgroups
Отдельный класс проблем возникает на устройствах NVIDIA Jetson. В окружении JetPack 5.3.1 поведение cgroups и системных компонентов может отличаться от привычной серверной конфигурации Linux. При этом версия kubelet 1.36 предъявляет собственные требования к иерархии cgroups и взаимодействию с systemd.
На практике необходимо заранее проверять режим cgroups, настройки containerd, лимиты памяти и параметры запуска kubelet. Простая установка K3s ещё не гарантирует корректную работу всех компонентов. Особенно важно тестировать обновление не на одном стенде, а на каждом типе аппаратной платформы: стандартном ARM-устройстве, Jetson и amd64-сервере могут проявлять разные ошибки при одинаковых манифестах.
Обновления в разнородном флоте
В автопарке нельзя рассчитывать, что все агенты одновременно доступны для обновления. Часть машин находится на линии, часть - в гараже, а некоторые временно работают без VPN. Поэтому выкладка должна быть рассчитана на постепенное и повторяемое выполнение.
Ansible-роль может проверять архитектуру, версию K3s, доступный объём памяти и состояние туннеля перед изменением системы. Обновление лучше проводить волнами: сначала на нескольких тестовых машинах, затем на ограниченной группе, и только после анализа результатов - на остальном флоте. Не менее важны таймауты и возможность безопасно повторить операцию после восстановления связи.
При этом следует разделять обновление control plane и агентов. Центральные узлы должны сохранять кворум, поэтому их нельзя перезапускать одновременно. На периферии, напротив, допустима длительная пауза между этапами, если локальные приложения способны работать автономно.
Работа без control plane
Главный открытый вопрос для такой архитектуры - поведение пода при временной недоступности control plane. Уже запущенный контейнер обычно продолжает выполняться на узле, поскольку его жизненный цикл контролирует локальный kubelet, а не постоянное соединение с API-сервером. Однако новые назначения, пересоздание подов, изменение конфигурации и получение секретов могут быть невозможны до восстановления связи.
Это означает, что автономность нужно проектировать на уровне приложений. Сервисы должны иметь локальный кэш конфигурации, уметь переживать недоступность центральных API и сохранять данные в локальное хранилище с последующей синхронизацией. Полагаться только на Kubernetes как на механизм управления офлайн-режимом нельзя.
Именно здесь раскрывается специфика K3s edge computing офлайн режим. Кластер на периферии должен восприниматься не как обычный удалённый дата-центр, а как набор автономных вычислительных узлов, которые периодически связываются с центральной системой. Такая модель требует идемпотентных операций, локальных очередей, устойчивости к повторной доставке сообщений и понятной политики разрешения конфликтов.
В сухом остатке получается не просто облегчённый Kubernetes, а распределённая платформа для мобильной инфраструктуры. HA control plane обеспечивает доступность управления, kube-vip скрывает переключение между серверами, WireGuard защищает транспорт, а K3s позволяет запускать workloads на ограниченных ARM-ресурсах. Но конечная надёжность определяется не отдельным компонентом, а тем, насколько корректно система учитывает потерю связи, задержки, неоднородность оборудования и невозможность мгновенно обновить весь флот.


