LabHub
배우기 러닝패스 코스

CRDs and Operators

Handing Validation Off to the API Server

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

일부러 규칙을 어긴 리소스를 던져 API 서버가 무엇을 어떻게 거부하는지 직접 수집하고, 기본값 주입·pruning·CEL 검증까지 스키마 하나로 처리되는 것을 확인합니다.

왜 중요한가

검증을 스키마로 옮기는 진짜 이득은 "거부한다"가 아니라 "거부하면서 무엇이 왜 안 되는지 사용자에게 알려 준다" 입니다. enum 을 넣으면 거부 메시지에 허용 목록이 함께 나오고, maximum 을 넣으면 상한이 그대로 문구에 들어갑니다. 사용자는 위키를 뒤지지 않고 오류만 읽어도 고칠 수 있습니다. pruning 은 처음에는 당황스럽습니다 — 오타 필드가 에러도 없이 조용히 사라지기 때문입니다. 하지만 이것이 "스키마가 곧 계약"을 강제하는 장치이고, 그래서 임의의 키를 받아야 하는 자리는 예외적으로만, 그 자리만 열어야 합니다. 마지막으로 CEL 은 판을 바꿨습니다. 예전에는 "prod 면 복제본 2개 이상" 같은 필드 간 제약을 위해 검증 웹훅 서버를 띄우고, 인증서를 관리하고, 그 웹훅이 죽으면 클러스터가 마비되는 위험까지 감수해야 했습니다. 이제는 스키마의 한 줄입니다.

단계

시작 전 준비: 실습 파드는 실습마다 새로 뜨므로 앞 실습에서 만든 클러스터 상태는 남아 있지 않습니다. kubectl get crd webservices.apps.labhub.io 가 비어 있으면 앞 실습에서 쓴 CRD 를 /root/crd/crd.yaml 로 다시 작성해 적용하고 kubectl create ns crd-lab 도 하세요. 이 실습이 요구하는 스키마는 spec.required: [image], replicas(integer, minimum 1, maximum 10, default 1), tier(string, enum [dev, stage, prod], default dev) 이며, 6번과 7번에서 spec.extra 와 CEL 규칙을 여기에 더하게 됩니다.

  1. /root/crd/validate/no-image.yamlmetadata.name: no-image(네임스페이스 crd-lab)이고 specimage 가 없는 WebService 를 쓰고 적용해 보세요. 실패 출력을 표준 에러까지 포함해 /root/crd/validate/out/err-required.txt 로 저장하세요. 출력에 spec.image 와 필수 값 관련 문구가 있어야 하고, no-image 는 클러스터에 남으면 안 됩니다.
  2. /root/crd/validate/bad-type.yamlmetadata.name: bad-type, spec.image: nginx:1.27, spec.replicas: "three" 를 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-type.txt 로 저장하세요.
  3. /root/crd/validate/bad-tier.yamlmetadata.name: bad-tier, spec.image: nginx:1.27, spec.tier: qa 를 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-enum.txt 로 저장하세요. 출력에 허용되는 값들이 함께 보여야 합니다.
  4. /root/crd/validate/too-many.yamlmetadata.name: too-many, spec.image: nginx:1.27, spec.replicas: 50 을 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-range.txt 로 저장하세요.
  5. /root/crd/validate/defaulted.yamlmetadata.name: defaultedspec.image 만 쓰세요. spec.replicasspec.tier절대 적지 마세요. 적용한 뒤 저장된 오브젝트에 replicas: 1, tier: dev 가 채워졌는지 확인하세요.
  6. /root/crd/crd.yaml 의 v1 스키마에 properties.spec.properties.extratype: objectx-kubernetes-preserve-unknown-fields: true 로 추가하고 CRD 를 재적용하세요. 그다음 /root/crd/validate/pruned.yamlmetadata.name: pruned, spec.image, 그리고 스키마에 없는 spec.bogus: anything 을 넣어 적용하고(저장된 오브젝트에서 bogus 는 사라져야 합니다), /root/crd/validate/preserved.yamlmetadata.name: preserved, spec.image, spec.extra.custom: kept 를 넣어 적용하세요(이 값은 남아 있어야 합니다).
  7. v1 스키마의 properties.spec 바로 아래에 x-kubernetes-validations 배열을 추가하세요. 첫 규칙의 ruleself.tier != 'prod' || self.replicas >= 2 이고 messageprod 계층은 복제본이 2개 이상이어야 합니다 입니다. 재적용한 뒤 /root/crd/validate/cel-violation.yamlmetadata.name: cel-violation, spec.image, spec.tier: prod, spec.replicas: 1 을 넣어 적용하고 실패 출력을 /root/crd/validate/out/err-cel.txt 로 저장하세요. 그 출력에 위 message 문구가 그대로 들어 있어야 합니다.
  8. /root/crd/validate/out/matrix.json 을 만드세요. 최상위 키는 cases 이고 배열의 각 원소는 name, expected(rejected 또는 accepted), actual, rule 네 키를 갖습니다. 거부 5건(no-image/required, bad-type/type, bad-tier/enum, too-many/maximum, cel-violation/cel)과 통과 3건(defaulted/default, pruned/pruning, preserved/preserve-unknown-fields)을 모두 넣고, 모든 케이스에서 expectedactual 이 같아야 합니다.

