NKT: Киллер фича № 8, плагины

—

от автора

Ядро знает, что спросить. Плагин знает, как сделать

Речь в статье идет о NKT предыдущие статьи: NKT, Скрипты.

В 1978 году Макилрой сформулировал принцип, который определил архитектуру IT-систем на полвека вперёд. Суть этой философии сводится к трём главным правилам, и мы в NKT сознательно им следуем:

1. Делай одну вещь и делай её хорошо (Do One Thing and Do It Well)

Вместо создания огромных монолитных комбайнов, которые пытаются решить все задачи сразу, программа должна отвечать за один конкретный процесс. Ядро NKT — это ровно 29 глаголов развёртывания. Оно идеально справляется с задачей «разверни сервис, проверь, что он работает, и перенеси, если нужно». Если команде нужен приватный реестр образов, управление DNS или интеграция с LLM — мы не перегружаем ядро сотнями новых абстракций. Мы не превращаем лёгкий декларативный язык в неподъёмный комбайн.

2. Пиши программы, чтобы они работали вместе (Write programs to work together)

Инструмент, изолированный от остальной экосистемы, бесполезен. Всё, что выходит за рамки базового развёртывания хостов и контейнеров, подключается через плагины. Плагин — это легковесная служба на 127.0.0.1, которая выступает мостом. Ядро NKT не знает внутренностей стороннего сервиса, а сторонний сервис не знает о существовании NKT. Они работают вместе через посредника.

3. Проектируй универсальные интерфейсы (Universal interfaces)

В мире Unix это были текстовые потоки (pipes). В мире NKT это строгий HTTP/JSON контракт на localhost между хабом и плагином, а также единые API и MCP-протоколы для сценариев и ИИ-агентов. Мы не вшиваем логику реестра Docker или DNS-провайдера в бинарник NKT. Мы заключаем между ними универсальный контракт.

Ядро знает, что спросить. Плагин знает, как сделать.

В этой статье на примере плагина для реестра образов rgstr мы разберём анатомию расширяемости NKT: как один сторонний сервис бесшовно встраивается в веб-интерфейс хаба, добавляет новые команды в язык сценариев и даёт суперсилы ИИ-агентам через MCP. И всё это — без единой строчки кода в самом ядре NKT.


Анатомия плагина

Каждый плагин — это служба nkt-plugin-<имя>, которая слушает только 127.0.0.1:9280 и работает без Docker. Она общается с хабом по HTTP на localhost и с внешним сервисом по его протоколу (HTTP API, gRPC, CLI — что угодно).

┌──────────┐       HTTP 127.0.0.1:9280       ┌─────────────────────┐       API       ┌──────────────┐│   Хаб    │ ◄─────────────────────────────► │  nkt-plugin-rgstr   │ ◄─────────────► │    rgstr     ││  (NKT)   │                                 │  (служба плагина)   │                 │  (реестр)    │└──────────┘                                 └─────────────────────┘                 └──────────────┘     │                                                                                      │     │  Пользователь видит: сводка, разделы, сценарии, MCP                                  │  docker push/pull     ▼                                                                                      ▼  /ui, API, сценарии                                                                   клиенты (CI/CD)

Что даёт плагин хабу (три точки расширения):

Точка

Что появляется

Пример для rgstr

Интерфейс

Разделы в хабе: сводка, находки, управление

Сводка реестра, репозитории, роботы, политики, бэкапы

Сценарии

Новые команды в языке (<имя> <глагол> …)

rgstr gc, rgstr backup run, rgstr robot create …

MCP

Инструменты для ИИ-агентов

rgstr_summary, rgstr_vulns, rgstr_robot_create

Конфигурация — переменные окружения в «Секреты» → .env конвейера плагина. Секреты лежат в файле окружения службы с правами 0600.

Совместимость: плагин показывает только то, что есть у внешнего сервиса. Если у реестра нет сканирования (появилось с 1.10) или бэкапов (с 1.8) — разделы просто не отображаются. Плагин не ломается на старых версиях.


Установка и конфигурация (на примере rgstr)

«О системе» → «Плагины» → «Каталог» → rgstr → «Установить на хост».

Хост — тот, где стоит реестр (или любой, откуда он виден по сети).

Параметр

Что задаёт

Пример

RGSTR_URL

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

http://127.0.0.1:5000 (на том же хосте)

RGSTR_USER, RGSTR_PASSWORD

Администратор реестра с уже сменённым паролем

admin / секрет

RGSTR_PUBLIC

Адрес для docker и конвейеров

registry.example.com

RGSTR_CA_FILE

PEM своего УЦ, если HTTPS подписан им

/etc/ssl/ca.pem

Важно: пока временный пароль не сменён в /ui реестра — плагин не сможет войти. Хаб покажет находку «у пользователя временный пароль».

