Platform engineering продают как историю про компании с сотнями команд: свой каталог, свои golden paths, отдельный platform-инженер в штате. У маленькой команды из трёх-пяти человек естественная реакция — «это не про нас, у нас и так все всё знают». Проблема в том, что «все всё знают» работает ровно до первого отпуска или увольнения, а дальше знание о том, как поднять новый сервис, живёт в переписке в Slack и голове одного человека. Минимальный Backstage — это не про масштаб, а про то, чтобы это знание не терялось.
Содержание
Открыть содержание
- IDP — это не платформа, а три конкретные вещи
- Почему именно сейчас, а не два года назад
- Минимальный Backstage в docker-compose
- Software Template: новый сервис одной кнопкой
- Сравнение: без каталога и с минимальным Backstage
- Ловушки, о которые спотыкаются даже маленькие команды
- Как проверить, что всё работает
- Итог
IDP — это не платформа, а три конкретные вещи
Internal Developer Platform звучит как что-то тяжеловесное, но на практике это три компонента, каждый из которых закрывает свою дыру.
- Каталог сервисов — единый список того, что вообще есть: какие сервисы существуют, кто владелец, где репозиторий, где дашборд, куда смотреть при инциденте. Без каталога это знание рассеяно по головам и закреплённым сообщениям в чате.
- Golden paths — не «единственно верный способ», а протоптанная тропа: если вы делаете обычный CRUD-сервис на Go, вот стандартный способ его собрать, задеплоить и мониторить, уже проверенный на трёх предыдущих сервисах.
- Scaffolder — механизм, который материализует golden path в код по кнопке: не документация «как сделать», а генератор, который сразу делает.
Порознь каждый из них можно кое-как заменить: каталог — таблицей в Notion, golden path — статьёй в вики, scaffolder — cookiecutter-шаблоном, который никто не обновляет. Работает какое-то время. Ломается ровно тогда, когда команда чуть подрастает или меняется состав — Notion-таблица устаревает, статью никто не читает до конца, а шаблон из своего форка репозитория никто не поддерживает.
Почему именно сейчас, а не два года назад
До недавнего времени поднять Backstage себе означало содержать отдельный Node.js-монорепо, разбираться в plugin API, который менялся между минорными версиями, и тратить на это недели, а не выходные. Причины, по которым это изменилось:
- Plugin API стабилизировался. Backstage прошёл через New Backend System, и плагины из сообщества (TechDocs, Kubernetes, GitHub Actions) теперь ставятся без форка ядра.
- Появились «light»-дистрибутивы. Официальный Helm chart и сборки вроде Roadie убрали ручную настройку сборки — образ уже собран, конфигурация выносится в YAML-файлы, а не в код.
- Docker-first старт стал нормой. Официальный образ
backstageиз create-app стартует в docker-compose с базой Postgres за десять минут, без npm-инсталляции на хосте.
Итог: то, что раньше было отдельным проектом с собственным roadmap, теперь укладывается в конфигурацию выходного дня.
Минимальный Backstage в docker-compose
Ниже — не production-конфигурация с полным auth и HA, а рабочий минимум, чтобы за один вечер увидеть каталог и первый Software Template живьём.
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: backstage
POSTGRES_PASSWORD: backstage
POSTGRES_DB: backstage
volumes:
- backstage-db:/var/lib/postgresql/data
backstage:
image: ghcr.io/backstage/backstage:1.32.0
depends_on:
- postgres
ports:
- "7007:7007"
environment:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: backstage
POSTGRES_PASSWORD: backstage
GITHUB_TOKEN: ${GITHUB_TOKEN}
volumes:
- ./app-config.production.yaml:/app/app-config.production.yaml
volumes:
backstage-db:
Ключевая идея этого файла в том, что вся кастомизация — в примонтированном app-config.production.yaml, а не в пересборке образа. В нём описываются интеграция с вашим GitHub/GitLab (откуда каталог будет читать catalog-info.yaml из репозиториев), TechDocs (документация из markdown прямо в интерфейсе) и список Software Templates:
catalog:
locations:
- type: url
target: https://github.com/acme/catalog-registry/blob/main/catalog-info.yaml
providers:
github:
acmeOrg:
organization: "acme"
catalogPath: "/catalog-info.yaml"
schedule:
frequency: { minutes: 30 }
Провайдер github раз в 30 минут обходит организацию и подтягивает catalog-info.yaml из каждого репозитория, где он есть, — это и есть автоматическое наполнение каталога без ручного добавления сервисов один за другим.
Software Template: новый сервис одной кнопкой
Каталог без scaffolder — это просто список, который надо поддерживать руками. Настоящий выигрыш начинается с Software Template — YAML-описания шагов, которые Backstage прогоняет, когда разработчик нажимает «Create» в интерфейсе.
Минимальный шаблон для нового Go-сервиса:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: golden-path-go-service
title: "Go-сервис (golden path)"
spec:
parameters:
- properties:
name:
type: string
title: "Имя сервиса"
steps:
- id: fetch
name: "Сгенерировать из скелета"
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
- id: publish
name: "Создать git-репозиторий"
action: publish:github
input:
repoUrl: "github.com?owner=acme&repo=${{ parameters.name }}"
- id: register
name: "Зарегистрировать в каталоге"
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: "/catalog-info.yaml"
Папка ./skeleton — это обычный набор файлов-шаблонов с плейсхолдерами ${{ values.name }}: Dockerfile, Helm-чарт с уже настроенными readiness/liveness-проверками, .github/workflows/ci.yaml с линтером, тестами и сборкой образа, и сам catalog-info.yaml, чтобы сервис сразу появился в каталоге как только репозиторий будет создан.
Результат для разработчика: три клика в интерфейсе — имя сервиса, «Create», подтверждение — и на выходе git-репозиторий с рабочим CI, который уже проходит зелёным на первом коммите, потому что скелет уже прошёл через этот пайплайн раньше на других сервисах.
Сравнение: без каталога и с минимальным Backstage
| Без IDP | Минимальный Backstage | |
|---|---|---|
| Где искать список сервисов | Slack, память, если повезёт — Notion | Каталог, обновляется автоматически |
| Новый сервис | Копипаста из «похожего» репо + правки руками | Software Template, 3 клика |
| CI нового сервиса | Настраивается с нуля или скопирован с багами | Уже в скелете, проверен на предыдущих сервисах |
| Онбординг нового инженера | Устные объяснения + догадки | Golden path — уже задокументированная норма |
| Владелец сервиса | «Кажется, это делал Петя» | Явно указан в catalog-info.yaml |
Ловушки, о которые спотыкаются даже маленькие команды
- Auth оставляют «на потом» и живут с ним вечно. Guest-провайдер удобен для локального теста, но если Backstage смотрит наружу хотя бы из внутренней сети,
catalog:registerи создание репозиториев без привязки к личности — это открытая дверь. Минимум — GitHub OAuth-провайдер, благо вapp-configэто блок из пяти строк. - Postgres без бэкапа. Каталог — не только зеркало гита: в нём накапливаются TechDocs, история scaffolder-запусков, кастомные аннотации. Потерять volume — значит собирать каталог заново руками.
- Secrets в
app-config.yaml, закоммиченном в репозиторий. GitHub-токен и данные для Postgres должны приходить через переменные окружения (как в примере выше) или секрет-менеджер, а не лежать текстом рядом с конфигом в git. - Обновление плагинов без плана. New Backend System сильно снизил breaking changes, но мажорные апдейты самого Backstage всё ещё требуют чтения changelog. Правило простое: обновляться не реже раза в квартал маленькими шагами, а не раз в два года одним прыжком через десяток мажорных версий.
Как проверить, что всё работает
Три быстрые проверки после первого запуска. Первая — каталог живой: curl -s localhost:7007/api/catalog/entities | jq length должен вернуть число больше нуля после того, как GitHub-провайдер отработал хотя бы один цикл синхронизации. Вторая — сам сценарий: пройти Software Template от параметров до конца и убедиться, что новый репозиторий действительно появился на GitHub и содержит запущенный workflow. Третья — то, ради чего всё затевалось: открыть Actions в свежесозданном репозитории и увидеть, что CI прошёл зелёным без единой ручной правки после генерации.
Итог
IDP — это не корпоративный ритуал для компаний с отдельным platform-департаментом, а способ один раз кодифицировать то, как ваша команда правильно делает сервисы, и больше не объяснять это каждому новому человеку устно. Стартовая стоимость — один вечер на docker-compose и один Software Template под самый частый тип сервиса в вашем стеке. Окупаемость — уже на втором-третьем новом сервисе, который поднимается за минуты вместо копипасты с чужими багами.