CBA — Backstage 인증 어소시에이트 · 카탈로그 품질과 정합성 진단 · 이론
카탈로그는 등록될 때가 아니라 시간이 지나면서 썩는다
한 줄 요약
카탈로그가 무너지는 것은 처음 등록할 때가 아니라 반년 뒤입니다. 썩음은 거의 언제나 세 가지 모양으로 나타납니다. 필수 필드가 빠진 엔티티, 존재하지 않는 대상을 가리키는 참조, 그리고 서로를 가리키는 의존 관계입니다. 셋 다 포털을 띄우지 않고도 정적으로 찾아낼 수 있습니다.
왜 이게 필요했나
포털을 처음 열 때는 대개 깨끗합니다. 사람이 손으로 넣었고, 넣은 사람이 아직 그 서비스를 기억하고 있기 때문입니다. 문제는 그다음입니다.
- 팀이 합쳐지면서
team-payments가 사라졌는데, 그 팀을 소유자로 적은 엔티티 열두 개가 남습니다. - 서비스가 다른 시스템으로 옮겨 갔는데
spec.system은 예전 이름 그대로입니다. - 임시로 만든 데이터베이스를 지웠는데
dependsOn에는 아직 그 Resource 가 있습니다.
여기서 중요한 것은 Backstage 가 이것들을 오류로 알려 주지 않는다 는 점입니다. 스키마를 어긴 엔티티는 카탈로그가 오류로 표시하지만, 없는 대상을 가리키는 참조는 그냥 "관계가 계산되지 않은 것" 이 됩니다. 화면에는 빈 칸이 보일 뿐이고 빨간 글씨는 없습니다.
그리고 카탈로그가 죽는 경로는 늘 같습니다. 참조가 끊기고, 그래프가 조각나고, 화면이 비어 보이고, 사람들이 안 보게 되고, 아무도 고치지 않습니다. 빈 화면은 장애처럼 보이지 않기 때문에 아무도 신고하지 않습니다.
어떻게 동작하나
진단할 것은 네 가지다
첫째, 필수 필드 누락. 필수 필드는 kind 마다 다릅니다. Component 와 API 는 spec.type, spec.lifecycle, spec.owner 가 모두 있어야 하고, Resource 는 spec.type 과 spec.owner, System 과 Domain 은 spec.owner 가 있어야 합니다. 여기에 모든 kind 공통으로 apiVersion, kind, metadata.name 이 필요합니다. "필수 필드 세 개" 를 통째로 외우면 kind 가 바뀔 때 틀립니다.
둘째, 끊어진 소유자. 가장 비싼 결함입니다. 소유자가 끊기면 장애 호출, 취약점 티켓, 비용 귀속, 폐기 결정이 모두 갈 곳을 잃습니다. 그리고 원인이 엔티티 파일이 아닌 경우가 많습니다. 조직 데이터 동기화가 멈춰서 Group 자체가 카탈로그에 들어오지 않은 것입니다. 파일만 고치면 다음 주에 같은 일이 다시 납니다.
셋째, 끊어진 참조. spec.system, spec.domain, spec.dependsOn, spec.providesApis 가 대상입니다. 소유자와 나누어 보는 이유는 대응이 다르기 때문입니다. 소유자는 조직 문제이고, 나머지는 대개 이름이 바뀌었거나 엔티티를 아직 안 만든 것입니다.
넷째, 의존 순환. A dependsOn B 이고 B dependsOn A 인 상태입니다. 이러면 영향도 분석이 의미를 잃습니다. "이걸 내리면 뭐가 깨지나" 를 물었을 때 답이 자기 자신으로 돌아옵니다. 원인은 대개 오해입니다. A 가 B 를 호출하니까 B 쪽에도 A 를 적어야 한다고 생각하는 것인데, 관계는 한쪽 선언으로 카탈로그가 양방향을 계산합니다.
비교하기 전에 참조를 정규화한다
이것을 빠뜨리면 검사기가 멀쩡한 참조를 결함으로 신고합니다.
team-orders → group:default/team-ordersgroup:team-orders → group:default/team-ordersgroup:default/team-orders → group:default/team-orders셋은 같은 것을 가리킵니다. kind 는 필드마다 기본값이 정해져 있고 네임스페이스의 기본값은 default 입니다. 문자열을 그대로 비교하면 세 표기가 전부 다른 것이 되어 버립니다. 정규화한 다음 비교하는 것이 이 작업의 첫 단계입니다.
고치는 순서가 있다
1. 조직 데이터 먼저. 없는 Group 과 User 를 채웁니다.
2. 묶음 다음. 없는 System 과 Domain 을 만들거나, 옮겨 간 곳의 이름으로 참조를 고칩니다.
3. 개별 엔티티 마지막. 빠진 필수 필드를 채우고 남은 참조를 정리합니다.
순서를 뒤집으면 같은 오류를 두 번 고칩니다. 개별 엔티티의 소유자를 하나씩 고쳐 놓고 나서 Group 을 만들면, 방금 고친 값들이 다시 어색해집니다.
그리고 반드시 지켜야 할 것 하나. 결함이 있는 엔티티를 지워서 목록을 깨끗하게 만드는 것은 고친 것이 아닙니다. 카탈로그의 목적은 우리가 가진 것을 빠짐없이 보여 주는 것입니다. 안 보이게 만든 서비스도 새벽 세 시에는 깨집니다.
게이트로 막는다
catalog-info.yaml 이 코드 저장소에 살기 때문에 검사를 PR 에서 돌릴 수 있습니다. 파일이 합쳐지기 전에 막으면 카탈로그가 썩는 속도가 크게 떨어집니다. 게이트는 깨끗한 입력에는 0 을, 결함이 있는 입력에는 0 이 아닌 값을 내야 합니다.
현장에서 만나는 모습
이 저장소에는 게이트에 관한 뼈아픈 기록이 있습니다. "문서에 평문 비밀번호가 없다" 는 검사 항목이 오랫동안 초록불이었는데, 사실은 한 가지 모양만 보고 있었습니다. 그 사이 여러 도구의 관리자 비밀번호가 두 문서에 평문으로 있었고, 셋 다 서로 다른 모양이라 아무 패턴에도 걸리지 않았습니다.
교훈은 정규식이 아니었습니다. 게이트를 만들었으면 막으려는 것을 실제로 넣어 보고 빨간불이 켜지는지 확인해야 합니다. 통과하는 것만 확인하면 그 게이트는 아무것도 아닌 채로 몇 달을 갑니다. 카탈로그 lint 도 똑같습니다. 깨끗한 디렉터리에서 0 이 나오는 것만 보고 만족하면, 결함이 들어와도 0 을 내는 게이트를 배포하게 됩니다.
같은 감각이 이 클러스터의 반복된 교훈인 "상태가 Ready 인 것과 실제로 동작하는 것은 다른 명제" 와 이어집니다. 카탈로그 화면이 정상으로 보이는 것과 그 안의 관계가 실제로 연결되어 있는 것은 다른 사실입니다. 후자는 눈으로 볼 수 없어서 반드시 계산해 봐야 합니다.
다음 실습에서 할 것
/root/cba-audit/incoming/ 에 인계받은 카탈로그 여덟 건을 그대로 재현합니다. 그 안에는 결함 네 종류가 일부러 들어 있습니다. 그다음 필수 필드 누락, 끊어진 소유자, 끊어진 참조, 의존 순환을 각각 진단해 목록으로 뽑고, 고친 사본을 만들어 네 진단이 모두 0 이 되게 합니다. 마지막으로 같은 검사를 하는 lint 스크립트를 작성해 깨끗한 입력과 결함 있는 입력 양쪽에서 시험하고, 감사 결과를 클러스터에 기록합니다.