본문 바로가기
WIKI 기술 지식 베이스

카탈로그 구성

원문 보기 위키 갱신

카탈로그 구성 (Catalog Configuration)

Backstage 소프트웨어 카탈로그의 프로세서, 프로바이더, 규칙, 읽기 전용 모드 등을 구성하는 방법을 설명하는 문서예요.

출처: 문서

본문

프로세서 (Processors)

카탈로그에는 원격 소스에서 원시 엔티티 데이터를 읽고, 파싱하고, 변환하고, 검증하는 것 같은 카탈로그 수집(ingestion) 작업을 수행하는 프로세서라는 개념이 있어요. 이러한 프로세서는 catalog.processors 구성 키 아래에 구성돼요.

정적 location 구성 (Static Location Configuration)

기본 @backstage/create-app 템플릿에 나와 있는 것처럼 카탈로그의 가장 단순한 구성은 정적 구성으로 YAML 파일을 가리키는 location을 선언적으로 추가하는 것이에요.

Location은 catalog.locations 키 아래에 카탈로그에 추가돼요.

catalog:  locations:    - type: url      target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/artist-lookup-component.yaml

url 유형의 location은 카탈로그에 포함된 표준 프로세서(UrlReaderProcessor)가 처리하므로 프로세서 구성이 필요 없어요. 하지만 이 프로세서는 주어진 URL을 어떻게 가져올지 이해하기 위해 통합(integration)이 필요해요. 위 예시의 경우 github.com에서 파일을 읽기 위해 GitHub 통합을 구성해야 해요.

정적 구성을 통해 추가된 location은 카탈로그 locations API로 제거할 수 없어요. 이러한 location을 제거하려면 구성에서 제거해야 해요.

catalog-info.yaml 파일에 있는 구문 오류나 다른 유형의 오류는 조사를 위해 로그에 기록돼요. 오류로 인해 처리가 중단되지는 않아요.

동일한 metadata.name 속성을 가진 여러 catalog-info.yaml 파일이 발견되면 하나가 처리되고 나머지 모두는 건너뛰어져요. 이 작업은 추가 조사를 위해 로그에 기록돼요.

로컬 파일 (type: file) 구성

url location 외에도 file location 유형을 사용해 로컬 파일 시스템의 콘텐츠를 가져올 수 있어요. 이는 로컬 개발, 테스트 설정, 예시 데이터에만 사용해야 하며 프로덕션 데이터에는 사용하지 마세요. 또한 $text, $json, $yaml 같은 자리표시자를 사용할 수 없어요. 하지만 현재 파일을 기준으로 다른 파일을 참조할 수는 있어요. 광범위한 예시는 전체 카탈로그 예시 데이터 집합을 참고하세요.

다음은 examples 폴더에서 all.yaml 파일을 가져오는 예시예요. ../../를 사용해 백엔드의 현재 실행 경로에서 두 단계 위로 올라간다는 점에 주의하세요. 이는 일반적으로 packages/backend/예요.

catalog:  locations:    - type: file      target: ../../examples/all.yaml

:::note Docker 컨테이너에서 일부 file 구성을 테스트해야 하는 경우가 있을 수 있어요. 그런 경우 기본 설정에서 백엔드가 프론트엔드를 제공하므로 경로는 루트에서 시작돼요. 또한 파일을 컨테이너에 복사해야 해요. 위 예시를 사용하면 다음과 같아요. :::

catalog:  locations:    - type: file      target: ./examples/all.yaml

통합 프로세서 (Integration Processors)

통합은 단순히 외부 제공자에 대한 url location 유형을 처리하는 메커니즘을 제공하거나, GitHub 조직에서 엔티티 디스크립터 파일을 스캔하는 GitHub discovery 프로세서 같은 추가 프로세서를 기본 제공할 수도 있어요.

각 통합이 무엇을 제공하는지 확인하려면 통합 문서를 참고하세요.

사용자 지정 프로세서 (Custom Processors)

이미 소프트웨어를 추적하는 기존 시스템에서 엔티티를 수집하려면 기존 시스템과 Backstage의 디스크립터 형식 사이를 변환하는 사용자 지정 프로세서를 작성할 수도 있어요. 이는 '외부 통합'에 문서화되어 있어요.

프로세서 구성

