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

카탈로그 FAQ

원문 보기 위키 갱신

이 페이지는 카탈로그에 대해 자주 묻는 질문들에 답합니다.

출처: 문서

본문

이 페이지는 카탈로그에 대해 자주 묻는 질문들에 답합니다.

카탈로그에 사용자와 그룹을 두는 게 정말 그렇게 중요할까요?

네. 카탈로그에서 가장 중요한 개념 중 하나는 조직 구조와 소유권(ownership)을 제대로 드러내서, 사용자가 자신의 시스템을 효과적으로 이해하고 소통할 수 있게 해 주는 것입니다. 사용자와 그룹에 대한 카탈로그 항목이 있으면 최종 사용자가 Backstage를 탐색하면서 그 소유자를 클릭해 404 Not Found 페이지 대신 그에 대한 풍부한 정보 페이지를 볼 수 있게 됩니다.

사용자가 로그인하면 그때그때 카탈로그에 사용자를 만들 수 있을까요?

새 Backstage 인스턴스를 구축할 때, 채택자들은 카탈로그가 로그인과 상호작용하는 경향이 있다는 점을 깨닫게 됩니다. 그래서 사용자가 로그인할 때마다 그때그때 카탈로그에 사용자가 나타나게 할 수 있는지 묻는 질문이 자주 나옵니다.

이것은 정말 피해야 합니다. 일반적인 권장 사항은 조직 데이터의 권위 있는 원천(LDAP, Azure, 맞춤형 HR 시스템 등)과 사전에 제대로 된 통합을 설정하고, 로그인 여부와 관계없이 모든 사용자와 그룹을 그곳에서 카탈로그로 일괄 수집하라는 것입니다. 이렇게 하면 복잡성과 좌절감을 최소화하면서 사용자에게 훨씬 나은 경험을 제공하는 경향이 있습니다.

배경을 설명하자면, 기술적으로 로그인에는 현재 사용자가 누구인지 확립하는 흐름을 지원하는 auth 백엔드만 필요합니다. 그 과정이 끝나면, 소위 sign-in resolver가 제3자가 확립한 신원(예: AD 항목에 대해 반환된 속성)을 Backstage 신원으로 변환하는 일을 맡습니다. 카탈로그에 같은 제3자의 사용자와 그룹이 채워져 있으면 신원이 자연스럽게 일치하고, 그에 제공되는 기본 sign-in resolver를 쓸 수 있기 때문에 이 중요한 단계가 훨씬 단순해집니다. 참고로, 원한다면 카탈로그와 전혀 상호작용하지 않는 나만의 resolver를 작성할 수도 있지만, 이 고급 옵션을 선택하지는 않는다고 가정하겠습니다.

온디맨드로 사용자를 만드는 것은 커스텀 엔티티 제공자를 작성하면 기술적으로 가능합니다. 하지만 기술적인 측면과 최종 사용자 삶의 질 측면 모두에서 상당한 문제가 따릅니다.

기술적 측면에서 이것은 원치 않는 복잡성입니다. 기본 제공되는 제공자로 쉽게 설정할 수 있는 일괄 수집 스케줄 대신, 커스텀 제공자를 구현하고 유지해야 합니다. 또한 그렇게 하더라도 카탈로그는 결과적 일관성(eventually consistent) 엔진입니다. 제공자가 시스템에 넣은 사용자가 즉시 나타난다는 보장이 없습니다. 부트스트래핑 시점에 경험이 부분적으로만 동작할 가능성이 높으며, 이는 원치 않는 부작용을 일으킬 수 있습니다.

사용자 경험 측면에서, 완전한 조직 데이터 없이 쓰는 Backstage 경험은 도구의 힘을 온전히 발휘하지 못하게 만드는 심각한 제약입니다. 사용자는 소유자를 클릭해 그들이 누구이고 어느 팀에 속하는지 볼 수 없게 됩니다. 문제가 생기거나 기능을 요청할 때 여러분이나 관리자에게 연락해야 하는 의사소통 경로를 알아낼 수 없게 됩니다. 어떤 팀이 무엇을 소유하고 서로 어떻게 관련되는지 개요를 얻을 수 없게 됩니다. 훨씬 황폐한 경험이 될 것입니다. 조직 데이터는 중앙에서 완전하고 정확하게 제공되는 것이 매우 가치 있습니다.

프로세서/제공자 내부에서 카탈로그 자체를 호출할 수 있을까요?

@backstage/plugin-catalog-node의 catalogServiceRef를 통해 카탈로그 클라이언트를 얻는 것이 가능하긴 하지만, 거의 항상 옳은 방법은 아니며 강력히 권장하지 않습니다.

