LabHub

CRD 와 오퍼레이터 · 왜 CRD 인가 · 이론

values 더미를 API 로 바꾸기

LabHub 에서 이어서 보기

한 줄 요약

CRD 는 새로운 기능을 추가하는 장치가 아니다. API 서버가 이미 갖고 있는 능력을 내가 정의한 타입에 그대로 빌려 주는 장치다.

왜 이게 필요했나

사내 서비스를 배포하는 Helm 차트를 상상해 보자. 처음에는 image, replicas 두 개였던 values.yaml 이 1년 뒤에는 마흔 줄이 된다. 그리고 이런 일이 반복된다.

문제의 뿌리는 하나다. values.yaml 은 API 서버 입장에서 그냥 문자열 덩어리다. 검증해 줄 주체가 없고, 저장 위치가 릴리스 시크릿 안이라 조회가 어렵고, 누가 언제 바꿨는지 감사 로그에 리소스 단위로 남지 않고, 값 하나만 바꾸는 권한을 RBAC 로 나눌 수도 없다.

CRD 는 이 문제를 "그러면 그것을 진짜 API 오브젝트로 만들자"로 뒤집는다.

어떻게 동작하나

CRD 하나를 적용하면 API 서버가 /apis/<그룹>/<버전>/namespaces/<ns>/<복수형> 엔드포인트를 열고, 그 순간부터 다음이 공짜로 따라온다.

| 능력 | values.yaml | CR |
| --- | --- | --- |
| 스키마 검증 | 없음 (렌더링 후에야 발견) | OpenAPI v3 로 apply 시점에 거부 |
| 기본값 주입 | 템플릿 안 default 함수 | 스키마 default 를 API 서버가 채움 |
| 모르는 필드 | 조용히 무시 | pruning 으로 잘라내거나 명시적으로 보존 |
| 저장 | 릴리스 시크릿 | etcd 에 오브젝트로 |
| 조회 | helm get values | kubectl get, 라벨 셀렉터, 커스텀 컬럼 |
| 변경 감시 | 없음 | watch 스트림 |
| 권한 분리 | 차트 전체 단위 | 리소스·서브리소스 단위 RBAC |
| 감사 | 파이프라인 로그 | API 감사 로그에 오브젝트 단위로 |

여기에 하나가 더 붙는다. 스키마 안에서 CEL 규칙을 쓸 수 있다. self.tier != 'prod' || self.replicas >= 2 같은 필드 간 제약을 웹훅 서버 없이 API 서버 안에서 검사한다. 예전에는 검증 웹훅을 띄워야 했던 일이 이제는 스키마의 한 줄이다.

그리고 반드시 기억할 것. CRD 만으로는 아무 일도 일어나지 않는다. CR 을 적용하면 검증된 데이터가 etcd 에 잘 저장될 뿐, 파드가 뜨지도 않고 백업이 돌지도 않는다. 여기에 그 타입을 watch 하며 조정하는 컨트롤러가 붙어야 비로소 오퍼레이터다.

CRD          = 새 어휘 (무엇을 원하는지 말하는 언어)컨트롤러      = 그 어휘를 현실로 만드는 두뇌오퍼레이터    = CRD + 컨트롤러

현장에서 만나는 모습

첫째, 플랫폼 팀의 셀프서비스. 내부 개발자 플랫폼을 만드는 팀은 대부분 CRD 로 추상화를 판다. 개발자는 WebService 한 장을 쓰고, 플랫폼은 그것을 Deployment·Service·Ingress·HPA·NetworkPolicy 로 번역한다. 개발자가 배워야 할 표면이 40줄 values 에서 5줄 CR 로 줄어든다.

둘째, Prometheus Operator 의 ServiceMonitor. 거대한 Prometheus 설정 파일을 사람이 편집하는 대신, 각 팀이 작은 CR 을 만들어 "내 서비스의 메트릭을 긁어 가라"고 선언한다. 설정 파일 하나를 여러 팀이 편집하던 충돌이 리소스 단위 소유권으로 바뀐다.

셋째, 쓰지 말아야 할 때가 분명히 있다. 다음 중 하나라도 해당하면 CRD 는 과잉이다.

넷째, CRD 는 코드가 아니라 API 계약이다. 컨트롤러 코드는 언제든 다시 배포할 수 있지만, 이미 etcd 에 쌓인 수천 개의 CR 과 사용자가 Git 에 커밋해 둔 매니페스트는 함부로 못 바꾼다. 필드 하나를 잘못 만들면 v1alpha1 부터 v1 까지 몇 년을 따라다닌다. 그래서 API 표면은 작게 시작하고, 진화할 길을 미리 닦아 둬야 한다.

다음 확인에서 볼 것

이어지는 퀴즈에서는 CRD를 단순 YAML 형식이 아니라 장기 호환성을 가진 API 계약으로
설계해야 하는 이유를 확인한다. 이름·스코프·스키마·버전 변환의 판단 기준을 점검한
뒤 다음 모듈에서 apps.labhub.io 그룹의 WebService 타입을 직접 정의한다.