Наткнулся на интересный материал про тестирование GitOps на масштабируемость и нагрузку. Его целых три недели проводила компания iits-Consulting. Оригинал читать не меньше 40 минут, поэтому сократил его, сохранив все самое важное — и теперь делюсь со всеми обитателями Хабра. Читать

Наткнулся на интересный материал про тестирование GitOps на масштабируемость и нагрузку. Его целых три недели проводила компания IITS Consulting. Оригинал читать не меньше 40 минут, поэтому сократил его, сохранив все самое важное, — и теперь делюсь со всеми обитателями Хабра.
Если совсем нет времени читать, то вот коротко: управление кластерами тестировали на основе Argo CD, vCluster, kubara и Sveltos. В итоге контроллер приложений Argo CD начинал сталкиваться с OOM-завершениями примерно при 15 000–20 000 кешированных объектов на хаб. Развернутые манифесты помогали, настройка помогала лишь частично. При этом Sveltos обрабатывал сценарии развертывания типа аддонов при значительно меньшем потреблении памяти — примерно 2 ГБ против 21 ГБ. Основной вывод: при очень больших масштабах архитектура важнее тонкой настройки.
А теперь подробности.
Что хотели выяснитьБольшинство платформ Kubernetes и инструментов GitOps предназначены для работы с 10–300 кластерами. Но периферийным сетям, розничной торговле, телекоммуникациям, супермаркетам и другому бизнесу требуется от 1 000 до 10 000 кластеров. Выдержит ли инфраструктура? Сколько кластеров вообще можно обслуживать осмысленным образом?
Поступил амбициозный запрос: поддержать работу более 15 000 кластеров и свыше 75 000 приложений во всем мире. Для этого в iits-consulting разработали фреймворк GitOps под названием kubara. Он основан на архитектуре «хаб-и-спицы». С его помощью хотели понять ограничения в большом масштабе, чтобы принимать более правильные архитектурные решения и для меньших сред.
Как создали средуТестовую среду запустили на управляемом кластере Kubernetes от STACKIT. Сервис основан на Gardener и называется STACKIT Kubernetes Engine (SKE). Кластер работал на версии Kubernetes 1.35.4. Использовали несколько пулов узлов.

Настройка среды
Во всех пулах узлов использовали метки, рабочие нагрузки планировали с учетом соответствующих допусков. В функционале фреймворка — развертывание приложений в масштабе через назначение на основе меток, стек мониторинга для теста нагрузки, безопасная конфигурация ingress, расширяемый каталог и другие инструменты. Базовая настройка kubara — на диаграмме. Это основа, ее расширяли для различных тестов.

Kubara инициализирует кластер хаба и управляет компонентами платформы через Argo CD
Что происходит на этой диаграмме:
Kubara создавал каталог компонентов платформы на основе общих (umbrella) Helm-диаграмм.
Он инициализировал Argo CD и позволял ему управлять собой через этот каталог.
Подключение к Vault устанавливалось через External Secrets Operator (ESO).
На основе меток и генератора кластеров ApplicationSet Argo CD развертывал и управлял различными компонентами платформы: Traefik, cert-manager, external-dns.
Затем эту конфигурацию расширили: создали общие (umbrella) Helm-диаграммы для vCluster и vCluster Platform и добавили их как компоненты платформы.

Расширение конфигурации kubara с помощью vCluster и vCluster Platform
Идея была простой — поставить метку на хаб- или дочерний кластер, чтобы движок GitOps развернул в нем нужное приложение. На этом этапе все стало немного интереснее — тестировщикам нужно было придумать, как делать три вещи:
1. Развертывать любое количество кластеров по требованию.
2. Подключать любое количество кластеров.
3. Развертывать любое количество приложений в этих кластерах.
Для решения первой задачи расширили среду с помощью паттерна App of Apps. Его суть в том, чтобы создать много приложений Argo CD и развертывать их одновременно.

