В одном чате по куберу меня спросили единственное, что реально важно, когда ты собрал оркестратор контейнеров внутри таблицы: а сколько оно вообще тянет? Сколько подов, пока не ляжет. Какой образ влезает в ячейки. Сколько кластеров держит одна машина. И — раз уж мы фонд с серьёзным лицом — как это смотрится рядом с настоящими: Kubernetes, Docker Swarm, Nomad.

Поэтому мы провели честное нагрузочное тестирование. Четыре измерения, два бэкенда (.xlsx на диске и живая Google-таблица), синтетика на ноутбуке и реальные Docker-образы на облачной виртуалке. А потом поставили цифры рядом со взрослыми оркестраторами.

Короткая версия: по каждой оси, которая имеет значение, мы проигрываем на 3–5 порядков. По осям, которые значения не имеют, — выигрываем вчистую. И один наш давний «факт» оказался неверным — бенчмарк нас поправил. Поехали.

Впервые тут? Что это вообще. Sheeternetes — оркестратор контейнеров, у которого весь control plane живёт внутри электронной таблицы: Deployments, Nodes, Pods, Events — это вкладки Google Sheets или Excel, планировщик читает и пишет ячейки, а на другом конце крутятся настоящие Docker-контейнеры. Таблица не симулирует кластер — она и есть кластер. Проект входит в Sheet-Native Computing Foundation (SNCF) — вендор-нейтральный дом для sheet-native computing, работающую пародию на CNCF: 30+ проектов, стандарт контейнеров SICF, верифицируемая сертификация инженеров и живые демо на настоящих таблицах.

Ссылки: sncfoundation.github.io · github.com/sncfoundation · Telegram t.me/stncf · Slack sheetncf · LinkedIn company/sheetncf

Подробности: https://habr.com/ru/articles/1077612/

Что именно мы мерили

apiserver.py — это весь control plane: kube-apiserver + kube-scheduler в одном маленьком Python-процессе. Он читает и пишет книгу (вкладки Deployments/Nodes/Pods/Events/Images/Layers) через openpyxl, гоняет планировщик на каждый heartbeat кубелета и пишет желаемые поды обратно. Один процесс, одна книга, один кластер — и он single-writer, в этом вся суть того, где находится потолок.

Четыре теста:

  • A — объекты в одной книге. Время reconcile (load + schedule + write + save) vs число подов.

  • B — SICF-образы в ячейках. Сколько мегабайт образа влезает и какой ценой.

  • C — число кластеров. Сколько независимых книг-кластеров reconcile’ит один хост.

  • D — длина строки в ячейке. Сколько символов переживает значение, пока не испортится.

Машины: Mac (лёгкие точки), облачная VM на Cozystack с Docker (round-trip реальных образов) и инструмент sheetbuild из sci для упаковки образов.

A — поды в одной книге

Reconcile строго линеен: около 0.022 мс на под. Десять тысяч подов reconcile’ятся за 0.22 с, а файл — погрешность округления, 0.21 МБ.

Время reconcile от числа подов и время import SICF от размера образа
Время reconcile от числа подов и время import SICF от размера образа

поды

reconcile

файл

пик RAM

1 000

0.030 с

0.03 МБ

0.9 МБ

5 000

0.110 с

0.11 МБ

8.9 МБ

10 000

0.224 с

0.21 МБ

12.9 МБ

Формат Excel тут не предел — влезут миллионы строк. Предел — время reconcile одного openpyxl-процесса, потому что он перечитывает и переписывает всю книгу на каждый heartbeat. Экстраполяция: 100k подов ≈ 2.2 с на цикл. Вот тут кластер и начинает ощущаться как ходьба по смоле.

B — какой образ влезает в ячейки

Это вопрос SICF — образ, хранящийся как base64 в ячейках, адресуемый по sha256. На маке мы паковали синтетические несжимаемые слои; на VM — реальные Docker-образы и запускали их обратно. Обе серии ложатся на одну линию: ~0.06 с/МБ на import, export в 2–3 раза быстрее, а .xlsx выходит примерно того же размера, что и tar от docker save (раздувание base64 компенсируется zip-сжатием книги).

Реальный round-trip — то, ради чего всё затевалось. Тянем настоящий образ, пакуем в книгу, удаляем локальную копию, пересобираем чисто из ячеек и запускаем:

Реальный образ nginx, прогнанный через Excel-книгу, запускается
Реальный образ nginx, прогнанный через Excel-книгу, запускается

Три реальных образа, по три независимых проверки целостности у каждого — внутренний sha256 в sheetbuild, собственная валидация docker load и реально запущенный контейнер:

образ

tar

import

export

.xlsx

строк Layers

verify

запуск

alpine:latest

4 МБ

0.30 с

0.15 с

4 МБ

172

nginx:alpine

29 МБ

1.67 с

0.68 с

28 МБ

1 285

python:3.12-slim

47 МБ

2.88 с

0.96 с

45 МБ

2 056

Поскольку между import и export локальный образ был удалён (docker rmi), пересобранный образ доказуемо пришёл из таблицы, а не из кэша. Вот как он лежит в ячейках — слои нарезаны в base64, по строке на чанк, с адресацией по дайджесту:

Образ контейнера, живущий в ячейках Google-таблицы
Образ контейнера, живущий в ячейках Google-таблицы

RAM скромная (пик 191 МБ на образе 47 МБ, ~4× tar). Честный потолок — суммарные байты → секунды import и RAM; образ 500 МБ был бы ~30 с import на 1-vCPU. Нативный SICF — для маленьких образов: статические бинарники, scratch/alpine, WASM. Ровно то, для чего формат и задумывался.