catalog.processorOptions 키 아래에서 프로세서를 구성할 수 있어요. 이름별로 각 프로세서에 대한 옵션을 정의할 수 있어요. 프로세서 옵션으로 프로세서를 비활성화하거나 우선순위를 설정할 수 있어요.

catalog:  processorOptions:    processorName:      disabled: false # Defaults to false      priority: 100

priority는 프로세서가 실행되는 순서를 정의하는 숫자예요. 숫자가 낮을수록 우선순위가 높아요. 기본 우선순위는 20이에요.

공급자 구성 (Provider configuration)

구성을 사용해 엔티티 공급자를 비활성화하는 것도 가능해요. catalog.providerOptions 키 아래에서 공급자를 구성할 수 있어요. 키는 공급자 이름이에요.

catalog:  providerOptions:    providerName:      disabled: true

카탈로그 규칙 (Catalog Rules)

기본적으로 카탈로그는 kind가 Component, API, Location인 엔티티만 수집하도록 허용해요. 다른 kind의 엔티티가 추가되도록 허용하려면 카탈로그에 규칙을 추가해야 해요. 규칙은 별도의 catalog.rules 키에 추가하거나, 정적으로 구성된 location에 추가돼요.

예를 들어 다음 구성이 주어졌을 때:

catalog:  rules:    - allow: [Component, API, Location, Template]  locations:    - type: url      target: https://github.com/org/example/blob/master/org-data.yaml      rules:        - allow: [Group]

어떤 location에서든 kind Component, API, Location, Template의 엔티티를 추가할 수 있고, org-data.yaml(정적으로 구성된 location으로도 읽힘)에서는 Group 엔티티를 추가할 수 있어요.

catalog.rules 키가 있으면 기본값을 대체한다는 점에 유의하세요. 즉 기본 kind들을 여전히 허용하려면 기본 kind에 대한 규칙을 추가해야 해요.

다음 구성은 어떤 kind의 엔티티든 카탈로그에 추가되는 것을 거부해요.

catalog:  rules: []

읽기 전용 모드 (Readonly mode)

프로세서는 정적 location 구성이나 GitHub Discovery 같은 discovery 프로세서와 결합될 때 엔티티 수집을 자동화하는 좋은 방법을 제공해요. 엔티티를 찾는 데 프로세서 사용을 강제하려면 카탈로그를 readonly 모드로 구성할 수 있어요. 이 구성은 카탈로그 API로 location을 등록하고 삭제하는 것을 비활성화해요.

catalog:  readonly: true

엔티티를 만들고, 업데이트하고, 삭제하는 카탈로그 API에 의존하는 어떤 플러그인도 이 모드에서는 작동하지 않는다는 점에 유의하세요.

이 모드를 사용할 때 UUID로 엔티티를 삭제하는 DELETE /entities/by-uid/:uid는 허용돼요. 명시적 삭제에서 언급한 것처럼 다시 발견될 수 있어요.

이 구성의 일반적인 사용 사례는 조직이 Backstage에 미러링되어야 하는 원격 소스가 있을 때예요. Backstage를 이 원격 소스의 미러로 만들려면 사용자가 catalog-import 플러그인 등으로 새 엔티티를 등록할 수도 없어야 해요.

Location 분석 권한 (Location analysis permissions)

카탈로그 location 분석 엔드포인트는 구성된 location 분석기를 호출하며, 분석기는 구성된 소스 제어 통합을 사용하고 카탈로그 처리 파이프라인의 일부를 dry-run 모드로 실행할 수 있어요. 권한 시스템이 활성화되면 호출자에게 catalog.location.analyze가 부여되어야 해요.

분석은 서비스 컨텍스트에서 작동하는 구성된 통합과 UrlReaderService를 통해 읽을 수 있어요. 그러한 소스를 검사할 수 있어야 하는 사용자에게 권한을 부여하고, Backstage 위협 모델에 따라 backend.reading.allow의 범위를 유지하세요.

고아 엔티티 자동 제거 (Automatic removal of orphaned entities)

엔티티는 여러 방법으로 고아(orphaned)가 될 수 있어요. 예를 들어 카탈로그의 등록을 업데이트하지 않고 버전 제어 시스템에서 catalog-info YAML 파일을 한 위치에서 다른 위치로 옮길 때요. 기본 동작은 고아 엔티티를 자동으로 제거하는 것이에요. 고아 엔티티에 대해 여기에서 더 자세히 읽을 수 있어요.

