TT Lab
시작하기
배우기 러닝패스 코스

CBA — Backstage 인증 어소시에이트

엔티티와 관계 — 소유권이 카탈로그의 심장인 이유

TT Lab 에서 이어서 보기

한 줄 요약

카탈로그는 서비스 목록이 아니라 관계 그래프 입니다. 엔티티 종류를 외우는 것보다, 각 종류가 어떤 질문에 답하기 위해 존재하는지를 이해하는 편이 시험과 실무 모두에 유용합니다.

왜 이게 필요했나

"서비스 목록"만 있으면 이런 질문에 답할 수 없습니다.

그래서 Backstage 는 엔티티를 여러 종류로 나누고 그 사이의 관계를 저장합니다.

소유권과 의존 관계는 서로 다른 화살표다

같은 서비스에서 나가는 참조라도 관계의 뜻을 구분해야 장애 대응에 쓸 수 있다.

  • 소유권 관계payments → team-payments: 누가 책임지고 돌보는가.
  • 의존 관계payments → orders-api: 무엇에 의존해 동작하는가.

여기서 구분할 것 카탈로그의 소유권 메타데이터만으로 실제 시스템의 접근 권한이 자동 부여되는 것은 아니다.

잠깐, 예측해 보세요 owner를 다른 팀으로 바꾸면 그 팀의 클러스터 권한도 자동으로 바뀔까?

설명 확인 · 채점 없는 자가 점검

그런 별도 연동을 구현하지 않았다면 아니다. 카탈로그의 책임 정보와 인증·인가 정책은 구분해서 검증해야 한다.

근거 문서

어떻게 동작하나

엔티티 여덟 종류

kind 답하는 질문 대표 필드
Component 우리가 만들고 배포하는 소프트웨어 조각 spec.type(service/website/library), spec.lifecycle, spec.owner, spec.system
API 컴포넌트가 노출하거나 소비하는 인터페이스 spec.type(openapi/asyncapi/graphql/grpc), spec.definition
Resource 컴포넌트가 필요로 하는 인프라 spec.type(database/s3-bucket/queue)
System 함께 동작하는 엔티티들의 묶음 spec.owner, spec.domain
Domain 여러 시스템을 아우르는 사업 영역 spec.owner
Group 팀·조직 단위 spec.type(team), spec.children, spec.profile
User 사람 spec.memberOf
Location 다른 엔티티가 있는 위치를 가리키는 표지판 spec.type, spec.targets

여기에 Template(스캐폴더용)이 더해집니다. 그리고 spec.lifecycle 은 자유 문자열이지만 관례적으로 experimental / production / deprecated 를 씁니다 — 폐기 예정 서비스를 목록에서 걸러 내는 데 쓰입니다.

관계(relations)는 계산되는 것이다

중요한 포인트입니다. catalog-info.yaml 에 쓰는 것은 spec.owner, spec.system, spec.providesApis 같은 선언 이고, 카탈로그가 이를 읽어 양방향 관계 를 계산해 저장합니다.

spec.owner: group:team-checkout      →  ownedBy / ownerOf
spec.system: commerce                →  partOf / hasPart
spec.providesApis: [checkout-api]    →  providesApi / apiProvidedBy
spec.consumesApis: [payments-api]    →  consumesApi / apiConsumedBy
spec.dependsOn: [resource:checkout-db] →  dependsOn / dependencyOf

그래서 providesApis 를 한쪽에만 써도 API 엔티티 페이지에서 "이 API 를 제공하는 컴포넌트"가 보입니다. 반대 방향을 손으로 쓸 필요가 없습니다. 시험에서 "관계를 양쪽 파일에 모두 적어야 하는가?" 를 물으면 답은 아니오입니다.

엔티티 참조 형식

관계를 쓸 때 다른 엔티티를 가리키는 문자열 형식이 정해져 있습니다.

[<kind>:][<namespace>/]<name>

세 부분 중 kind 와 namespace 는 생략 가능하고, 생략하면 문맥에 따른 기본값이 적용됩니다. namespace 의 기본값은 default 입니다.

쓴 것 해석
team-checkout 문맥의 기본 kind + default 네임스페이스
group:team-checkout group:default/team-checkout
group:payments/team-checkout 네임스페이스까지 명시