카탈로그 처리 루프는 전체 카탈로그 클러스터가 협력해 가능한 한 높은 속도로 모든 엔티티를 훑어내는 초고속 시스템입니다. 이상적인 프로세서는 극히 최소한의 작업만 하고 즉시 제어권을 돌려줍니다. 프로세서에서 외부 시스템(카탈로그 포함)에 비동기 요청을 수행하면, 그 외부 시스템이 매우 높은 빈도의 소규모 요청을 처리할 준비가 되어 있지 않다면 곧 압도되어 자원이 고갈될 수 있습니다. 각 단계가 응답을 기다려야 하면 처리 루프도 크게 느려집니다. 이는 카탈로그에 작업이 "쌓여" 엔티티가 갱신되는 것이 지연되는 결과를 낳을 수 있습니다. The Life of an Entity 문서는 엔티티가 원래 수집부터 처리를 거쳐 최종 엔티티가 되기까지 일어나는 이벤트의 흐름을 보여줍니다.

관련 검증 주제도 참조하세요.

프로세서에서 관계(relation)를 검증할 수 있을까요?

프로세서는 엔티티 본문에서 관계를 생성하는 역할을 담당합니다 — 자세한 내용은 The Life of an Entity 문서를 참조하세요. 존재하지 않는 다른 엔티티에 대한 관계를 가진 엔티티를 유효하지 않은 것으로 표시하는 규칙을 프로세서에 넣고 싶은 유혹이 있습니다. 예를 들어 해산된 팀을 spec.owner로 선언하는 Component 엔티티가 그렇죠. 우리는 두 가지 이유로 프로세서에서 이런 종류의 "엄격한(hard)" 검증을 하는 것을 강력히 권장하지 않습니다.

첫째, 성능입니다. 여기서 설명했듯이, 대상 엔티티가 존재하는지 확인하는 것을 포함해 어떤 이유로든 프로세서에서 카탈로그를 호출하는 것은 피해야 합니다. 성능 문제 외에도, 엔티티 사이의 숨은 의존성이 정착하지 못하게 만들거나 디버깅하기 어려운 이유로 상태 사이를 앞뒤로 깜빡이게 하는 데이터 레이스로 이어질 수 있습니다.

둘째, 사용자 경험입니다. 카탈로그는 외부 현실을 끊임없이 반영하려고 하는 결과적 일관성 시스템입니다. 사용자가 catalog-info 파일을 바꾸거나 외부 시스템에서 무언가가 갱신되면, 그 변경이 스트리밍되어 시간이 지나 카탈로그 안에 정착합니다. 하지만 프로세서에서 오류를 던지면 그 엔티티의 처리가 즉시 중단되고 수집이 멈춥니다. 대규모 조직에서 이런 변경이 하루에 수백 번 일어난다고 상상해 보세요. catalog-info 파일의 소유자들은 자신의 파일이 수집 중 "깨졌다"는 소식에 끊임없이 놀라게 될 것입니다. 심지어 처음 만들어진 지 아주 오래 지난 후에 말이죠 — 만들 당시에는 유효했고 그 뒤로 건드린 적이 없는데도요! 이는 통제할 수 없는 이유로 조용히 깨지기 때문에 매우 답답하고 사용자까지 느려지게 만듭니다.

프로세서에서 엄격한 검증 오류를 던져도 괜찮은 경우도 있습니다. 특히 스키마 테스트를 통과하지 못해, 그 데이터를 통과시킨다면 카탈로그 데이터의 소비자가 깨질 때가 그렇습니다. 소유자(owner)를 문자열 대신 숫자로 설정하는 것이 그런 예가 될 수 있습니다.

엔티티를 검증할 때 오류를 던질 수 있을까요?

짧게 말하면: 때때로. 형태가 너무 잘못되어 파싱조차 되지 않거나 TypeScript와 같은 계약을 위반하는 경우에만 그렇습니다.

"소프트(soft)" 오류 — 특히 기존 대상과 일치하지 않는 관계(위 참조) — 때문에 오류를 던지지 마세요. 소프트 오류의 경우에는 그대로 카탈로그에 통과시키고, 검사를 외부에서 구현해 사람들이 자신의 메타데이터를 고치도록 부드럽게 유도하는 것을 권장합니다. 엔티티 페이지 상단의 동적 정보 표시줄처럼, 소유자가 페이지를 방문할 때 특정 관계가 잘못된 것 같고 고쳐야 한다고 알려주는 방식이 아주 효과적일 수 있습니다.

크게 보면 이는 사용자 경험의 문제입니다. 카탈로그는 외부 현실을 끊임없이 반영하려고 하는 결과적 일관성 시스템입니다. 사용자가 catalog-info 파일을 바꾸거나 외부 시스템에서 무언가가 갱신되면, 그 변경이 스트리밍되어 시간이 지나 카탈로그 안에 정착합니다. 하지만 프로세서에서 오류를 던지면 그 엔티티의 처리가 즉시 중단되고 수집이 멈춥니다. 대규모 조직에서 이런 변경이 하루에 수백 번 일어난다고 상상해 보세요. catalog-info 파일의 소유자들은 자신의 파일이 수집 중 "깨졌다"는 소식에 끊임없이 놀라게 될 것입니다. 심지어 처음 만들어진 지 아주 오래 지난 후에 말이죠 — 만들 당시에는 유효했고 그 뒤로 건드린 적이 없는데도요! 이는 통제할 수 없는 이유로 조용히 깨지기 때문에 매우 답답하고 사용자까지 느려지게 만듭니다.