하지만 고아 엔티티를 유지하고 싶다면 다음 구성을 사용할 수 있고, 자동 정리는 비활성화돼요.

catalog:  orphanStrategy: keep

고아 엔티티 공급자에서 엔티티 자동 제거

기본적으로 카탈로그에 엔티티를 제공했던 엔티티 공급자가 더 이상 구성되지 않으면, 그 공급자가 제공한 엔티티는 자동 제거돼요.

대신 이러한 엔티티를 유지하려면 다음 구성을 사용할 수 있어요.

catalog:  orphanProviderStrategy: keep

과거에 엔티티를 카탈로그에 수집했던 공급자가 설치되어 있고 그 엔티티를 유지하고 싶다면, 공급자를 카탈로그에 다시 추가하는 것을 권장해요. 공급자가 실행되길 원하지 않는다면 매우 큰 간격으로 예약할 수 있어요.

처리 간격 (Processing Interval)

처리 루프는 특정 간격으로 등록된 프로세서를 모든 엔티티에 실행하는 책임을 가져요. 그 간격은 processingInterval app-config 매개변수로 구성할 수 있어요.

catalog:  processingInterval: { minutes: 45 }

값은 years, months, weeks, days, hours, minutes, seconds, milliseconds 필드 중 하나 이상을 가진 duration 객체예요. 예를 들어 { hours: 1, minutes: 15 }처럼 결합할 수 있는데, 이는 기본적으로 처리 루프가 대략 75분마다 엔티티를 방문하기를 원한다는 의미예요.

이것은 단지 제안된 최소값이며 실제 간격은 더 길어질 수 있다는 점에 유의하세요. 내부적으로 카탈로그는 이 숫자를 작은 계수로 확장하고 그 범위에서 임의의 숫자를 골라 부하를 분산해요. 카탈로그가 과부하되어 간격 동안 모든 엔티티를 처리할 수 없다면, 주어진 엔티티의 처리 실행 사이에 걸리는 시간도 여기에 지정된 것보다 길어질 수 있어요.

이 값을 너무 낮게 설정하면 catalog-info 파일을 보관하는 버전 제어 시스템처럼 프로세서가 쿼리하는 외부 시스템의 속도 제한(rate limit)이 소진될 위험이 있어요.

스티칭 (Stitching)

스티칭은 작업자 큐(worker queue)를 통해 엔티티를 비동기적으로 완성해요. catalog.stitchingStrategy 아래에서 다음 매개변수를 조정할 수 있어요.

  • pollingInterval - 스티칭이 필요한 엔티티를 폴링하는 간격

  • stitchTimeout - 엔티티가 스티칭되기를 기다리는 최대 시간

이 매개변수들은 processingInterval 매개변수와 비슷한 duration 객체를 받아들여요.

app-config.yaml

catalog:  stitchingStrategy:    pollingInterval: { seconds: 1 }    stitchTimeout: { minutes: 1 }

카탈로그 오류 구독하기 (Subscribing to Catalog Errors)

카탈로그 오류는 events 플러그인 @backstage/plugin-events-node에 게시돼요. 이벤트를 구독하고 오류에 응답할 수 있어요. 예를 들어 오류를 로그로 기록하고 싶을 수 있어요.

첫 번째 단계는 Backstage 애플리케이션에 events 백엔드 플러그인을 추가하는 것이에요. Backstage 애플리케이션 디렉터리로 이동해 플러그인 패키지를 추가해요.

Backstage 루트 디렉터리에서

yarn --cwd packages/backend add @backstage/plugin-events-backend

이제 백엔드에 events 백엔드 플러그인을 설치할 수 있어요.

packages/backend/src/index.ts

backend.add(import('@backstage/plugin-events-backend'));

오류 로깅 (Logging Errors)

카탈로그 오류를 로그로 기록하려면 @backstage/plugin-catalog-backend-module-logs 모듈을 설치할 수 있어요.

catalog logs 모듈을 설치해요.

Backstage 루트 디렉터리에서

yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs

모듈을 백엔드에 추가해요.

packages/backend/src/index.ts

backend.add(import('@backstage/plugin-catalog-backend-module-logs'));

