보뇨 다이어리

[CKA] Cluster Architecture - CRD 본문

컴퓨터 관련/Docker, Kubernetes 정보

[CKA] Cluster Architecture - CRD

보뇨 2026. 9. 25. 19:25
반응형

[11. CRD / Operator]

출제 비중: 낮음 ~ 중간. 커리큘럼에 "CRD 와 Operator 이해"가 있다.
보통 목록 조회, CR 생성, explain 으로 필드 찾기 수준. CRD 를 직접 만드는 문제는 드묾.
관련 문제: 0022 (CRD 조회와 Custom Resource 생성) - 통과


1. 왜 CRD 인가

  쿠버네티스에는 Pod, Deployment, Service 같은 기본 리소스가 있다.
  "인증서", "Gateway", "DB 클러스터"처럼 기본에 없는 개념도
  쿠버네티스 방식으로 관리하고 싶어진다.
  CRD 는 apiserver 에 새 리소스 타입을 등록하는 기능이다.
  등록하고 나면 kubectl get, apply, delete 가 기본 리소스와 똑같이 동작한다.


2. 세 가지 용어

    CRD        새 리소스 타입의 정의. 이름, 필드, 검증 규칙      = 테이블 스키마
    CR         그 타입으로 만든 실제 오브젝트 하나              = 테이블의 행 하나
    Operator   CR 을 감시하다가 실제 일을 하는 컨트롤러          = 행이 추가되면 동작하는 프로그램
               보통 Deployment 로 뜬다

  CRD 만 있으면 아무 일도 일어나지 않는다.
  CR 을 만들어도 etcd 에 저장만 될 뿐이다.
  Operator 가 CR 을 읽고 Pod 을 띄우든 설정을 바꾸든 실제 동작을 해야 의미가 생긴다.
  Deployment 도 같은 구조다.
  Deployment 오브젝트를 읽고 ReplicaSet 을 만드는 건 controller-manager 안의 컨트롤러다.


3. 이미 쓰고 있었던 것

  회사 서버 helm list 에서
    prometheus-crds, aieg-crd                              CRD 만 설치하는 차트
    prometheus-operator                                    ServiceMonitor 같은 CR 을 감시하는 Operator
    workload-controller-manager, project-controller        이름으로 보면 회사에서 만든 Operator

  kind 클러스터에도 이미 있다.
  Gateway API 와 Calico 가 설치될 때 CRD 를 수십 개 등록했다.


4. 시험 명령

    kubectl get crd                                  설치된 CRD 목록
    kubectl get crd <이름> -o yaml                   group, versions, scope, names, schema
    kubectl api-resources --api-group=<group>        그룹별 리소스, kind, 약칭
    kubectl api-resources | grep -i <키워드>
    kubectl explain <kind>                           CR 최상위 필드 + GROUP/KIND/VERSION
    kubectl explain <kind>.spec                      spec 아래 필드
    kubectl explain <kind> --recursive               전체 필드 구조를 한 번에
    kubectl get <kind> -A                            CR 목록

  --recursive 가 좋은 이유
    설명 없이 필드 트리만 쭉 보여줘서 전체 틀을 한눈에 볼 수 있다.
    YAML 을 어떤 depth 로 써야 하는지 바로 보인다.
    기본 리소스에도 쓸 수 있다. 예) kubectl explain pod.spec.containers --recursive
    출력이 길면 | less 또는 | grep -A5 <필드> 로 좁힌다.


5. CRD 이름과 CR apiVersion 읽는 법

  CRD 이름은 항상 <복수형>.<group>

    shirts.stable.example.com
      |         +-- group
      +-- plural

  CR 을 만들 때
    CRD 필드                         CR 에서 쓰는 곳
    spec.group + versions[].name     apiVersion: <group>/<version>   예) stable.example.com/v1
    spec.names.kind                  kind: 대소문자 그대로            예) Shirt
    spec.scope                       Namespaced 면 metadata.namespace 필요

  apiVersion 을 빨리 찾는 두 곳
    kubectl explain shirts          GROUP: stable.example.com / VERSION: v1
    kubectl api-resources | grep -i shirt
      shirts   sh   stable.example.com/v1   true   Shirt
      (이름    약칭  APIVERSION            NAMESPACED KIND)
    api-resources 의 APIVERSION 열을 그대로 복사하면 된다.

  1절 RBAC 의 "apiGroups 는 apiVersion 의 앞부분"과 같은 원리.
  RBAC 에서 CR 권한을 줄 때도 apiGroups 에 이 group 을 쓴다.
    apiGroups: ["stable.example.com"]  resources: ["shirts"]


