콘텐츠로 이동
Study NoteCKA

CRD — 새로운 API 리소스 정의

결론부터
CRD는 새로운 리소스의 API와 스키마를 정의하며, 그 리소스에 따라 작업하는 컨트롤러는 별도로 필요하다.

기본 리소스만으로 도메인의 선언을 표현하기 어려울 때 새 종류를 정의할 수 있다. CustomResourceDefinition(CRD)과 그 인스턴스인 Custom Resource(CR)를 만들면 API 서버에서 무엇이 달라지는지 살펴본다.

“매일 새벽 3시에 백업” 같은 도메인 개념을 kubectl get backup으로 다루고 싶어도, 내장 kind에는 그런 종류가 없다. CRD(CustomResourceDefinition)는 API에 리소스 종류 자체를 등록하는 리소스다 — 등록하는 순간 kubectl·검증·etcd 저장까지 내장 리소스와 똑같이 동작한다.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata: { name: backups.ops.example.com } # 반드시 <복수형>.<그룹> 형식
spec:
group: ops.example.com
scope: Namespaced # Namespaced | Cluster
names:
{ plural: backups, singular: backup, kind: Backup, shortNames: ["bk"] }
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required: ["schedule"]
properties:
schedule: { type: string }
retention: { type: integer, default: 7 }
subresources: { status: {} }
additionalPrinterColumns: # kubectl get 의 출력 열을 정한다
- { name: Schedule, type: string, jsonPath: .spec.schedule }

이 골격을 손으로 치지 않는다 — 시험 중에는 공식 CustomResourceDefinition 문서의 전체 예시를 복사해 이름·스키마만 깎아내는 게 정석이다.

CRD 를 적용하면 API 엔드포인트가 생겨 kubectl 조회 · explain · 검증까지 되지만, 보고 행동하는 컨트롤러가 없어 아무 일도 일어나지 않는다는 것을 보여 주는 그림
터미널 창
kubectl apply -f backup-crd.yaml
kubectl wait --for=condition=Established \
crd/backups.ops.example.com --timeout=60s
kubectl api-resources | grep backups
kubectl get --raw='/apis/ops.example.com/v1'
kubectl explain backup.spec # ★ 스키마가 있으니 explain도 동작한다
apiVersion: ops.example.com/v1
kind: Backup
metadata:
name: nightly
spec:
schedule: "0 3 * * *"

CR까지 적용한 뒤 저장 여부와 조정 여부를 따로 판정한다.

터미널 창
kubectl apply -f backup.yaml
kubectl get backup nightly \
-o jsonpath='{.metadata.uid}{"\t"}{.metadata.resourceVersion}{"\n"}'
kubectl get backup nightly \
-o jsonpath='{.metadata.generation}{"\t"}{.status.conditions}{"\n"}'

CRD의 Established=True, discovery 응답, CR의 uid·resourceVersion은 각각 새 API 등록과 객체 저장을 증명한다. 여기까지 성공해도 백업 같은 실제 작업은 아직 증명되지 않는다. 그 결과는 컨트롤러가 기록한 status.conditions, 컨트롤러가 만든 하위 리소스, 컨트롤러 로그로 따로 확인해야 한다. CRD만 있는 예제에서 status가 비어 있는 것은 저장 실패가 아니라 조정할 컨트롤러가 없다는 경계다.

오퍼레이터를 설치하면 CRD가 한꺼번에 여러 개 생긴다. 어떤 종류가 생겼는지와 각 필드의 뜻은 문서를 찾기 전에 API 서버에 먼저 묻는다. CRD 스키마에 적힌 설명을 kubectl explain이 그대로 보여 준다.

터미널 창
kubectl get crd # 전체 목록. 이름은 <복수형>.<그룹>
kubectl get crd | grep ops.example.com # 그룹 이름으로 거른다
kubectl api-resources --api-group=ops.example.com # 종류·단축 이름·네임스페이스 범위 여부
kubectl explain backup.spec # spec 아래 필드 목록
kubectl explain backup.spec.schedule # 필드 하나의 문서
kubectl explain backup.spec --recursive # 하위 필드를 트리로
  • kubectl get crd는 종류의 정의를, kubectl get backup은 그 종류로 만든 오브젝트를 보여 준다.
  • kubectl explain은 필드의 문서를, kubectl get backup nightly -o jsonpath='{.spec.schedule}'은 오브젝트에 든 값을 보여 준다.
  • 결과를 남기라는 조건이면 명령 끝에 > 파일을 붙인다.

목록과 필드 문서를 파일로 저장하는 연습은 실전 과제에 있다.

  • CRD는 새로운 리소스의 API와 스키마를 정의하며, 그 리소스에 따라 작업하는 컨트롤러는 별도로 필요하다.
  • CRD는 종류의 정의이고 CR은 그 종류로 생성한 실제 오브젝트다.
  • CRD 삭제는 CR 삭제로 이어지므로 범위를 확인한다. 선언 실행은 Operator의 역할이다.