Перейти к содержимому
Hogin Hogin
Назад

Backstage за выходные: IDP и golden paths для маленькой команды

7 мин чтения

Platform engineering продают как историю про компании с сотнями команд: свой каталог, свои golden paths, отдельный platform-инженер в штате. У маленькой команды из трёх-пяти человек естественная реакция — «это не про нас, у нас и так все всё знают». Проблема в том, что «все всё знают» работает ровно до первого отпуска или увольнения, а дальше знание о том, как поднять новый сервис, живёт в переписке в Slack и голове одного человека. Минимальный Backstage — это не про масштаб, а про то, чтобы это знание не терялось.

Содержание

Открыть содержание

IDP — это не платформа, а три конкретные вещи

Internal Developer Platform звучит как что-то тяжеловесное, но на практике это три компонента, каждый из которых закрывает свою дыру.

Порознь каждый из них можно кое-как заменить: каталог — таблицей в Notion, golden path — статьёй в вики, scaffolder — cookiecutter-шаблоном, который никто не обновляет. Работает какое-то время. Ломается ровно тогда, когда команда чуть подрастает или меняется состав — Notion-таблица устаревает, статью никто не читает до конца, а шаблон из своего форка репозитория никто не поддерживает.

Без каталога знание живёт в головах, с каталогом — в одном месте

Почему именно сейчас, а не два года назад

До недавнего времени поднять Backstage себе означало содержать отдельный Node.js-монорепо, разбираться в plugin API, который менялся между минорными версиями, и тратить на это недели, а не выходные. Причины, по которым это изменилось:

Итог: то, что раньше было отдельным проектом с собственным 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, который уже проходит зелёным на первом коммите, потому что скелет уже прошёл через этот пайплайн раньше на других сервисах.

От клика в интерфейсе до зелёного CI без ручных шагов

Сравнение: без каталога и с минимальным Backstage

Без IDPМинимальный Backstage
Где искать список сервисовSlack, память, если повезёт — NotionКаталог, обновляется автоматически
Новый сервисКопипаста из «похожего» репо + правки рукамиSoftware Template, 3 клика
CI нового сервисаНастраивается с нуля или скопирован с багамиУже в скелете, проверен на предыдущих сервисах
Онбординг нового инженераУстные объяснения + догадкиGolden path — уже задокументированная норма
Владелец сервиса«Кажется, это делал Петя»Явно указан в catalog-info.yaml

Ловушки, о которые спотыкаются даже маленькие команды

Как проверить, что всё работает

Три быстрые проверки после первого запуска. Первая — каталог живой: curl -s localhost:7007/api/catalog/entities | jq length должен вернуть число больше нуля после того, как GitHub-провайдер отработал хотя бы один цикл синхронизации. Вторая — сам сценарий: пройти Software Template от параметров до конца и убедиться, что новый репозиторий действительно появился на GitHub и содержит запущенный workflow. Третья — то, ради чего всё затевалось: открыть Actions в свежесозданном репозитории и увидеть, что CI прошёл зелёным без единой ручной правки после генерации.

Итог

IDP — это не корпоративный ритуал для компаний с отдельным platform-департаментом, а способ один раз кодифицировать то, как ваша команда правильно делает сервисы, и больше не объяснять это каждому новому человеку устно. Стартовая стоимость — один вечер на docker-compose и один Software Template под самый частый тип сервиса в вашем стеке. Окупаемость — уже на втором-третьем новом сервисе, который поднимается за минуты вместо копипасты с чужими багами.


Поделиться:

Следующая статья
AI SRE-агенты в 2026: что они реально делают и где ломаются