이렇게 하면 warn 레벨로 오류가 기록돼요.

카탈로그가 이벤트를 내보내면서 로그가 표시되어야 해요. 예시:

[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml

사용자 지정 오류 처리 (Custom Error Handling)

오류를 기록하는 것과 다른 특정 로직으로 카탈로그 오류를 처리하고 싶다면 다음이 시작하는 데 도움이 될 거예요. 예를 들어 누군가 조사하도록 알림을 보내거나 티켓을 만들고 싶을 수 있어요.

카탈로그 오류 이벤트를 구독하는 백엔드 모듈을 만들어요. 토픽은 experimental.catalog.errors예요.

packages/backend/src/index.ts

import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend';import {  coreServices,  createBackendModule,} from '@backstage/backend-plugin-api';import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node';interface EventsPayload {  entity: string;  location?: string;  errors: Error[];}interface EventsParamsWithPayload extends EventParams {  eventPayload: EventsPayload;}const eventsModuleCatalogErrors = createBackendModule({  pluginId: 'events',  moduleId: 'catalog-errors',  register(env) {    env.registerInit({      deps: {        events: eventsServiceRef,        logger: coreServices.logger,      },      async init({ events, logger }) {        events.subscribe({          id: 'catalog',          topics: [CATALOG_ERRORS_TOPIC],          async onEvent(params: EventParams): Promise<void> {            const event = params as EventsParamsWithPayload;            const { entity, location, errors } = event.eventPayload;            // Add custom logic here for responding to errors            for (const error of errors) {              logger.warn(error.message, {                entity,                location,              });            }          },        });      },    });  },});

이제 모듈을 설치해요.

packages/backend/src/index.ts

backend.add(eventsModuleCatalogErrors);

OpenAPI 및 AsyncAPI 자리표시자 지원

OpenAPI Catalog 백엔드 모듈은 openapi(및 asyncapi) 자리표시자 키에 대한 JSON Schema 자리표시자 리졸버를 등록해요. 이를 통해 카탈로그 엔티티에서 $openapi와 $asyncapi 참조를 사용하면서, 스키마 처리의 일부로 모든 기반 $ref 포인터가 해석되고 번들링되도록 할 수 있어요.

설치 (Installation)

  • 패키지를 백엔드에 추가해요:

Backstage 루트 디렉터리에서

yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-openapi
  • 백엔드에서 모듈을 등록해요:

packages/backend/src/index.ts

backend.add(import('@backstage/plugin-catalog-backend-module-openapi'));

사용 (Usage)

$ref 해석을 트리거하려면 카탈로그 엔티티 정의에서 $openapi(또는 $asyncapi) 자리표시자를 사용해요.

apiVersion: backstage.io/v1alpha1kind: APImetadata:  name: example  description: Example APIspec:  type: openapi  lifecycle: production  owner: team  definition:    $openapi: ./spec/openapi.yaml # by using $openapi Backstage will now resolve all $ref instances

Backstage OpenAPI 모듈

Backstage가 핵심 API(예: Catalog와 Scaffolder)를 정의하는 데 OpenAPI를 점점 더 많이 사용함에 따라, 이러한 API를 발견하고 상호 작용하는 것은 외부 도구를 통합하는 데 필수적이에요.

Backstage OpenAPI 모듈을 설치하면 Backstage 인스턴스 플러그인용 OpenAPI 명세를 카탈로그에 직접 쉽게 노출할 수 있어요.

설치 (Installation)

  • 백엔드에 모듈을 설치해요:
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-backstage-openapi
  • 백엔드에서 모듈을 등록해요:

packages/backend/src/index.ts

backend.add(  import('@backstage/plugin-catalog-backend-module-backstage-openapi'),);
  • app-config.yaml에 구성을 추가해요:

app-config.yaml

catalog:  providers:    backstageOpenapi:      plugins:        - catalog        - scaffolder      # Optional configuration:      # definitionFormat controls how generated definitions are serialized.      # Supported values: 'json' (default) or 'yaml'.      # definitionFormat: json      # entityOverrides can be used to override parts of the produced entities.      # For example, to add a tag to all generated APIs:      # entityOverrides:      #   metadata:      #     tags:      #       - from-openapi

더 알아보기 (Learn more)