Использование паттерна App of Apps для создания множества виртуальных кластеров с помощью Argo CD
Вторую задачу можно было решить двумя путями. Первый — получить kubeconfig, отправить его в Vault, создать ExternalSecret, добавить метки и позволить Argo CD развертывать приложения на основе полученных генераций. Это трудоемко.
Второй вариант — использовать vCluster Platform вместе с Argo CD Connector. Тогда платформа будет создавать виртуальные кластеры из пользовательского ресурса VirtualClusterInstance.
Это удобнее, потому что коннектор автоматически устанавливает соединение между Argo CD и созданными виртуальными кластерами. Конечная точка при этом защищается интеграцией с Tailscale.
В итоге серия тестов показала, где находится предел для open-source-версии Argo CD в архитектуре «хаб-и-спицы». Вот так она выглядела:

Архитектура для управления кластером на базе GitOps
Как это работалоК описанной выше среде на базе kubara добавили несколько скриптов для имитации различных сценариев поведения. Первый шаг — создание vCluster. Для этого использовали уже известный паттерн App of Apps и сгенерированные Argo CD приложения.

Генерация приложений Argo CD для vCluster
./scripts/1-create-applications.sh 5
Generating 5 Argo CD Application manifests from scripts/app-vcluster-template.yaml
vcluster-1 -> apps/vcluster-1.yaml
vcluster-2 -> apps/vcluster-2.yaml
vcluster-3 -> /Users/artemlajko/git/15-04-2025/new/demos/scale-tests-with-1000-vclusters-based-on-kubara-2026/apps/vcluster-3.yaml
vcluster-4 -> /Users/artemlajko/git/15-04-2025/new/demos/scale-tests-with-1000-vclusters-based-on-kubara-2026/apps/vcluster-4.yaml
vcluster-5 -> apps/vcluster-5.yaml
Generated 5 manifests in appsКак альтернативу можно создать ресурсы VirtualClusterInstance.
./scripts/1-create-applications.sh --virtual 5
Generating 5 VirtualClusterInstance manifests from /scripts/virtualclusterinstance-template.yaml
vcluster-1 -> /apps/virtualclusterinstance-1.yaml
vcluster-2 -> /apps/virtualclusterinstance-2.yaml
vcluster-3 -> /apps/virtualclusterinstance-3.yaml
vcluster-4 -> /apps/virtualclusterinstance-4.yaml
vcluster-5 -> /apps/virtualclusterinstance-5.yaml
Generated 5 manifests in /appsВторой шаг — получить файлы kubeconfig и отправить их в Vault.

Получение файлов kubeconfig для vCluster и их сохранение в Vault
./scripts/2-sync-vclusters.sh 5
Logging in to Vault...
Received Vault token
Processing vClusters from 1 to 5 (parallelism=1)
[vcluster-1] Generating kubeconfig via vcluster-1.controlplane-dev.stackit.run
[vcluster-1] Kubeconfig generated
[vcluster-2] Generating kubeconfig via vcluster-2.controlplane-dev.stackit.run
...
[vcluster-4] Kubeconfig generated
[vcluster-5] Generating kubeconfig via vcluster-5.controlplane-dev.stackit.run
[vcluster-5] Kubeconfig generated
Reading current Vault secret my_clusters
Writing 5 kubeconfig(s) to Vault secret my_clusters
Synchronized 5 vClustersЭтот шаг требуется, только когда vCluster развертываются с помощью поставщика Helm-диаграмм.
Третий шаг — подключить кластеры к Argo CD и развернуть приложения на основе меток.

Подключение vCluster к Argo CD и применение меток
./scripts/3-generate-values.sh 5 > customer-service-catalog/helm/controlplane/argo-cd/values.yamlОстальное берет на себя kubara. Он создает ExternalSecrets с необходимыми метками, извлекает kubeconfig-файлы и позволяет Argo CD использовать их для целевого развертывания.
При использовании vCluster Platform второй шаг можно пропустить. Argo CD Connector автоматически устанавливает соединение с vCluster. В этом случае нужно лишь добавить метки.

Повторное использование подключения к платформе vCluster и применение меток
./scripts/12-argocd-deploy-applications.sh "kro=enabled"
Excluded: cluster-vcluster-platform.controlplane-dev.stackit.run-52690538
Dry run: false
Applying labels:
- kro=enabled
argocd/cluster-vcluster-platform.controlplane-dev.stackit.run-3735921280
argocd/cluster-vcluster-platform.controlplane-dev.stackit.run-3752698899
argocd/cluster-vcluster-platform.controlplane-dev.stackit.run-3769476518
argocd/cluster-vcluster-platform.controlplane-dev.stackit.run-3836586994
argocd/cluster-vcluster-platform.controlplane-dev.stackit.run-3853364613Вот так это выглядит в пользовательском интерфейсе Argo CD.