spec.owner 같은 필드는 기본 kind 가 정해져 있어 team-checkout 만 써도 동작하지만, 명시적으로 group: 을 붙이는 편이 리뷰에서 훨씬 안전합니다. 사람이 읽을 때 그것이 팀인지 개인인지 바로 보이기 때문입니다.

왜 catalog-info.yaml 은 코드 옆에 사는가

카탈로그를 채우는 방식은 세 가지입니다.

  1. 정적 등록 — Backstage 설정 파일에 URL 목록을 적는다. 소규모에는 되지만 늘어나면 관리 불가.
  2. Location 엔티티 — 표지판 엔티티가 다른 파일들을 가리킨다. 계층적으로 묶을 때 유용.
  3. 디스커버리(discovery) — 조직의 저장소를 훑어 catalog-info.yaml 을 찾아 자동 등록. 실무의 정답.

3 번이 성립하려면 파일이 코드와 같은 저장소 에 있어야 합니다. 이 배치가 만드는 효과가 큽니다.

반대로 카탈로그를 중앙 저장소 한 곳에 몰아 두면, 그 파일을 고칠 동기가 있는 사람이 아무도 없어집니다. 카탈로그가 썩는 가장 흔한 경로입니다.

소유권이 심장인 이유

카탈로그에서 딱 하나만 정확해야 한다면 그것은 소유자 입니다.

그래서 소유자는 사람(User)이 아니라 팀(Group) 이어야 합니다. 사람은 퇴사하고 팀은 인수됩니다. 시험에서 자주 나오는 지점이고, 실무에서 카탈로그가 무너지는 첫 번째 원인이기도 합니다.

현장에서 만나는 모습

저자의 홈랩에서 쿠버네티스 워크로드에 app.kubernetes.io/name, app.kubernetes.io/part-of 같은 표준 라벨을 붙이는 습관이 이 카탈로그 사고와 정확히 같은 것입니다. Helm 차트 모범 사례에서도 app.kubernetes.io/name, instance, version, component, part-of, managed-by 여섯 개를 표준으로 붙이라고 권합니다.

즉 같은 소유권·소속 정보를 클러스터 라벨과 카탈로그 엔티티 두 곳에 일관되게 표현 하는 것이 실무의 모습입니다. 그리고 이 둘을 연결해 주는 것이 Backstage 의 Kubernetes 플러그인입니다 — 엔티티에 애너테이션 backstage.io/kubernetes-id 를 달아 두면, 그 값과 같은 라벨을 가진 워크로드를 클러스터에서 찾아 엔티티 페이지에 보여 줍니다.

홈랩 GPU 노드에 붙인 gpu.homelab/tier=xlarge 같은 의미 기반 라벨도 같은 정신입니다. 물리적 사실을 사람이 결정에 쓸 수 있는 어휘로 번역하는 것 — 카탈로그가 시스템·도메인으로 서비스를 묶는 이유와 다르지 않습니다.

참조를 적는 것과 관계가 만들어지는 것을 나눈다

엔티티 이름의 오타나 네임스페이스 혼동은 파일 문법 검사만으로 잡히지 않을 수 있다.

  1. 참조 작성kind·namespace·name으로 어떤 엔티티를 가리키는지 분명히 한다.
  2. 카탈로그 처리등록·처리 결과와 해당 엔티티의 존재를 확인한다.
  3. 관계 확인최종 엔티티의 관계에서 의도한 소유자와 의존 대상을 확인한다.

여기서 구분할 것 문법이 유효한 문자열이어도 의도한 상대를 가리킨다는 보장은 없다.

잠깐, 예측해 보세요 YAML 검사는 통과했는데 소유 팀 링크가 맞지 않는다. 다음 증거는?

설명 확인 · 채점 없는 자가 점검

참조의 kind·namespace·name과 실제 등록된 팀 엔티티를 비교하고, 처리 오류와 최종 relations를 확인한다.

근거 문서

다음 실습에서 할 것

/root/cba-catalog/ 에 Component, API, Resource, System, Domain, Group, User, Location 엔티티 파일을 직접 작성합니다. 그다음 같은 소유권 정보를 실제 클러스터의 라벨로 표현해 kubectl 로 확인하고, 마지막에 모든 엔티티의 참조 문자열을 정규화된 형식으로 뽑아 봅니다.