콘텐츠로 이동

Backstage

소프트웨어 카탈로그 및 개발자 경험을 관리하기 위한 Spotify의 오픈소스 내부 개발자 포털 플랫폼.

명령어설명
npx @backstage/create-app@latest새 Backstage 애플리케이션 생성
npx @backstage/create-app@latest --skip-install종속성 설치 없이 앱 생성
cd my-backstage-app && yarn install종속성 설치
yarn dev개발 모드로 프론트엔드 및 백엔드 시작
yarn start프론트엔드만 시작
yarn start-backend백엔드만 시작
yarn build:backend프로덕션용 백엔드 빌드
yarn build모든 패키지 빌드
node_modules/.bin/backstage-cli --versionBackstage CLI 버전 확인
명령어설명
yarn build:backend --config ../../app-config.yaml구성과 함께 백엔드 빌드
docker build -t backstage -f packages/backend/Dockerfile .Docker 이미지 빌드
docker run -p 7007:7007 backstageBackstage 컨테이너 실행
명령어설명
yarn backstage-cli package start패키지를 개발 모드로 시작
yarn backstage-cli package build패키지 빌드
yarn backstage-cli package lint패키지 소스 코드 린트
yarn backstage-cli package test패키지 테스트 실행
yarn backstage-cli repo build --all모노레포의 모든 패키지 빌드
yarn backstage-cli repo lint --all모든 패키지 린트
yarn backstage-cli versions:bumpBackstage 종속성을 최신으로 업데이트
yarn backstage-cli versions:bump --release next다음 프리릴리스로 업데이트
yarn backstage-cli migrate package-roles패키지 역할 사용으로 마이그레이션
명령어설명
yarn backstage-cli create-plugin새 프론트엔드 플러그인 생성
yarn backstage-cli create-plugin --backend새 백엔드 플러그인 생성
yarn backstage-cli create-plugin --id my-plugin특정 ID로 플러그인 생성
yarn new템플릿에서 대화형으로 컴포넌트 생성
명령어설명
저장소 루트에 catalog-info.yaml 추가카탈로그에 컴포넌트 등록
catalog-info.yaml에서 kind: Component소프트웨어 컴포넌트 정의
catalog-info.yaml에서 kind: APIAPI 엔티티 정의
catalog-info.yaml에서 kind: System시스템 그룹 정의
catalog-info.yaml에서 kind: Domain비즈니스 도메인 정의
catalog-info.yaml에서 kind: Resource인프라 리소스 정의
catalog-info.yaml에서 kind: Group팀/그룹 정의
catalog-info.yaml에서 kind: User사용자 정의
catalog-info.yaml에서 kind: Location다른 카탈로그 파일 참조
명령어설명
spec.owner: team-name 설정엔티티 소유권 설정
spec.lifecycle: production 설정엔티티 라이프사이클 단계 설정
spec.type: service 설정컴포넌트 유형 설정 (service, website, library)
spec.dependsOn: ['component:other'] 설정종속성 정의
spec.providesApis: ['api-name'] 설정제공하는 API 선언
spec.consumesApis: ['api-name'] 설정사용하는 API 선언
spec.system: system-name 설정시스템에 할당
통합을 위해 metadata.annotations 설정CI/CD, 모니터링 등에 연결
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: payment-service
  description: Handles payment processing and billing
  annotations:
    github.com/project-slug: org/payment-service
    backstage.io/techdocs-ref: dir:.
    jenkins.io/job-full-name: payment-service/main
    pagerduty.com/service-id: PABC123
    sonarqube.org/project-key: org_payment-service
  tags:
    - java
    - payments
  links:
    - url: https://dashboard.example.com/payments
      title: Monitoring Dashboard
      icon: dashboard
    - url: https://wiki.example.com/payment-service
      title: Wiki
spec:
  type: service
  lifecycle: production
  owner: team-payments
  system: billing
  providesApis:
    - payment-api
  consumesApis:
    - user-api
    - notification-api
  dependsOn:
    - resource:payments-db
    - component:auth-service
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: payment-api
  description: Payment processing REST API
  tags:
    - rest
    - payments
