아키텍처 개요
Backstage는 세 가지 주요 구성 요소로 구성되어 있으며, 각각 Backstage와 서로 다르게 상호작용하는 서로 다른 기여자 그룹을 위한 것이에요.
출처: 문서
본문
용어
Backstage는 세 가지 주요 구성 요소로 구성되어 있으며, 각각 Backstage와 서로 다르게 상호작용하는 서로 다른 기여자 그룹을 위한 것이에요.
- Core - 오픈소스 프로젝트 내의 코어 개발자가 개발한 기본 기능을 포함해요.
- App - 사용자 지정되고 유지 관리되는 Backstage 애플리케이션의 배포 인스턴스를 나타내며, 보통 조직 내 생산성 팀인 앱 개발자가 유지해요. 코어 기능에 추가 플러그인을 통합해요.
- Plugins - Backstage 앱의 유용성을 높이기 위한 추가 기능을 제공해요. 플러그인은 회사 전용이거나 오픈소스화되어 재사용 가능할 수 있어요.
개요
다음 다이어그램은 Backstage의 전체 아키텍처를 높은 수준으로 보여 줘요. 실제 환경에서 이 아키텍처를 실행하려면 보통 구성 요소를 컨테이너화해야 해요. 이를 위해 다양한 명령이 제공돼요.
이 아키텍처에는 3가지 주요 구성 요소가 있어요.
- 프론트엔드는 핵심 Backstage UI를 포함하며, 통합된 코어 기능 플러그인과 사용자가 추가한 다른 플러그인의 정보를 사용자에게 직접 보여 주는 확장이에요.
- 백엔드는 백엔드 플러그인, 코어 서비스, 기타 서비스를 포함해요. 이것들이 연결되도록 배선하는 Backstage의 서버 측 부분이에요. 규모 확장과 개별 기능 격리 필요에 따라 백엔드를 여러 개, 백엔드 컨테이너를 여러 개 배포할 수 있어요.
- 데이터베이스는 Backstage 데이터를 호스팅해요.
프론트엔드 구성 요소
아키텍처 다이어그램은 다양한 구성 요소와 각 구성 요소가 상호작용하는 다른 구성 요소를 개괄적으로 보여 줘요.
App
Backstage 프론트엔드 애플리케이션의 루트로 만들고 사용하는 앱 인스턴스 자체예요. 그 자체로는 직접적인 기능이 없고, 단순히 여러 것을 연결해 주는 역할을 해요.
확장 (Extensions)
확장은 애플리케이션의 시각적·비시각적 구조를 모두 구축하는 구성 요소예요. 앱 자체가 제공하는 내장 확장도 있고, 플러그인이 제공하는 확장도 있어요. 각 확장은 데이터를 공유하는 부모에 연결되며, 자신만의 자식을 얼마든지 가질 수 있어요. 모든 확장을 앱 확장 트리(app extension tree)라는 단일 트리로 연결하는 것은 앱의 몫이에요. 이 구조로부터 전체 앱이 인스턴스화되어 렌더링될 수 있어요.
사용자 인터페이스
UI는 프론트엔드의 확장 중 하나예요. 플러그인 집합을 감싸는 얇은 클라이언트 측 래퍼예요. 구성 관리 같은 공유 활동을 위한 핵심 UI 구성 요소와 라이브러리를 제공해요. [라이브 데모]
각 플러그인은 보통 전용 URL에서 UI에 자신을 노출해요. 예를 들어 Service Catalog 플러그인은 /catalog에서 UI에 등록돼요.
프론트엔드 플러그인
플러그인은 앱 안에서 실제 기능을 제공해요. 플러그인의 크기는 작은 구성 요소부터 다른 플러그인을 구성하고 통합할 수 있는 완전히 새로운 시스템까지 다양해요. 플러그인은 완전히 독립적일 수도 있고, 서로 위에 구축되어 기존 플러그인을 확장하고 기능을 보강할 수도 있어요. 플러그인은 확장을 구성하거나 Utility API와 라우트를 공유하여 서로 통신할 수 있어요.
Backstage에는 다음과 같은 핵심 플러그인 집합이 포함돼요.
- Software Catalog - 서비스, 웹사이트, 라이브러리, ML 모델, 데이터 파이프라인 등 모든 소프트웨어의 메타데이터를 담는 중앙화된 시스템이에요. 소프트웨어 운영에 필요한 물리적·가상 인프라의 메타데이터도 담을 수 있어요. 소프트웨어 카탈로그는 UI를 통해 보고 검색할 수 있어요.
- Software Templates - Backstage 안에서 구성 요소를 만드는 데 도움을 주는 도구예요. 템플릿은 코드 스켈레톤을 로드하고 변수를 포함한 다음 GitHub 같은 위치에 템플릿을 게시할 수 있어요.
- TechDocs - Backstage에 내장된 docs-like-code 솔루션이에요. 문서는 코드와 함께 있는 Markdown 파일로 작성돼요.
- Kubernetes - 개발자가 로컬 호스트든 프로덕션이든 서비스의 상태를 확인할 수 있게 해 주는 도구예요.
- Search - Backstage 생태계에서 정보를 검색해요. 각 검색 결과의 모양과 느낌을 커스터마이즈하고 자체 검색 엔진을 사용할 수 있어요.
플러그인 아키텍처에서 플러그인 자체의 아키텍처에 대한 더 자세한 내용을 확인할 수 있어요.
확장 오버라이드 (Extension Overrides)
내장 확장과 플러그인이 제공하는 확장 외에도 확장 오버라이드를 설치할 수 있어요. 이는 기존 확장을 대체할 수 있는 높은 우선순위의 확장 모음이에요. 예를 들어 플러그인이 제공하는 개별 확장을 오버라이드하거나, 새로운 앱 테마 같은 완전히 새로운 확장을 설치하는 데 사용할 수 있어요.
Utility API
Utility API는 플러그인을 더 쉽게 만들 수 있게 해 주고, 플러그인이 다른 플러그인과 기능을 공유할 수 있게 해 주며, 통합자가 앱 동작을 변경할 수 있는 커스터마이즈 포인트 역할도 해요. 각 Utility API는 TypeScript 인터페이스와 구현에 접근하는 데 사용하는 참조에 의해 정의돼요. Utility API의 구현은 제공되는 확장에 의해 정의되며 다른 확장과 마찬가지로 오버라이드될 수 있어요.
라우트 (Routes)
Backstage 라우팅 시스템은 추상화 계층을 추가해 플러그인이 확장이 렌더링되는 URL 경로를 구체적으로 알지 못하거나 심지어 존재하는지조차 몰라도 서로의 확장으로 라우팅할 수 있게 해줘요. 플러그인이 서로 라우트를 공유하고 런타임에 구체적인 링크를 동적으로 생성할 수 있게 해줘요. 이런 링크를 실제 URL로 해석하는 것은 앱의 책임이지만, 통합자가 링크를 어떻게 해석할지 결정하는 자체 라우트 바인딩을 정의할 수도 있어요. 라우팅 시스템은 플러그인이 내부 라우트를 정의해 같은 플러그인의 다른 콘텐츠로 연결하는 것도 돕아요.
백엔드 구성 요소
아키텍처 다이어그램은 다양한 구성 요소와 각 구성 요소가 상호작용하는 다른 구성 요소를 개괄적으로 보여 줘요.
백엔드
배포 단위로 생각할 수 있는 백엔드 인스턴스 자체예요. 그 자체로는 기능이 없고, 단순히 여러 것을 연결해 주는 역할을 해요.
얼마나 많은 백엔드를 배포할지는 여러분이 결정해요. 모든 기능을 하나에 둘 수도 있고, 규모 확장과 개별 기능 격리 필요에 따라 여러 개의 더 작은 배포로 나눌 수도 있어요.
백엔드 플러그인
플러그인은 실제 기능을 제공해요. 플러그인은 서로 완전히 독립적으로 동작해요. 플러그인이 서로 통신하려면 네트워크를 통해 해야 해요. 플러그인 사이에 코드를 통한 직접 통신은 있을 수 없어요. 이런 제약 때문에 각 플러그인은 자체 마이크로서비스로 간주될 수 있어요.
플러그인 아키텍처에서 플러그인 자체의 아키텍처에 대한 더 자세한 내용을 확인할 수 있어요.
서비스 (Services)
서비스는 플러그인을 더 간단히 구현할 수 있도록 유틸리티를 제공해, 각 플러그인이 모든 것을 처음부터 구현할 필요가 없게 해줘요. 로깅, 데이터베이스 접근, 구성 읽기를 위한 것 같은 많은 내장 코어 서비스가 있지만, 서드파티 서비스를 가져오거나 직접 만들 수도 있어요.
서비스는 개별 백엔드 설치를 위한 커스터마이즈 포인트이기도 해요. 자체 구현으로 서비스를 오버라이드하고, 기존 서비스에 더 작은 커스터마이즈를 할 수도 있어요.
확장 포인트 (Extension Points)
많은 플러그인에는 이를 확장할 수 있는 방법이 있어요. 예를 들어 Catalog의 엔티티 제공자나 Scaffolder의 사용자 지정 액션이요. 이런 확장 패턴은 이제 확장 포인트(Extension Points)로 인코딩돼요.
확장 포인트는 서비스와 조금 비슷한데, 서비스를 의존하듯 의존하기 때문이에요. 핵심 차이는 확장 포인트가 플러그인이나 모듈 자체가 각자 노출하고 싶은 커스터마이즈에 기반해 등록·제공한다는 점이에요.
확장 포인트는 플러그인이나 모듈 인스턴스 자체와 별도로 내보내지며, 여러 다른 확장 포인트를 동시에 노출할 수 있어요. 이렇게 하면 하나의 거대한 API 표면을 다루는 대신 개별 확장 포인트를 시간에 따라 진화시키고 deprecated 처리하기가 더 쉬워져요.
모듈 (Modules)
모듈은 확장 포인트를 사용해 다른 플러그인이나 모듈에 새 기능을 추가해요. 예를 들어 개별 Catalog 엔티티 제공자나 하나 이상의 Scaffolder 액션을 추가할 수 있어요.
각 모듈은 단일 플러그인에 속한 확장 포인트만 사용할 수 있으며, 모듈은 그 플러그인과 같은 백엔드 인스턴스에 함께 배포되어야 해요. 모듈은 등록된 확장 포인트를 통해서만 자신의 플러그인이나 다른 모듈과 통신할 수 있어요.
플러그인과 마찬가지로 모듈도 서비스에 접근할 수 있고 자체 서비스 구현에 의존할 수 있어요. 그러나 확장하는 플러그인과 서비스를 공유할 거예요 — 모듈 전용 서비스 구현은 없어요.
데이터베이스
데이터베이스는 Backstage 데이터를 호스팅해요. Backstage 백엔드와 내장 플러그인은 Knex 라이브러리를 기반으로 하며, 플러그인별로 별도의 논리적 데이터베이스를 구성해요. 이는 훌륭한 격리를 제공하며 각자 별도로 마이그레이션하고 진화할 수 있게 해줘요.
Knex 라이브러리는 다양한 데이터베이스를 지원하지만, 작성 시점 기준으로 Backstage는 주로 다음 두 가지에 대해 테스트돼요.
- SQLite - 주로 인메모리 목/테스트 데이터베이스로 사용돼요.
- PostgreSQL - 선호되는 프로덕션 데이터베이스예요.
MySQL 변종 같은 다른 데이터베이스도 동작한다고 보고되지만 아직 완전히 테스트되지는 않았어요.
Backstage 인스턴스용 PostgreSQL을 설정하는 지침은 Database에서 찾을 수 있어요. 플러그인용 데이터베이스를 구성하는 방법은 Configuring Plugin Databases에서 확인할 수 있어요.
플러그인 아키텍처
아키텍처상 플러그인은 세 가지 형태를 가질 수 있어요.
- 독립형 (Standalone)
- 서비스 백엔드 (Service backend)
- 서드파티 백엔드 (Third-party backend)
독립형 플러그인
독립형 플러그인은 완전히 브라우저에서 실행돼요. 예를 들어 Tech Radar 플러그인은 하드코딩된 정보를 단순히 렌더링해요. 다른 서비스에 API 요청을 하지 않아요.
Backstage 앱에 설치된 Tech Radar의 아키텍처는 매우 간단해요. 다음 다이어그램에서 보듯 Tech Radar를 앱에 프론트엔드 플러그인으로 추가하기만 하면 돼요.
참고:
다음 다이어그램은 지정된 플러그인 추가와 관련된 변경 사항을 강조하기 위해 프론트엔드와 백엔드 컨테이너의 상세 내용을 보여 주지 않아요.
플러그인이 추가되면 Backstage UI에서 Tech Radar 정보를 볼 수 있어요.
서비스 백엔드 플러그인
서비스 백엔드 플러그인은 Backstage를 운영하는 조직의 범위 안에 있는 서비스에 API 요청을 해요.
예를 들어 Lighthouse 플러그인은 lighthouse-audit-service에 요청해요. lighthouse-audit-service는 Google Lighthouse 라이브러리 사본을 실행하고 결과를 PostgreSQL 데이터베이스에 저장하는 마이크로서비스예요.
Lighthouse 플러그인은 프론트엔드에 추가돼요. lighthouse-audit-service 컨테이너는 이미 Docker Hub에 공개되어 있으며 다음으로 다운로드해 실행할 수 있어요.
docker run spotify/lighthouse-audit-service:latest
참고:
다음 다이어그램은 지정된 플러그인 추가와 관련된 변경 사항을 강조하기 위해 프론트엔드와 백엔드의 상세 내용을 보여 주지 않아요.
Backstage의 소프트웨어 카탈로그는 서비스 백엔드 플러그인의 또 다른 예예요. Backstage Backend 서비스에서 서비스("엔티티") 목록을 가져와 사용자에게 테이블로 렌더링해요.
서드파티 백엔드 플러그인
서드파티 백엔드 플러그인은 서비스 백엔드 플러그인과 비슷해요. 주요 차이는 플러그인을 뒷받침하는 서비스가 Backstage를 호스팅하는 회사의 생태계 밖에 호스팅된다는 점이에요.
CircleCI 플러그인은 서드파티 백엔드 플러그인의 예예요. CircleCI는 Backstage에 대한 지식 없이도 사용할 수 있는 SaaS 서비스예요. Backstage 플러그인이 콘텐츠를 표시하기 위해 소비하는 API를 보유해요.
사용자 브라우저에서 CircleCI로 가는 요청은 Backstage가 제공하는 프록시 서비스를 통해 전달돼요. 이게 없으면 https://example.com에서 서빙되는 브라우저 페이지가 https://circleci.com에서 호스팅되는 리소스를 서빙하지 못하게 막는 Cross Origin Resource Sharing 정책에 의해 요청이 차단돼요.
참고:
다음 다이어그램은 지정된 플러그인 추가와 관련된 변경 사항을 강조하기 위해 프론트엔드와 백엔드의 상세 내용을 보여 주지 않아요.
패키지 아키텍처
Backstage는 NPM 패키지에 크게 의존해요. 라이브러리 배포와 프로젝트 내 코드 구조화 모두에 사용돼요. Backstage 프로젝트를 구성하는 방식은 여러분의 몫이지만, 따르기를 권장하는 일련의 확립된 패턴이 있어요. 이런 패턴은 건전한 프로젝트 구조를 세우는 데 도움이 되고 서로 다른 Backstage 프로젝트 간에 익숙함을 제공해요.
다음 다이어그램은 Backstage의 패키지 아키텍처를 개략적으로 보여 줘요. 개별 플러그인과 그것이 가질 수 있는 모든 패키지의 관점을 취하며, 두꺼운 테두리와 이탤릭 텍스트로 표시돼요. 플러그인을 둘러싼 것은 플러그인의 서로 다른 가능한 인터페이스 포인트인 서로 다른 패키지 그룹이에요. 간결함을 위해 일부 패키지가 생략되어 모든 라이브러리 패키지 목록이 완전하지 않다는 점에 주의하세요.
개요
위 다이어그램의 화살표는 대상 패키지 코드에 대한 런타임 의존성을 나타내요. 이 엄격한 의존성 그래프는 런타임 dependencies에만 적용되며, 테스트 목적으로 이 표의 규칙을 어길 수 있는 devDependencies가 있을 수 있어요. 프론트엔드, 백엔드, isomorphic 패키지 모음에 대한 의존성을 보여 주는 일부 화살표가 있지만, 그것들도 왼쪽 아래에 보이는 중요한 호환성 규칙을 따라야 해요.
app과 backend 패키지는 Backstage 프로젝트의 진입점이에요. app 패키지는 프론트엔드 플러그인 모음을 모아 조직에 맞게 커스터마이즈하는 프론트엔드 애플리케이션이고, backend 패키지는 Backstage 애플리케이션을 구동하는 백엔드 서비스예요. 각 패키지는 프로젝트 안에 여러 인스턴스가 있을 수 있다는 점을 주목할 만해요. 특히 backend 패키지는 각자 더 작은 플러그인 모음으로 각자의 목적에 봉사하는 더 작은 배포 단위로 분할하는 것이 유리할 수 있어요.
플러그인 패키지
일반적인 플러그인은 최대 5개 패키지로 구성돼요. 프론트엔드 2개, 백엔드 2개, isomorphic 1개예요. 플러그인 내 모든 패키지는 공통 접두사를 공유해야 하며, 보통 @<scope>/plugin-<plugin-id> 형식이지만 backstage-plugin-<plugin-id>이나 @<scope>/backstage-plugin-<plugin-id> 같은 대안도 유효해요. 이 접두사와 함께 각 패키지는 역할을 나타내는 고유한 접미사를 가져요. 이 5개 플러그인 패키지 외에도 플러그인은 선택 기능을 활성화하기 위해 설치할 수 있는 추가 프론트엔드·백엔드 모듈을 가질 수 있어요. 접미사와 역할의 전체 목록은 Plugin Package Structure ADR을 참고하세요.
-react, -common, -node 플러그인 패키지는 함께 플러그인의 외부 라이브러리를 구성해요. 플러그인 라이브러리는 다른 플러그인이 플러그인 위에 구축하고 확장할 수 있게 하며, 마찬가지로 플러그인도 다른 플러그인을 의존하고 확장할 수 있게 해줘요. 이 때문에 플러그인 라이브러리 패키지는 플러그인 라이브러리 패키지가 자기 자신의 중복 설치를 허용하는 것이 좋은데, 결국 다양한 플러그인의 의존성으로 설치되는 버전이 섞일 수 있기 때문이에요. 또한 플러그인이 다른 플러그인의 non-라이브러리 패키지를 직접 import하는 것은 금지되며, 플러그인 간의 모든 통신은 라이브러리와 애플리케이션 자체를 통해 처리되어야 해요.
프론트엔드 패키지
프론트엔드 패키지는 두 가지 주요 그룹으로 묶여요. 첫 번째는 "Frontend App Core"로, app 패키지 자체만이 사용하는 패키지 집합이에요. 이 패키지들은 앱의 코어 구조를 만드는 데 도움이 되고 플러그인 라이브러리가 의존할 기반을 제공해요.
두 번째 그룹은 나머지 공유 패키지로, "Frontend Plugin Core"와 "Frontend Libraries"로 더 나뉘어요. 코어 패키지는 특히 안정적이라고 간주되며 프론트엔드 프레임워크의 핵심을 형성해요. 가장 중요한 역할은 각 플러그인 주변의 경계를 형성하고 플러그인 모음을 실행 중인 애플리케이션으로 결합하는 데 도움이 되는 도구 집합을 제공하는 것이에요. 나머지 프론트엔드 패키지는 플러그인을 만드는 구성 요소 역할을 하는 더 전통적인 라이브러리예요.
백엔드 패키지
백엔드 라이브러리 패키지는 현재 프론트엔드 패키지와 비슷한 플러그인 아키텍처를 공유하지 않아요. 대신 백엔드 서비스를 만드는 데 도움이 되는 구성 요소와 패턴 모음일 뿐이에요. 그러나 이는 미래에 바뀔 가능성이 커요.
Common 패키지
Common 패키지는 사실상 다른 모든 페이지가 의존하는 패키지예요. 훨씬 더 작은 패키지 집합이지만 매우 널리 퍼져 있어요. Common 패키지는 isomorphic이고 프론트엔드와 백엔드 모두에서 실행되어야 하므로, 어떤 프론트엔드나 백엔드 패키지에도 절대 의존할 수 없어요.
Backstage CLI는 그 자체 범주에 속하며 사실상 다른 모든 패키지가 의존해요. 그러나 그 자체로는 라이브러리가 아니며, 항상 개발 의존성(devDependency)으로만 사용되어야 해요.
코드를 어디에 둘지 결정하기
플러그인 코드를 어디에 둘지 결정하기 어려울 때가 있어요. 예를 들어 -backend 플러그인 패키지에 직접 두어야 할지 -node 패키지에 두어야 할지요. 일반적인 지침으로 코드의 노출을 가능한 낮게 유지하려고 해야 해요. 공개 API가 될 필요가 없다면 피하는 것이 좋아요. 다른 플러그인이 사용할 필요가 없다면 플러그인 패키지에 직접 두세요.
아래는 코드를 어디에 둘지 결정하는 데 도움이 되는 차트예요.
캐시
Backstage 백엔드와 내장 플러그인은 성능이나 신뢰성을 개선하기 위한 수단으로 캐시 저장소를 활용할 수도 있어요. 데이터베이스가 지원되는 방식과 비슷하게, 플러그인은 논리적으로 분리된 캐시 연결을 받으며 내부적으로는 Keyv가 구동해요.
작성 시점 기준으로 Backstage는 다섯 가지 캐시 저장소 중 하나를 사용하도록 구성할 수 있어요.
memorymemcacheredisvalkeyinfinispan
memory는 주로 로컬 개발에 사용되며, 프로덕션 배포에서는 나머지 캐시 저장소 중 하나를 사용하는 것을 권장해요. Backstage 인스턴스에 적합한 캐시 저장소는 자체 런타임 제약 조건과 실행 중인 플러그인에 요구되는 것에 따라 달라져요.
메모리를 캐시로 사용
backend: cache: store: memory
memcache를 캐시로 사용
backend: cache: store: memcache connection: user:[email protected]:11211
Redis를 캐시로 사용
backend: cache: store: redis connection: redis://user:***@cache.example.com:6379
Infinispan을 캐시로 사용
최소 구성
- 기본값,
authentication없음,cache라는 캐시와127.0.0.1:11222호스트 가정.
backend: cache: store: infinispan
확장 구성
- Redis와 달리 Infinispan은 캐시를 자동으로 만들어 주지 않아요. 여기서 구성하기 전에 infinispan 서버에서 캐시를 구성해 두는 것이 기대돼요.
- 사용 가능한 전체 구성 항목 목록: https://docs.jboss.org/infinispan/hotrod-clients/javascript/1.0/apidocs/module-infinispan.html 백업 클러스터 지원을 포함해요.
backend: cache: store: infinispan infinispan: servers: - host: 127.0.0.1 port: 11222 cacheName: backstage-cache mediaType: application/json authentication: enabled: true userName: yourusername password: yourpassword saslMechanism: PLAIN
다른 캐시 저장소를 지원하는 기여를 환영해요!