"엄격한" 오류 — 예를 들어 metadata.annotations 값이 문자열 대신 배열인 경우처럼 엔티티 형태의 기본 기대치가 깨진 경우에는 오류를 던질 수 있습니다. 그것은 TypeScript 계약과 맞지 않으며, 그런 엔티티를 카탈로그에 받아들이면 엔티티를 읽는 쪽에서 그 값에 문자열 연산을 수행하려다 폭발할 가능성이 높습니다.

카탈로그에서 (API, 서비스 등의) 버전을 표현할 수 있을까요?

카탈로그에서 세밀한 버전을 표현하려고 시도하는 것은 권장하지 않습니다. 카탈로그에는 (의도적으로) 그런 내장 기능이 없으며, 그래도 하려고 하는 기존 대안들은 어색하고 상당한 단점이 있습니다. 주 버전의 파괴적인 변경은 별도의 엔티티로 표현할 수 있을 때도 있습니다(아래에서 더 설명합니다).

이 답변이 놀랍게 보일 수 있지만, 그 뒤에는 분명한 의도가 있습니다. 카탈로그 엔티티는 일반적으로 어떤 사물의 정확한 기술적 구현이 아니라 "인간 개념"을 나타냅니다. 카탈로그 항목의 이름과 세분성은 다른 사람과 이야기할 때 그 사물을 부르고 말하는 방식과 자주 일치합니다. 그런 다음 그 상위 개념에 플러그인을 붙여, 사용자가 필요로 하는 그 사물의 더 세밀한 세부 사항을 보여주게 합니다.

카탈로그는 자주 바뀌지 않고 사람이 선별한 데이터를 담아야 하며, 그 엔티티의 소유자들이 쉽게 확인하고 관리할 수 있어야 합니다.

한 가지 예로 백엔드 서비스가 있습니다. 빠르게 움직이는 세계에서 한 서비스의 여러 버전이 여러 환경에 동시에 배포될 수 있고, 그것들은 빠르게 변할 수 있습니다. 그럼에도 동료와 그 서비스에 대해 이야기할 때는 예를 들어 "스캐폴더"라고 부를 가능성이 높습니다. 그래서 kind: Component, name: scaffolder, type: service 같은 형태로 카탈로그에 넣습니다. 하지만 프론트엔드에서는 여전히 CI/CD 시스템, 로그 수집기 등을 직접 조회해 그 서비스와 관련해 인프라에서 정확히 무슨 일이 일어나고 있는지 정밀하고 실시간인 정보를 보여주는 풍부한 플러그인을 가질 수 있습니다. 그리고 주목할 점은, 이런 보기를 충족시키기 위해 최종 사용자에게 복잡하고 빠르게 변하는 yaml 데이터를 유지하라는 부담을 지우지 않았다는 것입니다.

또 다른 예로 소프트웨어 라이브러리가 있습니다. 모든 소프트웨어 컴포넌트의 모든 의존성을 카탈로그에 넣고 싶은 유혹이 있지만, 궁극적으로 카탈로그에 잘 맞지 않습니다. 조직에서 널리 쓰이는 inner-source 라이브러리를 개발한다면, 주저하지 말고 그에 대해 단일 컴포넌트를 만드세요! 그러면 사람들이 그것을 검색하고, 소유자를 찾고, 비슷한 통찰을 얻을 수 있습니다. 하지만 생태계 내 개별 버전과 그 사용량을 추적하고 싶다면, 그것은 별도의 솔루션으로 더 잘 해결되는 사용 사례입니다. 그리고 그 솔루션은 Backstage에서 멋진 플러그인 보기를 가질 수 있어, 라이브러리 자체의 보기 안에서 그 출력을 바로 볼 수 있습니다!

그리고 마지막으로 API의 예입니다. 이 주제는 때로 가장 논란이 많을 수 있습니다. API의 매 반복마다 엔티티를 만들어야 한다면 좋지 않을 것이고, 검색을 어지럽히고 결국 혼란스러울 것입니다.

특히 API에서이지만 다른 종류에서도, 그 사물의 새 주 버전이 출시될 때 새 카탈로그 엔티티를 만들고 싶어질 수 있습니다. 그 시점에 어떤 경우에는 새 주 버전이 완전히 새 컴포넌트에 가깝고, 이전 것과 분리되어 배포되며, 완전히 갱신된 계약을 가지고, 어쩌면 다른 문서를 가질 수도 있습니다. 그렇다면 물론 예를 들어 kind: API, name: customerinfo2를 만드세요. 그런 다음 그 문자열을 검색하면 검색 결과에 엔티티 두 개가 나타나기로 선택한 것이며, 이 경우에는 그것이 좋은 일일 수도 있습니다.

더 알아보기 (Learn more)