тле2После установки служба nkt-plugin-rgstr запускается автоматически. В хабе появляется раздел плагина со сводкой.


Что получает хаб: расширение интерфейса

Сводка и находки

Первое, что видит администратор — сводка: версия реестра, тип входа (локальный / LDAP / OIDC), количество репозиториев и скачиваний, занятый диск, состояние сборки мусора, сканирования и бэкапов.

Под ней — находки. Это автоматическая проверка безопасности и здоровья:

Находка

Почему важно

Вход выключен

Любой может пушить и удалять

Реестр по HTTP не на loopback

Трафик и пароли в открытом виде

У пользователя временный пароль

docker login и API не работают

Роль user с правом удалять

Избыточные привилегии

Робот с записью во все репозитории (* + push)

Компрометация = доступ ко всему

Мало места на диске

Пуш скоро упадёт

Сборка мусора выключена / давно не шла / упала

Диск не освобождается

Нет политик хранения

Старые образы копятся бесконечно

/metrics открыт без входа

Утечка информации

Скан выключен или падает

Уязвимости не обнаруживаются

Критические уязвимости в образах

Риск для production

Бэкапы не настроены / упали / опоздали

Данные не защищены

Кеш ходит в upstream по HTTP

Трафик кеша в открытом виде

Находки обновляются при каждом обращении к сводке. Они видны и в журнале, и через MCP.

Разделы управления

Плагин добавляет в хаб полноценные разделы:

  • Репозитории → Теги — digest, размер, платформы, время загрузки, «неизменяемый», уязвимости по уровням. Удаление с подтверждением; доступно сухим прогоном

  • Уязвимости тега — уровень, CVE, пакет, установленная/исправленная версия. Кнопка «Сканировать» ставит образ в очередь

  • Проекты — создать (публичный, квота в ГБ, кеш другого реестра, запрет pull уязвимых образов), сменить запрет, удалить пустой

  • Бэкапы — куда, расписание, последний удачный и размер, ошибка, архивы; «Сделать бэкап сейчас»

  • Роботы — создать (проект или *, pull или pull+push, срок), выдать новый секрет, удалить

  • Политики — хранение и неизменяемость: правка JSON в окне с диффом и историей версий. «Применить хранение» — сразу или сухим прогоном

  • Пользователи, вебхуки (с кнопкой «Проверить»), журнал (последние 200 записей)

Всё это — не интерфейс самого реестра. Это интерфейс хаба, который общается с реестром через плагин. Администратор не открывает /ui реестра — он работает в одном окне.


Сценарии: плагин добавляет глаголы в язык

Помните 29 глаголов? Плагин добавляет новые — без изменения ядра.

Команды плагина в сценарии начинаются с его имени:

rgstr reposrgstr tags shop/webrgstr tag-delete shop/web 1.0.0rgstr gcrgstr retention runrgstr project shop quota 20rgstr project dockerhub proxy https://registry-1.docker.io block criticalrgstr scan shop/web 1.0rgstr backup runrgstr robot ci-shop project shop push to-pipeline shop env @registry

У project слова quota, proxy и block (critical, high, medium, low) — в любом порядке.

Проверка: кнопка «Проверить» спрашивает плагин, правильно ли написаны слова.

Сухой прогон показывает, что было бы сделано, без применения.

Права: хаб проверяет права токена до вызова плагина. Робот, секрет которого некуда положить, не создаётся.

Пример: ночная чистка

Сохранённый сценарий, запуск по расписанию:

rgstr retention runrgstr gc

Пример: бэкап перед обновлением

rgstr backup rundeploy rgstr

Пример: создать проект и дать доступ конвейеру

rgstr project shop quota 20rgstr robot ci-shop project shop to-pipeline shop env @registrydeploy shop

Запуск по расписанию или через API:

curl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"dry_first":true}' https://hub.example.com/api/hub/scripts/7/run

API плагинов

Любая операция плагина доступна через единую точку входа:

POST /api/hub/plugins/<имя>/call

Тело запроса:

{"op": "<операция>", "args": {...}, "dry_run": true}

Примеры для плагина rgstr:

# Список репозиториевcurl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"op":"repos"}' https://hub.example.com/api/hub/plugins/rgstr/call# Сколько освободит сборка мусора — без удаленияcurl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"op":"gc_run","dry_run":true}' https://hub.example.com/api/hub/plugins/rgstr/call# Уязвимости образаcurl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"op":"vulns","args":{"repo":"shop/web","tag":"1.0"}}' \  https://hub.example.com/api/hub/plugins/rgstr/call# Запретить pull с критическими уязвимостями в проектеcurl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"op":"project_block","args":{"name":"shop","severity":"critical"}}' \  https://hub.example.com/api/hub/plugins/rgstr/call# Создать робота сразу в конвейерcurl -sS -X POST -H "Authorization: Bearer $NKT_TOKEN" -H 'Content-Type: application/json' \  -d '{"op":"robot_create","args":{"name":"ci-shop","project":"shop","to_pipeline":"shop","env":"@registry"}}' \  https://hub.example.com/api/hub/plugins/rgstr/call

