백엔드를 새 백엔드 시스템으로 마이그레이션하기
이 섹션은 기존 Backstage 백엔드 서비스 패키지(일반적으로 packages/backend)를 새 백엔드 시스템을 사용하도록 마이그레이션하는 방법을 설명해요.
출처: 문서
본문
개요
이 섹션은 기존 Backstage 백엔드 서비스 패키지(일반적으로 packages/backend)를 새 백엔드 시스템을 사용하도록 마이그레이션하는 방법을 설명해요.
새 백엔드 시스템의 주요 이점 중 하나는 플러그인과 그 의존성이 배선되는 방식을 추상화하여, 플러그인이나 그 의존성이 발전할 때 거의 바꿀 필요가 없는 훨씬 간소화된 백엔드 패키지를 만들어낸다는 점이에요. 일반적으로 내부 플러그인과 지원 클래스 자체를 먼저 백엔드 시스템으로 변환할 필요는 없어요. 여기서의 마이그레이션은 주로 배선과, 가능하면 백엔드 패키지 자체에서 호환성 래퍼 사용을 다뤄요. 이 단계의 결과로 훨씬 더 작고 이해하기 쉬우며 유지 관리하기 쉬운 패키지를 얻게 되기를 바라며, 플러그인 마이그레이션은 나중에 별도의 작업으로 할 수 있기를 바라요.
전체 구조
일반적인 백엔드 패키지는 몇 가지 전체 구성 요소를 가져요:
-
모든 플러그인과 그 의존성의 생성과 배선을 담고 있는
index.ts파일 -
"환경(environment)", 즉 백엔드가 만들고 각 플러그인에 전달하는 다양한 의존성을 정의하는
types.ts파일 -
각 플러그인마다 하나의 파일이 있는
plugins폴더, 예:plugins/catalog.ts
index 파일은 이 전체적인 형태를 가져요:
import todo from './plugins/todo'; // repeated for N pluginsfunction makeCreateEnv(config: Config) { return (plugin: string): PluginEnvironment => { // ... build per-plugin environment };}async function main() { // ... early init const createEnv = makeCreateEnv(config); const todoEnv = useHotMemoize(module, () => createEnv('todo')); // repeated for N plugins const apiRouter = Router(); apiRouter.use('/todo', await todo(todoEnv)); // repeated for N plugins // ... wire up and start http server}module.hot?.accept();main().catch(...);
index 파일 마이그레이션
이 마이그레이션은 처음에는 plugins 폴더를 변경하지 않고 두고, 먼저 환경 타입을 제거하고 index 파일을 최소한으로 줄이는 데 초점을 맞춰요. 그런 다음 이후 단계에서 plugins 폴더를 조금씩 줄여, 그 파일들을 일반적으로 index 파일의 한 줄짜리 코드로 대체할 수 있어요.
새 index 파일의 기초를 세우는 것부터 시작해 보아요. 이전 내용을 주석 처리하거나, 참조를 위해 이전 파일을 index.backup.ts로 이름을 바꾸고 작업할 새 빈 파일을 만드는 것이 좋아요. index 파일의 새 빈 내용은 다음과 같아요:
packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';const backend = createBackend();backend.start();
환경 빌더와 main 구문이 완전히 사라졌음을 확인하세요.
또한 일부 백엔드 시스템 패키지를 의존성으로 추가하고 싶을 거예요. 다음 명령을 실행하세요:
# from the repository rootyarn --cwd packages/backend add @backstage/backend-defaults @backstage/backend-plugin-api
이제 로컬에서 친숙한 yarn workspace backend start 명령으로 이것을 시작하고 몇몇 로그가 지나가는 것을 볼 수 있을 거예요. 하지만 실제 기능이 추가되지 않은 빈 서비스일 뿐이에요. Ctrl+C로 중지하고 몇몇 플러그인을 다시 도입해 보아요.
packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';import { legacyPlugin } from '@backstage/backend-common';const backend = createBackend();backend.add(legacyPlugin('todo', import('./plugins/todo')));backend.start();
위에서 사용된 todo 플러그인은 예시일 뿐이며 자체 백엔드에서 활성화하지 않았을 수 있어요. plugins 폴더에 실제로 있는 다른 플러그인, 예를 들어 backend.add(legacyPlugin('catalog', import('./plugins/catalog')))로 자유롭게 바꾸세요.
legacyPlugin 헬퍼는 구식 플러그인 파일과 새 백엔드 시스템 사이의 간극을 쉽게 메워줘요. 이전에 env에서 수동으로 선언해야 했던 의존성이 백그라운드에서 모아지도록 보장하고, 관련 createPlugin export 함수에 전달하며, 반환되는 라우트 핸들러가 주어진 접두사와 함께 HTTP 라우터로 전달되도록 해요.
커스텀 환경 처리
단순한 경우라면 위에서 한 것이 충분하고 TypeScript도 만족하며 백엔드는 새 기능으로 실행돼요. 그렇다면 이 전체 섹션을 건너뛰고 types.ts를 삭제해도 돼요.
때로는 새로 추가된 줄에 PluginEnvironment 타입의 일부가 일치하지 않는다는 타입 오류가 보고될 수 있어요. 이는 환경이 기본값에서 변경됐을 때, 아마도 자체 커스텀 추가로 변경됐을 때 발생해요. 설치에서 이런 경우라면 여전히 방법이 있어요. 커스텀 legacyPlugin 함수를 만들 수 있어요.
packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';import { legacyPlugin } from '@backstage/backend-common';import { makeLegacyPlugin, loggerToWinstonLogger,} from '@backstage/backend-common';import { coreServices } from '@backstage/backend-plugin-api';const legacyPlugin = makeLegacyPlugin( { cache: coreServices.cache, config: coreServices.rootConfig, database: coreServices.database, discovery: coreServices.discovery, logger: coreServices.logger, permissions: coreServices.permissions, scheduler: coreServices.scheduler, tokenManager: coreServices.tokenManager, reader: coreServices.urlReader, identity: coreServices.identity, // ... and your own additions }, { logger: log => loggerToWinstonLogger(log), },);const backend = createBackend();backend.add(legacyPlugin('todo', import('./plugins/todo')));backend.start();
makeLegacyPlugin의 첫 번째 인자는 환경 키에서 실제 백엔드 시스템 서비스 참조로의 매핑이에요.
두 번째 인자는 그 서비스들의 타입을 env에 더 잘 맞는 것으로 "조정(tweak)"할 수 있게 해요. 예를 들어 logger 서비스 API 타입이 옛날의 원시 Winston logger에서 다른 커스텀 API로 바뀐 것을 볼 수 있을 텐데, 그래서 특정 것을 변환하는 데 헬퍼 함수를 사용해요.
위에서 언급한 것처럼 환경에 추가하려면 백엔드 시스템 배선이 작동하는 방식의 세부 사항에 들어가기 시작할 거예요. 서비스 참조와 실제 서비스 생성을 수행하는 서비스 팩토리가 필요할 거예요. 서비스 참조와 그 기본 팩토리를 만드는 방법을 배우려면 서비스 문서를 참고하세요. 원한다면 그 코드를 지금은 index 파일에 직접 배치하거나, 실제 구현 클래스 근처에 배치할 수 있어요.
이 예시에서는 추가된 환경 필드의 이름이 example이고 만들어진 참조의 이름이 exampleServiceRef라고 가정할 거예요.
packages/backend/src/index.ts
import { exampleServiceRef } from '<somewhere>'; // if the definition is elsewhereconst legacyPlugin = makeLegacyPlugin( { // ... the above core services still go here example: exampleServiceRef, }, { logger: log => loggerToWinstonLogger(log), },);
이후 백엔드는 필요할 때 당신의 것을 인스턴스화하고 레거시 플러그인 환경에 배치하는 방법을 알게 돼요.
참고
기본 구현이 없는 서비스 참조를 다루고 별도의 서비스 팩토리가 있다면, 그 팩토리를 가져와 createBackend의 services 배열 인자에 전달해야 합니다.
@backstage/backend-common 제거
@backstage/backend-common 패키지는 새 백엔드 시스템으로 이동하면서 폐기됐으며, 기존 사용을 대체해야 해요. 패키지의 모든 내보내기가 최근 몇 릴리스에서 폐기로 표시됐으며, 각 내보내기에는 특정 내보내기를 어떻게 대체하는지 설명하는 자체 폐기 메시지가 있어요.
가장 흔한 대체에 대한 폐기 메시지는 다음과 같아요:
-
createLegacyAuthAdapters- 새 백엔드 시스템과 auth 서비스를 사용하도록 마이그레이션하세요. -
errorHandler-@backstage/backend-defaults/rootHttpRouter의MiddlewareFactory.create.error를 사용하세요. -
getRootLogger- 이 함수는 향후 제거될 거예요. 새 시스템에서 루트 로거를 가져와야 한다면 이 문서를 확인하세요: https://backstage.io/docs/backend-system/core-services/logger -
getVoidLogger- 이 함수는 향후 제거될 거예요. 새 시스템에서 루트 로거를 mock해야 한다면@backstage/backend-test-utils의mockServices.logger.mock()을 대신 사용하세요. -
legacyPlugin- 새 백엔드 시스템을 완전히 사용하세요. -
loadBackendConfig- 새 백엔드 시스템으로 마이그레이션하고coreServices.rootConfig를 사용하거나, 필요하면 @backstage/config-loader#ConfigSources 기능을 사용하세요. -
loggerToWinstonLogger- 새LoggerService를 사용하도록 마이그레이션하세요. -
resolveSafeChildPath- 이 함수는 폐기됐고 향후 릴리스에서 제거될 거예요, #24493 참조.@backstage/backend-plugin-api패키지의resolveSafeChildPath함수를 사용하세요. -
ServerTokenManager- 필요에 따라 새coreServices.auth,coreServices.httpAuth,coreServices.userInfo서비스로 마이그레이션하세요. -
useHotMemoize- 백엔드에서는 더 이상 핫 모듈 리로딩을 지원하지 않아요.
모든 폐기 항목을 한 곳에서 살펴보고 싶다면 패키지의 dist/index.d.ts 파일(node_modules/@backstage/backend-common/dist/index.d.ts)이나 npmjs.com의 code 탭에서 확인할 수 있어요.
plugins 폴더 정리
사설이고 자체 소유인 플러그인의 경우 나중에 적절한 전용 마이그레이션 가이드를 따를 수 있어요.
타사 백엔드 플러그인, 특히 Backstage 유지 관리자가 유지 관리하는 더 큰 핵심 플러그인의 경우 이미 새 백엔드 시스템으로 마이그레이션됐을 수 있어요. 이 섹션은 만들 수 있는 몇 가지 구체적인 마이그레이션을 설명해요.
참고
이 각각에 대해 백엔드가 여전히 그 플러그인 패키지에 의존성(예: packages/backend/package.json)을 가져야 하고, app-config에서 제대로 구성되어야 한다는 점을 유의하세요. 그 메커니즘은 구 백엔드 시스템에서와 똑같이 작동해요.
App 플러그인
백엔드에서 프론트엔드를 제공하는 app 백엔드 플러그인은 새 형태로 쉽게 사용할 수 있어요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-app-backend'));
기본값이 "app"인 앱 패키지 이름을 재정의해야 한다면 app.packageName 구성 키로 할 수 있어요.
이 시점에서 plugins/app.ts 파일을 삭제할 수 있을 거예요.
Catalog 플러그인
catalog 플러그인의 기본 설치 형태는 다음과 같아요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-catalog-backend'));backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),);
이것은 Template kind의 사용을 가능하게 하는 catalog용 scaffolder 모듈도 설치한다는 점에 유의하세요. 템플릿을 전혀 사용하지 않는다면 그 줄을 제거할 수 있어요.
plugins/catalog.ts에 커스텀 processor나 엔터티 공급자 추가 같은 다른 사용자 지정을 했다면 계속 읽으세요. 그렇지 않으면 이 시점에서 그 파일을 삭제하면 돼요.
Amazon Web Services
AwsEksClusterProcessor와 AwsOrganizationCloudAccountProcessor는 아직 새 백엔드 시스템으로 마이그레이션되지 않았어요. 새 백엔드 시스템에서 이것들을 사용하는 방법은 Other Catalog Extensions를 참고하세요.
AwsS3DiscoveryProcessor의 경우 먼저 AwsS3EntityProvider로 마이그레이션하세요.
AwsS3EntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-aws 모듈에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-aws'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 AWS 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: awsS3: yourProviderId: # ... schedule: frequency: PT1H timeout: PT50M
Azure DevOps
AzureDevOpsDiscoveryProcessor의 경우 먼저 AzureDevOpsEntityProvider로 마이그레이션하세요.
AzureDevOpsEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-azure 모듈에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-azure'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 Azure DevOps 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: azureDevOps: yourProviderId: # ... schedule: frequency: PT1H timeout: PT50M
Open API
InternalOpenApiDocumentationProvider는 아직 새 백엔드 시스템으로 마이그레이션되지 않았어요. 새 백엔드 시스템에서 이것을 사용하는 방법은 Other Catalog Extensions를 참고하세요.
Bitbucket
BitbucketDiscoveryProcessor의 경우 BitbucketCloudEntityProvider 또는 BitbucketServerEntityProvider로 마이그레이션하세요.
BitbucketCloudEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-bitbucket-cloud 모듈에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-bitbucket-cloud'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 Bitbucket Cloud 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: bitbucketCloud: yourProviderId: # ... schedule: frequency: PT30M timeout: PT3M
BitbucketServerEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-bitbucket-server에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add( import('@backstage/plugin-catalog-backend-module-bitbucket-server'),);
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 Bitbucket Server 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: bitbucketServer: yourProviderId: # ... schedule: frequency: PT30M timeout: PT3M
Google Cloud Platform
GkeEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-gcp에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-gcp'));
app-config.yaml의 구성은 동일하게 유지돼요.
Gerrit
GerritEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-gerrit에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-gerrit'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 Gerrit 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: gerrit: yourProviderId: # ... schedule: frequency: PT30M timeout: PT3M
GitHub
GithubDiscoveryProcessor, GithubMultiOrgReaderProcessor, GithubOrgReaderProcessor의 경우 먼저 동등한 Entity Provider로 마이그레이션하세요.
GithubEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-github에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-github'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 GitHub 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: github: yourProviderId: # ... schedule: frequency: PT30M timeout: PT3M
GithubMultiOrgEntityProvider 또는 GithubOrgEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-github-org에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-github-org'));
GithubOrgEntityProvider
GithubOrgEntityProvider를 사용했다면 코드에서 다음과 같이 구성했을 수 있어요:
packages/backend/src/plugins/catalog.ts
// The org URL below needs to match a configured integrations.github entry// specified in your app-config.builder.addEntityProvider( GithubOrgEntityProvider.fromConfig(env.config, { id: 'production', orgUrl: 'https://github.com/backstage', logger: env.logger, schedule: env.scheduler.createScheduledTaskRunner({ frequency: { minutes: 60 }, timeout: { minutes: 15 }, }), }),);
이제 이는 구성으로 설정해야 해요. 위에서 정의된 옵션은 아래와 같이 app-config.yaml에서 설정돼요:
app-config.yaml
catalog: providers: githubOrg: - id: production githubUrl: 'https://github.com' orgs: ['backstage'] schedule: frequency: PT30M timeout: PT15M
GithubMultiOrgEntityProvider
GithubMultiOrgEntityProvider를 사용했다면 코드에서 다음과 같이 구성했을 수 있어요:
packages/backend/src/plugins/catalog.ts
// The GitHub URL below needs to match a configured integrations.github entry// specified in your app-config.builder.addEntityProvider( GithubMultiOrgEntityProvider.fromConfig(env.config, { id: 'production', githubUrl: 'https://github.com', // Set the following to list the GitHub orgs you wish to ingest from. You can // also omit this option to ingest all orgs accessible by your GitHub integration orgs: ['org-a', 'org-b'], logger: env.logger, schedule: env.scheduler.createScheduledTaskRunner({ frequency: { minutes: 60 }, timeout: { minutes: 15 }, }), }),);
이제 이는 구성으로 설정해야 해요. 위에서 정의된 옵션은 아래와 같이 app-config.yaml에서 설정돼요:
app-config.yaml
catalog: providers: githubOrg: - id: production githubUrl: 'https://github.com' orgs: ['org-a', 'org-b'] schedule: frequency: PT30M timeout: PT15M
transformer를 제공했다면 githubOrgEntityProviderTransformsExtensionPoint를 확장해 구성할 수 있어요:
packages/backend/src/index.ts
import { createBackendModule } from '@backstage/backend-plugin-api';import { githubOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-github-org';backend.add( createBackendModule({ pluginId: 'catalog', moduleId: 'githubOrgTransformers', register(env) { env.registerInit({ deps: { githubOrgTransformers: githubOrgEntityProviderTransformsExtensionPoint, }, async init({ githubOrgTransformers }) { githubOrgTransformers.setUserTransformer(myUserTransformer); githubOrgTransformers.setTeamTransformer(myTeamTransformer); }, }); }, }),);
Microsoft Graph
MicrosoftGraphOrgReaderProcessor의 경우 먼저 MicrosoftGraphOrgEntityProvider로 마이그레이션하세요.
MicrosoftGraphOrgEntityProvider를 새 백엔드 시스템으로 마이그레이션하려면 @backstage/plugin-catalog-backend-module-msgraph에 대한 참조를 추가하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-msgraph'));
코드에서 schedule을 제공했다면 이제 구성으로 설정해야 해요. app-config.yaml의 다른 모든 Microsoft Graph 구성은 동일하게 유지돼요.
app-config.yaml
catalog: providers: microsoftGraphOrg: provider: schedule: frequency: PT4H timeout: PT30M
transformer를 제공했다면 microsoftGraphOrgEntityProviderTransformExtensionPoint를 확장해 구성할 수 있어요:
packages/backend/src/index.ts
import { createBackendModule } from '@backstage/backend-plugin-api';import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-msgraph/alpha';backend.add( createBackendModule({ pluginId: 'catalog', moduleId: 'microsoft-graph-extensions', register(env) { env.registerInit({ deps: { microsoftGraphTransformers: microsoftGraphOrgEntityProviderTransformExtensionPoint, }, async init({ microsoftGraphTransformers }) { microsoftGraphTransformers.setUserTransformer(myUserTransformer); microsoftGraphTransformers.setGroupTransformer(myGroupTransformer); microsoftGraphTransformers.setOrganizationTransformer( myOrganizationTransformer, ); }, }); }, }),);
Other Catalog Extensions
확장 지점 메커니즘을 사용해 플러그인의 기능을 확장하거나 조정할 거예요. 그러려면 적절한 확장 지점에 의존하고 상호 작용하는 자체 제작(bespoke) 모듈을 만들어요.
packages/backend/src/index.ts
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';import { createBackendModule } from '@backstage/backend-plugin-api';const catalogModuleCustomExtensions = createBackendModule({ pluginId: 'catalog', // name of the plugin that the module is targeting moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { catalog: catalogProcessingExtensionPoint, // ... and other dependencies as needed }, async init({ catalog /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated catalog.addEntityProvider(new MyEntityProvider()); // just an example catalog.addProcessor(new MyProcessor()); // just an example }, }); },});const backend = createBackend();backend.add(import('@backstage/plugin-catalog-backend'));backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),);backend.add(catalogModuleCustomExtensions);
이것은 해당 node 패키지에 대한 의존성이 이미 없다면 그것도 필요로 해요.
# from the repository rootyarn --cwd packages/backend add @backstage/plugin-catalog-node
여기서는 시작하기 쉽도록 모듈을 백엔드 index 파일에 직접 배치했지만, 가장 잘 맞는 곳으로 옮겨도 돼요. 전체 플러그인 생태계를 새 백엔드 시스템으로 마이그레이션하면서 이런 모듈을 그것이 나타내는 구현 바로 옆에 살고 거기서 내보내지는 "일급" 사물로 점점 더 많이 만들게 될 거예요.
Events 플러그인
events 플러그인의 기본 설치 형태는 다음과 같아요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-events-backend'));
plugins/events.ts에 커스텀 subscriber 추가 같은 다른 사용자 지정을 했다면 계속 읽으세요. 그렇지 않으면 이 시점에서 그 파일을 삭제하면 돼요.
확장 지점 메커니즘을 사용해 플러그인의 기능을 확장하거나 조정할 거예요. 그러려면 적절한 확장 지점에 의존하고 상호 작용하는 자체 제작 모듈을 만들어요.
packages/backend/src/index.ts
import { eventsServiceRef } from '@backstage/plugin-events-node';import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';import { createBackendModule } from '@backstage/backend-plugin-api';const eventsModuleCustomExtensions = createBackendModule({ pluginId: 'events', // name of the plugin that the module is targeting moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { events: eventsExtensionPoint, // ... and other dependencies as needed }, async init({ events /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated events.addHttpPostIngress({ // ... }); }, }); },});const otherPluginModuleCustomExtensions = createBackendModule({ pluginId: 'other-plugin', // name of the plugin that the module is targeting moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { events: eventsServiceRef, // ... and other dependencies as needed }, async init({ events /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated }, }); },});const backend = createBackend();backend.add(import('@backstage/plugin-events-backend'));backend.add(eventsModuleCustomExtensions);backend.add(otherPluginModuleCustomExtensions);
여기서는 시작하기 쉽도록 모듈을 백엔드 index 파일에 직접 배치했지만, 가장 잘 맞는 곳으로 옮겨도 돼요. 전체 플러그인 생태계를 새 백엔드 시스템으로 마이그레이션하면서 이런 모듈을 그것이 나타내는 구현 바로 옆에 살고 거기서 내보내지는 "일급" 사물로 점점 더 많이 만들게 될 거예요.
Scaffolder 플러그인
scaffolder 플러그인의 기본 설치 형태는 다음과 같아요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-scaffolder-backend'));
새 백엔드 시스템 버전의 Scaffolder 플러그인에서는 공급자별 작업을 별도로 설치해야 해요. 예를 들어 GitHub 작업은 이제 @backstage/plugin-scaffolder-backend-module-github 패키지 아래에 모여 있어요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-scaffolder-backend'));backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
물론 그것들도 별도로 설치해야 해요.
# from the repository rootyarn --cwd packages/backend add @backstage/plugin-scaffolder-backend-module-github
사용 가능한 모듈 목록은 monorepo의 plugins 디렉터리에서 찾을 수 있어요.
plugins/scaffolder.ts에 커스텀 작업 추가 같은 다른 사용자 지정을 했다면 계속 읽으세요. 그렇지 않으면 이 시점에서 그 파일을 삭제하면 돼요.
확장 지점 메커니즘을 사용해 플러그인의 기능을 확장하거나 조정할 거예요. 그러려면 적절한 확장 지점에 의존하고 상호 작용하는 자체 제작 모듈을 만들어요.
packages/backend/src/index.ts
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';import { createBackendModule } from '@backstage/backend-plugin-api';const scaffolderModuleCustomExtensions = createBackendModule({ pluginId: 'scaffolder', // name of the plugin that the module is targeting moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { scaffolder: scaffolderActionsExtensionPoint, // ... and other dependencies as needed }, async init({ scaffolder /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated scaffolder.addActions(new MyAction()); // just an example }, }); },});const backend = createBackend();backend.add(import('@backstage/plugin-scaffolder-backend'));backend.add(scaffolderModuleCustomExtensions);
이것은 해당 node 패키지에 대한 의존성이 이미 없다면 그것도 필요로 해요.
# from the repository rootyarn --cwd packages/backend add @backstage/plugin-scaffolder-node
여기서는 시작하기 쉽도록 모듈을 백엔드 index 파일에 직접 배치했지만, 가장 잘 맞는 곳으로 옮겨도 돼요. 전체 플러그인 생태계를 새 백엔드 시스템으로 마이그레이션하면서 이런 모듈을 그것이 나타내는 구현 바로 옆에 살고 거기서 내보내지는 "일급" 사물로 점점 더 많이 만들게 될 거예요.
Auth 플러그인
Microsoft 제공자를 가진 auth 플러그인의 기본 설치 형태는 다음과 같을 거예요.
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
추가로 취해야 할 단계는 resolver를 구성에 추가하는 것인데, 예시는 다음과 같아요:
auth: environment: development providers: microsoft: development: clientId: ${AZURE_CLIENT_ID} clientSecret: ${AZURE_CLIENT_SECRET} tenantId: ${AZURE_TENANT_ID} signIn: resolvers: - resolver: emailMatchingUserEntityProfileEmail
참고
resolver는 순서대로 시도되지만, NotFoundError를 던지는 경우에만 건너뛰게 됩니다.
Auth 플러그인 모듈과 그 Resolver
위 예시에서 확인했듯이 auth-backend와 auth-backend-module을 가져와야 해요. 다음 섹션은 각각과 그 resolver를 설명해요.
아래 모든 모듈은 다음 공통 resolver를 포함해요:
-
emailMatchingUserEntityProfileEmail
-
emailLocalPartMatchingUserEntityName
Atlassian
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider'));
추가 resolver:
- usernameMatchingUserEntityName
GCP IAP (Google Identity-Aware Proxy)
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider'));
추가 resolver:
- emailMatchingUserEntityAnnotation
GitHub
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
추가 resolver:
- usernameMatchingUserEntityName
GitLab
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider'));
추가 resolver:
- usernameMatchingUserEntityName
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
추가 resolver:
- emailMatchingUserEntityAnnotation
Microsoft
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
추가 resolver:
- emailMatchingUserEntityAnnotation
oauth2
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-oauth2-provider'));
추가 resolver:
- usernameMatchingUserEntityName
oauth2 Proxy
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add( import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'),);
추가 resolver:
- forwardedUserMatchingUserEntityName
Okta
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-okta-provider'));
추가 resolver:
- emailMatchingUserEntityAnnotation
Pinniped
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));
VMware Cloud
설정:
packages/backend/src/index.ts
const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add( import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'),);
추가 resolver:
- vmwareCloudSignInResolvers
커스텀 Resolver
공통 resolver나 사용 중인 auth 모듈에 포함된 resolver가 요구에 맞지 않는 경우가 있을 수 있어요. 이 경우 커스텀 resolver를 만들어야 해요. auth 제공자 모듈에 대한 두 번째 import 대신 자체 것을 제공해요:
packages/backend/src/index.ts
export const authModuleGoogleProvider = createBackendModule({ pluginId: 'auth', moduleId: 'googleProvider', register(reg) { reg.registerInit({ deps: { providers: authProvidersExtensionPoint }, async init({ providers }) { providers.registerProvider({ providerId: 'google', factory: createOAuthProviderFactory({ authenticator: googleAuthenticator, async signInResolver(info, ctx) { // custom resolver ... }, }), }); }, }); },});const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(authModuleGoogleProvider);
레거시 제공자 사용
모든 인증 제공자가 새 백엔드 시스템을 지원하도록 리팩터링되지는 않았어요. 인증 제공자 모듈이 아직 사용 가능하지 않다면 레거시 헬퍼를 사용해 백엔드 auth 플러그인을 가져와야 해요:
packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';import { legacyPlugin } from '@backstage/backend-common';import { coreServices } from '@backstage/backend-plugin-api';const backend = createBackend();backend.add(import('@backstage/plugin-auth-backend'));backend.add(legacyPlugin('auth', import('./plugins/auth')));backend.start();
모듈 마이그레이션 노력의 진행 상황은 여기에서 추적할 수 있어요.
Search 플러그인
Search 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-search-backend'));
참고
이것은 인덱스를 메모리에 저장하는 Lunr 검색 엔진을 사용합니다.
검색 엔진
다음 섹션은 기본 lunr 엔진 외에 다른 검색 엔진을 추가하는 방법을 설명해요.
Postgres
Postgres 검색 엔진을 사용하는 Search 플러그인 설치는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-search-backend'));backend.add(import('@backstage/plugin-search-backend-module-pg'));
Elasticsearch
Elasticsearch 검색 엔진을 사용하는 Search 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-search-backend'));backend.add(import('@backstage/plugin-search-backend-module-elasticsearch'));
Search Collator
다음 섹션은 검색 collator(검색 인덱싱 프로세스의 입력 소스)를 추가하는 방법을 설명해요.
Catalog
Catalog collator가 있는 Search 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-search-backend'));backend.add(import('@backstage/plugin-search-backend-module-catalog'));
TechDocs
TechDocs collator가 있는 Search 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-search-backend'));backend.add(import('@backstage/plugin-search-backend-module-techdocs'));
Permission 플러그인
Permission 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-permission-backend'));backend.add( import('@backstage/plugin-permission-backend-module-allow-all-policy'),);
참고
위 예시는 기본 allow-all 정책을 포함합니다. 원하는 것이 아니라면 두 번째 줄을 추가하지 말고 아래 옵션 중 하나를 살펴보세요.
커스텀 Permission Policy
자체 permission policy를 추가하려면 다음을 수행해야 해요:
import { createBackendModule } from '@backstage/backend-plugin-api';import { PolicyDecision, AuthorizeResult,} from '@backstage/plugin-permission-common';import { PermissionPolicy, PolicyQuery, PolicyQueryUser,} from '@backstage/plugin-permission-node';import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha';class CustomPermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, user?: PolicyQueryUser, ): Promise<PolicyDecision> { // TODO: Add code here that inspects the incoming request and user, and returns AuthorizeResult.ALLOW, AuthorizeResult.DENY, or AuthorizeResult.CONDITIONAL as needed. See the docs at https://backstage.io/docs/permissions/writing-a-policy for more information return { result: AuthorizeResult.ALLOW, }; }}const customPermissionBackendModule = createBackendModule({ pluginId: 'permission', moduleId: 'custom-policy', register(reg) { reg.registerInit({ deps: { policy: policyExtensionPoint }, async init({ policy }) { policy.setPolicy(new CustomPermissionPolicy()); }, }); },});const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-permission-backend'));backend.add(customPermissionBackendModule);
TechDocs 플러그인
TechDocs 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-techdocs-backend'));
Kubernetes 플러그인
Kubernetes 플러그인의 기본 설치 형태는 다음과 같을 거예요:
packages/backend/src/index.ts
const backend = createBackend();// Other plugins...backend.add(import('@backstage/plugin-kubernetes-backend'));