참고

필수 필드 누락이 거부되는 것 보기

/root/crd/validate/no-image.yamlmetadata.name: no-image(네임스페이스 crd-lab)이고 specimage 가 없는 WebService 를 쓰고 적용해 보세요. 실패 출력을 표준 에러까지 포함해 /root/crd/validate/out/err-required.txt 로 저장하세요. 출력에 spec.image 와 필수 값 관련 문구가 있어야 하고, no-image 는 클러스터에 남으면 안 됩니다.

일부러 실패시키는 단계입니다. 거부 메시지는 표준 에러로 나오므로 파일로 남기려면 표준 에러까지 함께 받아야 합니다. 거부된 리소스는 클러스터에 남으면 안 됩니다.

타입 불일치가 거부되는 것 보기

/root/crd/validate/bad-type.yamlmetadata.name: bad-type, spec.image: nginx:1.27, spec.replicas: "three" 를 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-type.txt 로 저장하세요.

YAML 에서 숫자를 따옴표로 감싸면 문자열이 됩니다. 스키마가 integer 를 기대할 때 어떤 문구가 나오는지 저장하세요.

열거값 위반과 허용 목록 안내 보기

/root/crd/validate/bad-tier.yamlmetadata.name: bad-tier, spec.image: nginx:1.27, spec.tier: qa 를 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-enum.txt 로 저장하세요. 출력에 허용되는 값들이 함께 보여야 합니다.

enum 위반 메시지는 거부만 하지 않고 무엇이 가능한지도 알려 줍니다. 그 목록이 출력에 들어가야 합니다.

범위 초과가 거부되는 것 보기

/root/crd/validate/too-many.yamlmetadata.name: too-many, spec.image: nginx:1.27, spec.replicas: 50 을 쓰고 적용해 실패 출력을 /root/crd/validate/out/err-range.txt 로 저장하세요.

maximum 을 넘기는 값을 주세요. 메시지에 상한이 그대로 언급됩니다.

적지 않은 필드에 기본값이 채워지는 것 확인하기

/root/crd/validate/defaulted.yamlmetadata.name: defaultedspec.image 만 쓰세요. spec.replicasspec.tier절대 적지 마세요. 적용한 뒤 저장된 오브젝트에 replicas: 1, tier: dev 가 채워졌는지 확인하세요.

매니페스트에 값을 적으면 기본값이 채워졌는지 알 수 없습니다. 두 필드를 비워 두고, 저장된 오브젝트를 다시 읽어 비교하세요.

모르는 필드의 잘림과 예외적 보존

/root/crd/crd.yaml 의 v1 스키마에 properties.spec.properties.extratype: objectx-kubernetes-preserve-unknown-fields: true 로 추가하고 CRD 를 재적용하세요. 그다음 /root/crd/validate/pruned.yamlmetadata.name: pruned, spec.image, 그리고 스키마에 없는 spec.bogus: anything 을 넣어 적용하고(저장된 오브젝트에서 bogus 는 사라져야 합니다), /root/crd/validate/preserved.yamlmetadata.name: preserved, spec.image, spec.extra.custom: kept 를 넣어 적용하세요(이 값은 남아 있어야 합니다).

스키마에 없는 필드는 저장 전에 잘립니다. 임의의 키를 받아야 하는 자리는 스키마에 오브젝트로 정의한 뒤 알 수 없는 필드를 보존하도록 표시해야 합니다. 그 표시는 x- 로 시작하는 확장 키입니다.

필드 간 제약을 CEL 로 표현하기

v1 스키마의 properties.spec 바로 아래에 x-kubernetes-validations 배열을 추가하세요. 첫 규칙의 ruleself.tier != 'prod' || self.replicas >= 2 이고 messageprod 계층은 복제본이 2개 이상이어야 합니다 입니다. 재적용한 뒤 /root/crd/validate/cel-violation.yamlmetadata.name: cel-violation, spec.image, spec.tier: prod, spec.replicas: 1 을 넣어 적용하고 실패 출력을 /root/crd/validate/out/err-cel.txt 로 저장하세요. 그 출력에 위 message 문구가 그대로 들어 있어야 합니다.

한 필드만 봐서는 판단할 수 없는 규칙입니다. spec 오브젝트 수준에 규칙 배열을 두고, 규칙 안에서는 self 로 현재 객체를 가리킵니다. message 는 사용자가 볼 문구이므로 그대로 오류에 나타납니다.

검증 매트릭스 만들고 실제와 대조하기

/root/crd/validate/out/matrix.json 을 만드세요. 최상위 키는 cases 이고 배열의 각 원소는 name, expected(rejected 또는 accepted), actual, rule 네 키를 갖습니다. 거부 5건(no-image/required, bad-type/type, bad-tier/enum, too-many/maximum, cel-violation/cel)과 통과 3건(defaulted/default, pruned/pruning, preserved/preserve-unknown-fields)을 모두 넣고, 모든 케이스에서 expectedactual 이 같아야 합니다.

앞 단계에서 만든 케이스를 표로 정리합니다. 각 케이스에 이름·예상·실제·걸린 규칙을 적고, 예상과 실제가 하나라도 다르면 안 됩니다.