spec:
  type: openapi
  lifecycle: production
  owner: team-payments
  system: billing
  definition: |
    openapi: "3.0.0"
    info:
      title: Payment API
      version: 1.0.0
    paths:
      /payments:
        post:
          summary: Create a payment
          responses:
            "201":
              description: Payment created
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
  name: billing
  description: Billing and payment processing system
spec:
  owner: team-payments
  domain: commerce
---
apiVersion: backstage.io/v1alpha1
kind: Domain
metadata:
  name: commerce
  description: E-commerce domain covering orders, payments, and fulfillment
spec:
  owner: group:engineering-leadership
명령어설명
template.yaml에서 kind: Template소프트웨어 템플릿 정의
spec.type: service 설정템플릿이 서비스를 생성
템플릿 액션에 spec.steps[] 설정스캐폴딩 단계 정의
action: fetch:template템플릿 파일 가져오기 및 렌더링
action: publish:github스캐폴딩된 저장소를 GitHub에 게시
action: publish:github:pull-request새 저장소 대신 PR 생성
action: catalog:register생성된 엔티티를 카탈로그에 등록
action: github:actions:dispatchGitHub Actions 워크플로우 트리거
템플릿에서 ${{ parameters.name }} 사용사용자 입력 매개변수 참조
폼 필드에 spec.parameters[] 설정템플릿 입력 폼 정의
매개변수에서 ui:widget: textarea 사용폼 필드 위젯 커스터마이즈
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: microservice-template
  title: Create a Microservice
  description: Scaffold a new microservice with CI/CD, monitoring, and docs
  tags:
    - recommended
    - microservice
spec:
  owner: team-platform
  type: service
  parameters:
    - title: Service Details
      required:
        - name
        - description
        - owner
      properties:
        name:
          title: Service Name
          type: string
          description: Unique name of the service
          ui:autofocus: true
          ui:options:
            rows: 5
        description:
          title: Description
          type: string
        owner:
          title: Owner
          type: string
          description: Team that owns this service
          ui:field: OwnerPicker
          ui:options:
            catalogFilter:
              kind: Group
    - title: Infrastructure
      properties:
        language:
          title: Language
          type: string
          enum: ["go", "java", "python", "typescript"]
          default: go
        database:
          title: Database
          type: string
          enum: ["postgres", "mysql", "none"]
          default: postgres
        enableMonitoring:
          title: Enable Monitoring
          type: boolean
          default: true
  steps:
    - id: fetch-base
      name: Fetch Base Template
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: ${{ parameters.name }}
          description: ${{ parameters.description }}
          owner: ${{ parameters.owner }}
          language: ${{ parameters.language }}
    - id: publish
      name: Publish to GitHub
      action: publish:github
      input:
        allowedHosts: ["github.com"]
        repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}
        description: ${{ parameters.description }}
        defaultBranch: main
        repoVisibility: internal
    - id: register
      name: Register in Catalog
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
        catalogInfoPath: /catalog-info.yaml
  output:
    links:
      - title: Repository
        url: ${{ steps['publish'].output.remoteUrl }}
      - title: Open in Catalog
        icon: catalog
        entityRef: ${{ steps['register'].output.entityRef }}
명령어설명
yarn add @backstage/plugin-catalog카탈로그 플러그인 설치
yarn add @backstage/plugin-techdocsTechDocs 플러그인 설치
yarn add @backstage/plugin-kubernetesKubernetes 플러그인 설치
yarn add @backstage/plugin-github-actionsGitHub Actions 플러그인 설치
yarn add @backstage/plugin-search검색 플러그인 설치
yarn add @backstage/plugin-scaffolder스캐폴더 플러그인 설치
yarn add @backstage/plugin-api-docsAPI 문서 플러그인 설치
yarn add @backstage/plugin-cost-insights비용 인사이트 플러그인 설치

packages/app/src/App.tsx에서 프론트엔드 플러그인 등록:

import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
import { TechDocsReaderPage } from '@backstage/plugin-techdocs';
import { SearchPage } from '@backstage/plugin-search';

