Недавно я рассказывал про Sheeternetes — оркестратор, у которого control plane живёт в таблицах. Здесь — про следующий логичный шаг: паттерн «оператор», применённый к самим таблицам. Настоящий полноценный Sheeternetes-оператор. Не скрипт внутри таблицы, а внешний контроллер, который приводит табличку к желаемому состоянию.
И раз уж так совпало по датам, демка этого оператора будет переворачивать календарь и возвращать таблице все атрибуты настоящего третьего сентября, дня прощаний.
Благодарность
Идею сделать именно оператор для таблиц (а не просто ещё один скрипт) подкинул Артём Горячев, кубастронавт и просто замечатльный человек, в одном замечательном чате по куберу. Именно он предложил посмотреть на управление таблицами как на operator pattern и добавить федерацию.
Что тут у вас происходит?!
Sheeternetes — оркестратор контейнеров, у которого весь control plane живёт внутри электронной таблицы: Deployments, Nodes, Pods, Events — это вкладки Google Sheets (или Excel), планировщик читает и пишет ячейки, а на другом конце крутятся настоящие Docker-контейнеры. Таблица не симулирует кластер — таблица и есть кластер. Под капотом реальная инженерия: bin-packing и failover, live-миграция, HMAC-подписи, свой формат образов (SICF), в котором образ хранится прямо в ячейках. Репозиторий: https://github.com/sncfoundation/sheeternetes.
Sheet-Native Computing Foundation (SNCF) — вендор-нейтральный дом для «sheet-native computing», пародия на CNCF, которая при этом работает: 30+ проектов (оркестрация, сеть, хранилище, наблюдаемость, CI/CD), собственный стандарт контейнеров (SCRI/SICF), верифицируемая сертификация инженеров и живые демо на настоящих таблицах. Всё — open source, комьюнити международное и англоязычное. Сайт: https://sncfoundation.github.io, код: https://github.com/sncfoundation.
Что такое selh-healing таблицы и почему именно оператор, а не скрипт
Разница тонкая, но принципиальная, и на ней держится вся идея. Можно было сделать максимально прямолинейно: повесить на таблицу Apps Script с триггером onEdit, который откатывает изменения. Но это не оператор. Это защита изнутри управляемого ресурса — как если бы под в Kubernetes сам себя чинил. Оно ломается вместе с ресурсом, живёт в его границах и не масштабируется на большое количество таблиц.
Настоящий оператор устроен иначе. Есть три части:
-
Control plane — отдельная таблица-реестр (
ManagedSheets), где записано желаемое состояние: какие таблицы мы ведём и по какому шаблону. -
Контроллер — внешний процесс (у нас — контейнер), который крутит цикл reconcile: читает реестр и сводит каждую управляемую таблицу к её шаблону.
-
Управляемая таблица — тот самый ресурс, который правят кожаные и который контроллер возвращает к описанному состоянию.
Желаемое состояние живёт снаружи управляемого ресурса, и контроллер тянет ресурс к нему. Управляемую таблицу можно удалить целиком, перекрасить, стереть — контроллеру всё равно, он перерисует её из шаблона. Именно поэтому это «самолечение», а не «откат правок».
Весь reconcile — это одна идемпотентная функция: взять шаблон, перерисовать поверх таблицы баннеры и пиксельную картинку (через фоны ячеек), и так на каждом цикле. Перерисовка поверх и есть откат дрейфа — не нужно вычислять, что именно поменяли, достаточно привести к эталону.
Демо: таблица, которая всегда 3 сентября
Управляемая таблица — публичная, править может кто угодно. Её желаемое состояние:
-
золотой баннер «И СНОВА ТРЕТЬЕ СЕНТЯБРЯ»;
-
красный баннер «🔥 ГОРЯТ КОСТРЫ РЯБИН 🔥»;
-
пиксельный портрет Шуфутинского, нарисованный фонами ячеек (реальное фото с Wikimedia, даунсемпл в сетку);
-
внизу — полоса, где ячейками нарисованы костры и грозди рябины.
Портрет — не карикатура, а даунсемпл настоящей фотографии (снятой, что символично, 03-09-2021). Сетка 138×192 ячейки, каждая ячейка 6 пикселей — так в тот же общий размер влезает втрое больше деталей: видно и лысину, и синие очки, и эспаньолку, и кулон.
Дальше — самое приятное. Вот self-heal вживую: я открыл таблицу, сломал баннер и пробил белую дыру в лице, а оператор через секунды всё вернул.
Участники чата этой ночью тоже неоднократно ломали Шуфыча, но он словно заправский Феникс заново восставал из пепла от костров рябин. Баннер вернулся, лицо собралось, дыра исчезла. Открытая на редактирование для всех, таблица живёт и лечится сама, пока где-то крутится контроллер.
Потрогать вживую (пока запущен контроллер):
-
Управляемая таблица (публичная, ломайте):
https://docs.google.com/spreadsheets/d/1AEF9J07u4GV66Hs5zURpWQwN9tFuFwNr3-rVdeoaCMQ -
Контрол-плейн (реестр, только чтение):
https://docs.google.com/spreadsheets/d/1ihtshuJoTZ0muxKUjiCe_3HYlaAGpODDNb60-Mu3AmU -
Sheeternetes-кластер (доступ на чтение):
https://docs.google.com/spreadsheets/d/15sxhOFegzp-RT1eP3gXLvaYU389qZy9-CATrg6nEGNE/edit
Как поднять свою такую таблицу — одной командой
Это шаблон для sheets-operator. Нужны Docker, git и Google OAuth «authorized-user» JSON (с scope spreadsheets и drive) — в нём есть refresh_token, поэтому контроллер сам обновляет доступ и работает бесконечно.
git clone https://github.com/sncfoundation/sheets-operator && cd sheets-operatorgit clone https://github.com/sncfoundation/demos # шаблоны (в т.ч. sep3) лежат тутcp /path/to/google-oauth-authorized-user.json creds.json # ваши креды; не коммитить# создать свою самолечащуюся таблицу «3 сентября» из шаблона одной командой:SHEETSOP_TEMPLATES=demos/sep3 SHEETSOP_CREDS=creds.json \ python3 sheetsctl.py apply my-sep3 --template sep3
Команда apply создаёт новую таблицу, делает её публичной, регистрирует в контрол-плейне и один раз реконсайлит. Дальше нужен контроллер, который будет её лечить постоянно:
docker build -t sheets-operator:1 .docker run -d --restart unless-stopped \ -e SHEETSOP_CONTROL=<id вашего контрол-плейна> -e SHEETSOP_TEMPLATES=/templates -e PYTHONUNBUFFERED=1 \ -v $PWD/creds.json:/creds/creds.json:ro \ -v $PWD/demos/sep3:/templates:ro \ sheets-operator:1 run --interval 10
И проверка:
docker ps # sheets-operator должен быть Updocker logs -f sheets-operator # ждём: reconciled my-sep3 (sep3)
Теперь откройте свою таблицу, что-нибудь сломайте — и через несколько секунд она соберётся обратно.
Грабли, на которые легко наступить:
-
Используйте
run, а неapply.runлечит существующие таблицы.applyсоздаёт новые (если запустите его в цикле — наплодите таблиц). -
Переезд на другой хост не меняет ссылки на таблицы. Контроллер ведёт таблицы по их id из контрол-плейна. Наведите новый хост на тот же
SHEETSOP_CONTROLс теми же кредами — и он поведёт те же таблицы, URL останутся прежними. Ноутбук для демо годится, но пока он спит — контроллер на паузе и правки не чинятся; для «всегда живого» нужен маленький VM.
Оператор как контейнер, который шедулит таблица
Дальше начинается матрёшка, ради которой всё и затевалось. Контроллер — это просто контейнер. А значит, его канонический дом — Deployment в Sheeternetes. То есть:
-
образ оператора можно положить в таблицу (тот самый SICF из статьи про DOOM);
-
шедулит его таблица-кластер;
-
запускает kubelet на ноде.
Получается оператор, который шедулит таблица и который управляет таблицами. Deployment выглядит как обычно, только с секретом для кредов и переменной, указывающей на контрол-плейн:
{ "name": "sheets-operator", "image": "sheets-operator:sep3", "replicas": 1, "cpu_req": 100, "mem_req": 128, "env": "SHEETSOP_CONTROL=<control-plane-id>", "secret_files": "gcreds:/creds/creds.json" }
Креды приходят как Secret, который kubelet монтирует в контейнер в рантайме, — они никогда не лежат в образе и не попадают в git. Исполнение, как всегда, на реальной ноде; таблица — контрол-плейн.
И финальный слой абсурда: есть третья, кластерная таблица, где вся структура Sheeternetes (Deployments/Nodes/Pods/Events/Images) лежит вкладками, плюс расположен дашборд Sheetfana. В ней модно увидеть, как оператор запущен подом, а рядом живёт его же образ в ячейках. Таблица шедулит оператор, который лечит таблицу.
Немного находок
-
Мелкая ячейка — больше деталей. Изначально 3× детализации сделали портрет втрое больше физически. Правильно — уменьшить ячейку (у нас 6 px вместо 16): тот же общий размер, втрое чётче картинка. Размер ячейки вынесен в шаблон (
cell_px), так что тюнится без правки кода. -
Конкурентное редактирование не мешает. Google Sheets под капотом использует operational transformation, поэтому даже когда таблицу одновременно «ломают» несколько человек, контроллер спокойно сводит всё к эталону на следующем проходе. Гонок нет: reconcile идемпотентен.
-
Один контроллер на контрол-плейн. Два не сломают (reconcile идемпотентен), но и смысла нет. А вот два контроллера с разными шаблонами устроят перетягивание каната — поэтому образ и шаблоны надо держать в одной версии.
Резюме
В принципе это рабочий, компактный пример того, что такое оператор и чем reconcile отличается от «отката правок»:
-
желаемое состояние живёт снаружи ресурса, в контрол-плейне;
-
контроллер непрерывно сводит ресурс к нему, а не реагирует на конкретные события;
-
перерисовка идемпотентна, поэтому не нужно вычислять дифф — достаточно привести к эталону;
-
ресурс можно уничтожить целиком, и он восстановится, потому что источник истины не в нём.
Ровно на этом паттерне строятся настоящие операторы в Kubernetes. Просто здесь управляемый ресурс — публичная Google-таблица с лицом Шуфутинского, и любой может проверить работу оператора своими руками.
А в следующей статье я расскажу, как мы кладём образы (в том числе образ самого оператора) в сами ячейки и запускаем оттуда DOOM (теперь всем так положено).
Присоединяйтесь
Все проекты Sheet-Native Computing Foundation выложены в open source и активно развиваются международным сообществом (хотя по нашему слаку это пока неочевидно).
-
📗 SheetsOperator: github.com/sncfoundation/sheets-operator
-
🎪 Демки (в т.ч. «3 сентября»): github.com/sncfoundation/demos
-
💬 Slack — sheetncf, Telegram — t.me/stncf, LinkedIn — company/sheetncf
-
🌐 Весь код: github.com/sncfoundation · sncfoundation.github.io
Переверни календарь. It reconciles.
ссылка на оригинал статьи https://habr.com/ru/articles/1077902/