Пользовательский интерфейс Argo CD, отображающий ресурсы vCluster и VirtualClusterInstance
Также эту идею протестировали со Sveltos.
./scripts/4-register-sveltos-clusters.sh 5
[vcluster-1] Merging kubeconfig
[vcluster-1] Registering in namespace vcluster-1
cluster vcluster-1 successfully registered/updated in namespace vcluster-1.
[vcluster-2] Generating kubeconfig via vcluster-2.controlplane-dev.stackit.run
[vcluster-2] Merging kubeconfig
[vcluster-2] Registering in namespace vcluster-2
cluster vcluster-2 successfully registered/updated in namespace vcluster-2.
[vcluster-3] Generating kubeconfig via vcluster-3.controlplane-dev.stackit.run
...
[vcluster-5] Merging kubeconfig
[vcluster-5] Registering in namespace vcluster-5
cluster vcluster-5 successfully registered/updated in namespace vcluster-5.
Registered 5 vClusters in Sveltos (parallelism=1)Чтобы проверить, работает ли — использовали это:
kubectl get clustersummaries.config.projectsveltos.io -A -o wide
NAMESPACE NAME AGE HELMCHARTS KUSTOMIZEREFS POLICYREFS
vcluster-1 cert-manager-sveltos-vcluster-1 85s Provisioned
vcluster-2 cert-manager-sveltos-vcluster-2 83s Provisioned
vcluster-3 cert-manager-sveltos-vcluster-3 82s Provisioned
vcluster-4 cert-manager-sveltos-vcluster-4 78s Provisioned
vcluster-5 cert-manager-sveltos-vcluster-5 78s ProvisionedРезультаты тестированияNon-HA- и HA-конфигурацииВ начальных Non-HA-тестах (одна реплика контроллера; лимит памяти — 12 ГБ) первые ошибки OOM-завершения появлялись на шестой итерации. Зафиксировали такой результат:
30 vCluster, 186 приложений, 6 300 объектов и 420 долго работающих подов, включая рабочие нагрузки и vCluster. Этого уже достаточно для многих целей. Если вы работаете в меньшем масштабе или хотите сэкономить, вам не обязательно сразу использовать HA-конфигурацию.
Использование WET YAML-манифестов показало себя лучше, чем использование DRY Helm-диаграмм: нагрузка на репо-сервер была существенно ниже.

Сравнение использования памяти в режимах WET и DRY
В HA-конфигурации с тремя репликами контроллера, автоматическим масштабированием и лимитом 12 ГБ памяти удалось выйти на такой результат: 150 vCluster, 742 приложения и 16 700 объектов. После этого появлялись ошибки OOM-завершения.
Снятие лимитов памяти лишь отсрочило проблему: контроллеры потребляли до 21 ГБ RAM, затем кластер становился нестабильным.
Тесты показали: проблема не в количестве кластеров или приложений, а в количестве объектов, которое Argo CD кеширует и обрабатывает. Барьер — примерно 15 000–17 000 объектов.
Тонкая настройка (Finetuning)Вот что сделали тестировщики для оптимизации:
Увеличили число воркеров (--status-processors=50, --operation-processors=25).
Использовали алгоритм шардирования consistent-hashing.
Настроили переменные окружения для управления кешем и пакетной обработкой событий.
Увеличили количество шардов с трех до шести.
Так получилось улучшить пропускную способность и глубину очередей, но фундаментально проблема не решилась. При достижении 18 000–20 000 объектов один из контроллеров неизбежно сталкивался с ошибкой OOM-завершения. Другие не брали на себя его работу, и его шард переставал синхронизироваться.