Права: токен должен иметь действие «плагин <имя>» и пределы (хосты, проекты, конвейеры). Хаб проверяет права до передачи запроса плагину.


MCP: плагин как инструмент для ИИ-агентов

Каждый плагин регистрирует инструменты MCP — те же операции, доступные ИИ-агентам (Claude Code, Cursor, и т.д.) через MCP-сервер хаба.

Инструменты плагина rgstr:

Категория

Инструменты

Доступ

Чтение

rgstr_summary, rgstr_repos, rgstr_tags, rgstr_vulns, rgstr_projects, rgstr_robots, rgstr_users, rgstr_policies, rgstr_backups

Любой токен

Изменения

rgstr_tag_delete, rgstr_gc_run, rgstr_retention_run, rgstr_scan_run, rgstr_backup_run, rgstr_project_create, rgstr_project_block, rgstr_project_delete, rgstr_robot_create, rgstr_robot_secret, rgstr_robot_delete

Токен с «плагин rgstr»

Принцип: агент может спросить всё, но изменять только с соответствующим токеном. И главное — агент никогда не видит секреты.

Пример: робот для конвейера через агента

rgstr_robot_create принимает to_pipeline и env (@registry или имя переменной). Агент вызывает операцию — хаб кладёт секрет в конвейер. Агент не получает значение секрета: без to_pipeline и env операция ему просто недоступна.

Пример: автоматическая реакция на уязвимости

Агент может:

  1. Вызвать rgstr_repos → получить список репозиториев

  2. Вызвать rgstr_vulns для каждого → найти критические

  3. Вызвать rgstr_project_block с severity: "critical" → запретить pull уязвимых образов

Всё через те же права токена, те же пределы, тот же журнал действий.

Полный список инструментов с аргументами — «Плагины» → <имя> → «Для агентов».


Роботы: плагин связывает реестр и конвейер

Отдельно стоит выделить ключевую фичу плагина — создание робота сразу в конвейер.

Конвейеру, который берёт образы из реестра, нужен ключ в «Секреты» → «Реестры». Плагин кладёт его туда сам — секрет никто не видит.

В окне: «Роботы» → «Создать» → поля «Сразу в конвейер» и «Имя переменной» = @registry.

Хаб записывает:

  • Ключ с адресом registry.example.com

  • Логин robot$ci-shop

  • Секрет (в «Реестры» конвейера)

Правила:

  • Ключ с тем же адресом заменяется, его CA сохраняется

  • Запись идёт с историей версий

  • В журнале действий — без значения секрета

Обычное имя вместо @registry (например, REGISTRY_TOKEN) — запись в .env конвейера.

Это и есть принцип плагина: не просто показать информацию, а связать внешний сервис с внутренними объектами хаба (конвейерами, секретами, хостами) одним действием.


Что делает и не делает плагин

Плагин делает:

✅ Оркестрирует внешний сервис через его API
✅ Показывает состояние и находки в хабе
✅ Добавляет команды в язык сценариев
✅ Даёт инструменты для ИИ-агентов
✅ Связывает внешние объекты (роботы, проекты) с внутренними (конвейеры, секреты)
✅ Проверяет права до выполнения операции

Плагин не делает:

❌ Не меняет внешний сервис: всё, что выше, — документированные возможности самого сервиса
❌ Не хранит секреты внешнего сервиса нигде, кроме окружения службы плагина
❌ Не показывает секреты роботов в журналах и не отдаёт их агенту
❌ Не подменяет аутентификацию: плагин входит локальным администратором, даже если реестр использует LDAP/OIDC
❌ Не выполняет операции без проверки прав хабом

Принцип: плагин — это контракт. Хаб знает, какие операции можно запросить. Плагин знает, как их выполнить. Внешний сервис не знает о хабе ничего.


Заключение

Система плагинов — это то, как 29 глаголов становятся бесконечностью. Один плагин — один внешний сервис. Три точки расширения: интерфейс, сценарии, MCP. Права проверяются до вызова. Секреты не покидают службу. Сухой прогон перед применением. Журнал каждого действия. Не нужно менять ядро, чтобы добавить реестр образов. Не нужно писать код, чтобы подключить DNS. Не нужно понимать внутренности сервиса, чтобы им управлять.

Одно ядро. Бесконечность рук.


Ссылки:

ссылка на оригинал статьи https://habr.com/ru/articles/1100668/