6. 내가 겪은 에러와 원인

  1) kubectl explain shirts .spec
     error: We accept only this format: explain RESOURCE
     -> 공백 없이 점으로 잇는다. kubectl explain shirts.spec

  2) kubectl create shirt -f sample.yaml
     error: Unexpected args: [shirt]
     -> kubectl create <종류> 형태는 deployment, service 처럼
        kubectl 에 생성기가 내장된 기본 리소스만 된다.
        CR 은 YAML 로만 만든다. kubectl create -f 또는 kubectl apply -f

  3) apiVersion: stable.example.com 으로 적었을 때
     error: resource mapping not found ... no matches for kind "Shirt"
            in version "stable.example.com" / ensure CRDs are installed first
     -> apiVersion 에 version 이 빠졌다. stable.example.com/v1
        "CRD 를 먼저 설치하라"는 문구에 속지 말 것.
        CRD 는 있는데 apiVersion 이나 kind 가 틀려도 같은 에러가 난다.

  4) k get shirt
     zsh: command not found: k
     -> 맥북에는 k alias 가 없다. 실제 시험 환경에는 미리 설정돼 있다.
        맥북에도 만들어 두면 시험과 같은 손버릇으로 연습할 수 있다.
          echo "alias k=kubectl" >> ~/.zshrc && source ~/.zshrc


7. 함정

  - CRD 이름만 저장하라는 문제에서 -o name 을 그대로 쓰면 접두사가 붙는다.
      kubectl get crd -o name
      -> customresourcedefinition.apiextensions.k8s.io/shirts.stable.example.com
    이름만 남기는 방법
      kubectl get crd -o name | grep stable.example.com | cut -d/ -f2
      kubectl get crd -o custom-columns=NAME:.metadata.name --no-headers | grep stable.example.com
    그냥 kubectl get crd | grep 결과를 저장하면 CREATED AT 열까지 들어간다.
    (이 저장소 채점기는 포함 여부만 봐서 접두사가 있어도 통과했지만,
     실제 시험에서 "이름만"을 엄격하게 보면 틀릴 수 있다)
  - schema 의 enum. 허용 값 목록 밖의 값은 apply 가 거부된다.
    size 는 S, M, L, XL 만. 소문자 m 도 거부.
  - CRD 를 지우면 CR 도 전부 사라진다.
    실무에서 제일 위험한 실수. 운영 클러스터에서 CRD 차트를 uninstall 하면 데이터가 날아간다.
  - kind 대소문자. kind: shirt 처럼 쓰면 못 찾는다. CRD 의 names.kind 그대로.


8. 문제 0022 풀이

  요구사항
    1) group stable.example.com 의 CRD 이름을 /tmp/cncf-out/crds.txt 에 한 줄씩
    2) 그 kind 로 default 에 CR blue-shirt. spec.color: blue, spec.size: M

  1) CRD 이름 저장
    kubectl get crd -o custom-columns=NAME:.metadata.name,GROUP:.spec.group | grep stable.example.com
    kubectl get crd -o name | grep stable.example.com | cut -d/ -f2 > /tmp/cncf-out/crds.txt
    cat /tmp/cncf-out/crds.txt       -> shirts.stable.example.com

    jsonpath 로 group 을 정확히 거르는 방법 (공식 풀이)
    kubectl get crd -o jsonpath='{range .items[?(@.spec.group=="stable.example.com")]}{.metadata.name}{"\n"}{end}' \
      > /tmp/cncf-out/crds.txt

  2) 스키마 확인
    kubectl explain shirts           GROUP, KIND, VERSION
    kubectl explain shirts.spec      color <string>, size <string> enum: S, M, L, XL

  3) CR 생성
    # sample.yaml
    apiVersion: stable.example.com/v1
    kind: Shirt
    metadata:
      name: blue-shirt
    spec:
      color: blue
      size: M

    kubectl create -f sample.yaml -n default
    -> shirt.stable.example.com/blue-shirt created

  4) 확인
    kubectl get shirt -n default
    kubectl get shirt blue-shirt -n default -o yaml

  5) 채점
    ./bin/q check 22

반응형