Обзор итераций, о которых идет речь
Это значит, что для масштаба более 1 000 кластеров и 5 000–10 000 тяжелых приложений один хаб Argo CD не подходит просто из-за архитектурных ограничений. Поэтому для таких задач лучше разделять нагрузку между несколькими хабами или использовать энтерпрайз-решения вроде Akuity Platform или Octopus Deploy.
SveltosSveltos — контроллер для управления аддонами, который работал поверх Argo CD. Он брал на себя развертывание приложений на целевых кластерах, а Argo CD управлял только самим Sveltos и его ресурсами.
Результаты впечатлили. При развертывании 600 приложений на 150 vCluster Sveltos использовал около 2 ГБ памяти. В то же время Argo CD в аналогичных тестах потреблял до 21 ГБ. И это притом что Sveltos работал с одной репликой.

Расширение стандартной конфигурации kubara с помощью Sveltos
Вот результаты тестов Sveltos с увеличением нагрузки:
1 000 приложений (250 кластеров) — около 70 минут (в DRY-режиме с Helm).
1 000 приложений с шардированием — время сократилось примерно до 35 минут.
1 000 приложений в WET-режиме (сгенерированные манифесты) — около 17 минут.
2 000 приложений (500 кластеров) — приблизительно 36–43 минуты.
5 000 приложений (1000 кластеров) — тест остановили примерно на 4 300 приложениях из-за нехватки бюджета. Инфраструктура стоила уже больше 120 000 евро, но Sveltos продолжал работать.
Безусловно, Sveltos гораздо эффективнее. Технически контроллер способен управлять более чем 15 000 кластеров и более чем 75 000 приложений с одного хаба, но такая архитектура нецелесообразна из соображений надежности. А вот комбинация Argo CD и Sveltos — вполне перспективный подход для крупномасштабных сред.
kubara
Начальная настройка kubara — отличная отправная точка, но, когда растет число кластеров и приложений, возникает множество узких мест. Следует пересмотреть ресурсы и архитектуру не только для Argo CD, но и для мониторинга, External Secrets Operator, сетевых контроллеров и других компонентов.
Дело в том, что архитектура важнее тонкой настройки. Попытка заставить один хаб управлять всем приводит к ошибкам OOM-завершения и простою. Решит проблему разделение нагрузки на 5–10 хабов по географическому, организационному или иному принципу.
Что это значит на практикеТак как конечная цель — не просто создать 15 000 кластеров, а сделать их работу безопасной и предсказуемой, имеет смысл проектировать систему на основе 5–10 хабов. Их можно сгруппировать по бизнес-юнитам, регионам или этапам жизненного цикла. Это снизит риски, упростит операции и оставит пространство для роста.
Что важно помнить:
Объекты — главный враг масштаба. Их количество имеет большее значение, чем число кластеров или приложений.
У тонкой настройки есть пределы. Если вы уперлись в архитектурный потолок, она не поможет.
Гибридные подходы работают. Использовать Argo CD для платформы и Sveltos для приложений — разумно при масштабировании.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Многоэтапные сборки в Docker: как уменьшить образ с 1,2 ГБ до 50 МБ | 5 | 8 | 28-06-2026 |
| 2 | ggrebalance: Часть 2. Планирование операции ребаланса | 0 | 7 | 17-07-2026 |
| 3 | В погоне за APDEX-ом, или как создать HighLoad на недорогом серверном железе | 1 | 16.37 | 20-05-2026 |
| 4 | Масштабирование без потерь: база знаний, чтобы запустить филиалы банка за 2 недели | 0 | 9.37 | 12-08-2026 |
| 5 | Куда пропали 14 млрд рынка observability? | 0 | 8.22 | 06-08-2026 |
| 6 | Почему ваш GitLab CI медленный: 6 ошибок в настройке Runner | 0 | 7 | 13-07-2026 |
| 7 | Что сломается в вашем сервисе завтра, если сегодня вы запустите контейнеры без проверки образов | 0 | 6.37 | 24-07-2026 |
| 8 | С нуля до Junior DevOps в 2026 году. Часть 3. Git и GitHub | 0 | 6 | 12-07-2026 |
| 9 | ggrebalance: Часть 1. Shrink | 0 | 7 | 26-06-2026 |
| 10 | Почему Excel не работает, когда активов становится 500+: подводные камни управления ИТ-парком в табличных редакторах | 0 | 7 | 22-06-2026 |