const routes = (
  <FlatRoutes>
    <Route path="/catalog" element={<CatalogIndexPage />} />
    <Route path="/catalog/:namespace/:kind/:name" element={<CatalogEntityPage />}>
      <EntityLayout>
        <EntityLayout.Route path="/" title="Overview">
          <EntityOverviewContent />
        </EntityLayout.Route>
        <EntityLayout.Route path="/api" title="API">
          <EntityApiContent />
        </EntityLayout.Route>
        <EntityLayout.Route path="/docs" title="Docs">
          <EntityTechDocsContent />
        </EntityLayout.Route>
      </EntityLayout>
    </Route>
    <Route path="/docs" element={<TechDocsReaderPage />} />
    <Route path="/search" element={<SearchPage />} />
    <Route path="/catalog-graph" element={<CatalogGraphPage />} />
  </FlatRoutes>
);

packages/backend/src/index.ts에서 백엔드 플러그인 등록:

import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-catalog-backend-module-github-org'));
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-techdocs-backend'));
backend.add(import('@backstage/plugin-search-backend'));
backend.add(import('@backstage/plugin-search-backend-module-catalog'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs'));
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
backend.add(import('@backstage/plugin-kubernetes-backend'));

backend.start();
명령어설명
npx @techdocs/cli serve로컬에서 TechDocs 미리보기
npx @techdocs/cli serve --docker-image techdocs-container사용자 정의 Docker 이미지로 서비스
npx @techdocs/cli generateTechDocs 정적 사이트 생성
npx @techdocs/cli generate --source-dir .특정 디렉터리에서 생성
npx @techdocs/cli publish --publisher-type googleGcsGCS에 TechDocs 게시
npx @techdocs/cli publish --publisher-type awsS3S3에 TechDocs 게시
backstage.io/techdocs-ref 어노테이션 추가엔티티에 TechDocs 활성화
mkdocs.yml과 함께 docs/ 디렉터리 생성TechDocs 소스 설정
구성에서 techdocs.builder: 'local' 설정로컬 TechDocs 빌더 사용
구성에서 techdocs.builder: 'external' 설정외부 CI/CD 빌더 사용
site_name: Payment Service
nav:
  - Home: index.md
  - Architecture: architecture.md
  - API Reference: api-reference.md
  - Runbooks:
      - Deployment: runbooks/deployment.md
      - Incident Response: runbooks/incident-response.md
plugins:
  - techdocs-core
markdown_extensions:
  - admonition
  - pymdownx.highlight
  - pymdownx.superfences
명령어설명
yarn add @backstage/plugin-search검색 프론트엔드 설치
yarn add @backstage/plugin-search-backend검색 백엔드 설치
yarn add @backstage/plugin-search-backend-module-catalog카탈로그 검색 콜레이터 추가
yarn add @backstage/plugin-search-backend-module-techdocsTechDocs 검색 콜레이터 추가
app-config.yaml에서 검색 엔진 구성Lunr, Elasticsearch 또는 PgStore 설정
구성에서 search.pg 설정검색에 PostgreSQL 사용
구성에서 search.elasticsearch 설정검색에 Elasticsearch 사용
명령어설명
app-config.yaml 편집메인 구성 파일
app-config.local.yaml 편집로컬 개발 오버라이드
app-config.production.yaml 편집프로덕션 구성
구성에서 app.baseUrl 설정프론트엔드 URL 구성
구성에서 backend.baseUrl 설정백엔드 URL 구성
구성에서 backend.database 설정데이터베이스 연결 구성
구성에서 backend.cors.origin 설정CORS 출처 구성
구성에서 auth.providers 설정인증 프로바이더 구성
구성에서 catalog.locations[] 설정카탈로그 엔티티 소스 추가
구성에서 catalog.rules[] 설정엔티티 검증 규칙 정의
구성에서 integrations.github[] 설정GitHub 통합 토큰 구성
app:
  title: My Company Developer Portal
  baseUrl: http://localhost:3000

organization:
  name: My Company

backend:
  baseUrl: http://localhost:7007
  listen:
    port: 7007
  cors:
    origin: http://localhost:3000
    methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
  database:
    client: pg
    connection:
      host: ${POSTGRES_HOST}
      port: ${POSTGRES_PORT}
      user: ${POSTGRES_USER}
      password: ${POSTGRES_PASSWORD}

integrations:
  github:
    - host: github.com
      token: ${GITHUB_TOKEN}

auth:
  environment: development
  providers:
    github:
      development:
        clientId: ${GITHUB_CLIENT_ID}
        clientSecret: ${GITHUB_CLIENT_SECRET}

catalog:
  import:
    entityFilename: catalog-info.yaml
    pullRequestBranchName: backstage-integration
  rules:
    - allow: [Component, System, API, Resource, Location, Domain, Group, User]
  locations:
    - type: url
      target: https://github.com/my-org/backstage-catalog/blob/main/all-components.yaml
    - type: github-discovery
      target: https://github.com/my-org
    - type: github-org
      target: https://github.com/my-org

techdocs:
  builder: local
  generator:
    runIn: local
  publisher:
    type: local

kubernetes:
  serviceLocatorMethod:
    type: multiTenant
  clusterLocatorMethods:
    - type: config
      clusters:
        - url: ${K8S_CLUSTER_URL}
          name: production
          authProvider: serviceAccount
          serviceAccountToken: ${K8S_TOKEN}
관계출발도착설명
ownerOfGroup/UserComponent/API그룹이 엔티티를 소유
ownedByComponent/APIGroup/User엔티티가 그룹에 의해 소유됨
consumesApiComponentAPI컴포넌트가 API를 사용
providesApiComponentAPI컴포넌트가 API를 노출
dependsOnComponentComponent/Resource컴포넌트가 다른 것에 의존
dependencyOfComponent/ResourceComponent다른 것의 종속성임
partOfComponentSystem컴포넌트가 시스템에 속함
hasPartSystemComponent시스템이 컴포넌트를 포함
parentOfGroupGroup상위 팀 관계
childOfGroupGroup하위 팀 관계
memberOfUserGroup사용자가 그룹에 속함
hasMemberGroupUser그룹이 사용자를 포함
  1. 모든 저장소에 catalog-info.yaml을 사용하세요 — 모든 서비스, 라이브러리, API를 카탈로그에 등록하여 완전한 가시성을 확보하세요.

  2. 의미 있는 소유권을 설정하세요 — 모든 엔티티에 유효한 Group을 가리키는 owner 필드를 설정하여 책임과 라우팅을 가능하게 하세요.

  3. 엔티티에 풍부한 어노테이션을 추가하세요 — CI/CD, 모니터링, PagerDuty, 문서에 대한 어노테이션을 추가하여 카탈로그를 진정한 허브로 만드세요.

  4. 골든 패스를 위한 템플릿을 만드세요 — 스캐폴더를 사용하여 새 서비스를 생성하는 표준화된 방법을 정의하여 일관성을 보장하세요.

  5. TechDocs를 구현하세요 — TechDocs 플러그인과 mkdocs.yml을 사용하여 코드와 함께 문서를 유지하여 살아있는 문서를 만드세요.

  6. GitHub 디스커버리를 사용하세요 — 카탈로그 위치에 github-discovery를 구성하여 저장소를 자동으로 발견하고 등록하세요.

  7. 조직을 모델링하세요 — 팀 구조를 반영하는 Group과 User를 정의하여 소유권 추적과 팀 페이지를 가능하게 하세요.

  8. app-config.yaml을 환경 인식으로 유지하세요 — 개발에는 app-config.local.yaml을, 프로덕션 시크릿에는 환경 변수를 사용하세요.

  9. 플러그인 생태계를 구축하세요 — 조직의 특정 도구로 Backstage를 확장하기 위해 사용자 정의 프론트엔드 및 백엔드 플러그인을 만드세요.

  10. 시스템과 도메인을 정의하세요 — 시스템과 도메인을 사용하여 상위 수준 아키텍처를 모델링하여 개발자에게 플랫폼의 지도를 제공하세요.