C — сколько кластеров на одном хосте — и вот тут настоящий разрыв

Одна книга (200 подов) reconcile’ится за ~15 мс, так что один хост клирит ~650 книг-кластеров за 10-секундный интервал. Excel масштабируется вширь прекрасно.

Google Sheets — нет. Один reconcile там 1.47 с (сеть + пара API-вызовов), и ты упираешься в жёсткую квоту 60 записей в минуту на пользователя:

интервал reconcile

макс. Google-таблиц-кластеров на аккаунт

каждые 10 с

~5

каждые 30 с

~15

каждые 60 с

~30

каждые 5 мин

~150

Итого: ~650 Excel-кластеров на хост, ~5 Google-кластеров на аккаунт. В облаке потолок ставит квота, а не ёмкость — разница ~130× и реально полезная вещь, если ты вдруг (не надо) соберёшься на этом строить.

D — сколько строка живёт в ячейке, и развенчанный миф

Вот этот тест нас поправил. Мы повторяли, в том числе в статье про DOOM, которая скоро выйдет, что Google Sheets тихо портит длинные строки после ~2000 символов. Бенчмарк говорит: не через API.

бэкенд

целостно до

свыше

Excel / openpyxl

32 767

тихая обрезка ровно до 32 767

Google Sheets API v4

50 000

явная ошибка HTTP 400, не порча

Прогоняя base64 туда-обратно и сверяя sha256, Google Sheets держал идеальную целостность ровно до 50 000 символов (документированный лимит ячейки) и отклонил 55 000 громким "more than the maximum of 50000 characters" — ошибкой, а не тихой порчей. Та порча, что мы видели раньше, — артефакт Apps Script-бэкенда (облачный путь Code.gs), а не самого Google Sheets. Хорошо. Бенчмарк, который только подтверждает твои убеждения, — не бенчмарк.

Схватка

А теперь то, ради чего вы сюда мотали. Вот таблица рядом с настоящими оркестраторами — по метрикам, для которых они, собственно, и построены:

Публично заявленные потолки по контейнерам, лог-шкала
Публично заявленные потолки по контейнерам, лог-шкала

Это публичные цифры: собственные пороги SIG Scalability у Kubernetes (150 000 подов, 5 000 нод, 300 000 контейнеров на кластер); демо Docker 2015 года — Swarm на 30 000 контейнеров и 1 000 нод; и C2M-прогон HashiCorp 2020 года — два миллиона контейнеров на 6 100 нодах, зашедулено примерно за 22 минуты. Мы упираемся в район 10 000 подов в одной линейной книге.

На этом графике мы не последние. Мы всего лишь в 200 раз позади предпоследнего.

Полное сравнение — честные оси и те, где мы «побеждаем»
Полное сравнение — честные оси и те, где мы «побеждаем»

Где мы честно проигрываем

Без виляния — вот где таблице нечего делать рядом с вашей инфраструктурой:

  • Масштаб: ~10k подов/книга против 150k (K8s) против 2M (Nomad). Четыре-пять порядков.

  • Задержка: 0.22 с на reconcile при 10k подов и 1.47 с на reconcile в Google Sheets. Kubernetes шедулит за миллисекунды и стартует поды с предзагруженным образом в рамках SLO в 5 секунд.

  • Нет HA control plane. Один openpyxl-writer на книгу. etcd, Raft-менеджеры Swarm и Raft-серверы Nomad держат кворум из 3–5 нод. У нас один файл и молитва.

  • Облачный бэкенд ограничен квотой до горстки кластеров на аккаунт.

Где мы «побеждаем»

И тем не менее:

  • Стоимость control plane: $0. LibreOffice бесплатен. Ни etcd-кластера, ни control-plane нод.

  • Зависимости: LibreOffice или браузер — против etcd + kubelet + kube-proxy + CNI + CoreDNS.

  • Состояние правится руками. Под редактируется мышкой. kubectl edit — это курсор. Попробуй так с etcd.

  • Реестр в комплекте. Образ живёт в том же файле, что и кластер (SICF). Ни Harbor, ни внешнего реестра.

  • Онбординг: любой стажёр-финансист на земле прочитает control plane. Не нужно учить HCL или kubectl.

  • Восстановление после сбоя: Ctrl+Z. Google Sheets бесплатно хранит полную историю ревизий. Откати кластер к 9:41 сегодняшнего утра кнопкой «восстановить эту версию».

Ничего из этого не важно. В этом и шутка. Но каждый пункт — правда, а пара из них (реестр-внутри-артефакта, человекочитаемое желаемое состояние, бесплатный DR через историю ревизий) — это идеи, за которые серьёзные системы заставляют попотеть.

Итог

Таблица — оркестратор на четыре-пять порядков хуже Kubernetes, и теперь мы можем доказать это цифрами, а не ощущениями. По дороге нагрузочный тест показал, что сам формат — едва ли узкое место (узкое место — single-writer reconcile-петля), что реальные образы round-trip’ятся без потерь и запускаются, что .xlsx стоит примерно как tar, и что «тихая порча», в которой мы винили Google Sheets, всё это время была нашим же Apps Script.

Вот эта последняя часть — и есть смысл бенчмарка. Не запускайте на этом прод. Запустите бенчмарк — он честный и поправит вас.

Воспроизвести самому: harness (бэкенды Excel + Google, все четыре теста) и сырой results.csv — в sci; round-trip реального образа — четыре команды на любом Docker-хосте.

Присоединяйтесь

It reconciles.