CRDでAPIを広げる
한국어 원문으로 표시합니다.
목표
CustomResourceDefinition 을 직접 작성해 쿠버네티스 API 를 넓히고, 스키마 검증이 실제로 요청을 거부하는 것을 확인하고, 새 리소스에 대한 권한을 Aggregated ClusterRole 로 붙입니다.
왜 중요한가
CKA 출제 범위에 CRD 가 들어간 이유는 오퍼레이터를 만들라는 뜻이 아닙니다. 오퍼레이터가 깔린 클러스터를 운영할 수 있느냐를 묻는 것입니다. 현장의 클러스터에는 이미 수십 개의 CRD 가 깔려 있습니다.
여기서 이해해야 할 구조가 있습니다. CRD 를 만들면 apiserver 에 새 엔드포인트가 생기고, 그 엔드포인트는 저장·검증·watch 를 제공합니다. 하지만 그것뿐입니다. 실제로 무언가를 하는 것은 그 CR 을 watch 하는 컨트롤러이고, 그건 별도 소프트웨어입니다. CR 을 만들었는데 아무 일도 안 일어난다면 대개 컨트롤러가 없거나 죽은 것입니다.
스키마도 같은 맥락입니다. apiextensions.k8s.io/v1 에서 schema 는 선택이 아니라 필수입니다. 스키마가 곧 그 API 의 계약이고, 잘못된 값을 컨트롤러가 아니라 apiserver 가 먼저 막아 줍니다.
단계
- CRD
widgets.labhub.io를 만든다. grouplabhub.io, scopeNamespaced, kindWidget, pluralwidgets, singularwidget, shortNames 에wg, 버전은v1alpha1하나이며 served 와 storage 모두 true. - 네임스페이스
cka-crd를 만들고 그 안에 Widgetdemo를 만든다.spec.replicas는 3,spec.tier는small. - CRD 의 v1alpha1 스키마를 고쳐 검증 규칙을 넣는다.
spec.replicas는 typeinteger에 minimum 1, maximum 10.spec.tier는 typestring에 enum[small, large]. spec 오브젝트의 required 는[replicas, tier]. spec.replicas가 99 인 Widgettoo-big을 만들어 보고, 거부된 에러 출력을/root/cka-crd/reject.txt에 저장한다.too-big은 생성되지 않아야 한다.- v1alpha1 에 additionalPrinterColumns 두 개를 추가한다. 이름
REPLICAS(typeinteger, jsonPath.spec.replicas), 이름TIER(typestring, jsonPath.spec.tier). - CRD
clusterwidgets.labhub.io를 만든다. scopeCluster, kindClusterWidget, pluralclusterwidgets, grouplabhub.io, 버전v1alpha1. 그리고 ClusterWidgetglobal을 만든다. - ClusterRole
cka-widget-viewer를 만든다. 라벨rbac.labhub.io/aggregate-to-widget=true, 규칙은 apiGroupslabhub.io의widgets에 대해get,list,watch. 그리고 ClusterRolecka-widget-aggregate를 만들어 aggregationRule 이 그 라벨을 셀렉터로 고르게 한다.
참고
- 스키마 최소 형태는
openAPIV3Schema: {type: object, properties: {spec: {type: object, x-kubernetes-preserve-unknown-fields: true}}}입니다. 3단계에서 이 spec 을 구체화하게 됩니다. kubectl get crd widgets.labhub.io -o yaml로 현재 스키마를 뽑아 고친 뒤 다시 적용하는 방식이 빠릅니다.- 흔한 실수 1: CRD 이름을
widget.labhub.io처럼 단수로 쓰는 것. 반드시 plural 과 group 을 이어 붙여야 합니다. - 흔한 실수 2: aggregationRule 을 쓰면서 rules 도 함께 적는 것. 컨트롤러가 rules 를 덮어쓰므로 손으로 쓴 규칙은 사라집니다.
CustomResourceDefinition 만들기
CRD widgets.labhub.io 를 만든다. group labhub.io, scope Namespaced, kind Widget, plural widgets, singular widget, shortNames 에 wg, 버전은 v1alpha1 하나이며 served 와 storage 모두 true.
CRD 의 metadata.name 은 반드시 '복수형.그룹' 형식이어야 합니다. apiextensions.k8s.io/v1 에서는 versions 배열의 각 항목에 schema 가 필수입니다.
커스텀 리소스 만들기
네임스페이스 cka-crd 를 만들고 그 안에 Widget demo 를 만든다. spec.replicas 는 3, spec.tier 는 small.
CR 의 apiVersion 은 '그룹/버전' 입니다. 스키마가 느슨하면 임의 필드가 들어가니, 우선 spec 아래에 미지의 필드를 허용해 두면 편합니다.
스키마에 검증 규칙 넣기
CRD 의 v1alpha1 스키마를 고쳐 검증 규칙을 넣는다. spec.replicas 는 type integer 에 minimum 1, maximum 10. spec.tier 는 type string 에 enum [small, large]. spec 오브젝트의 required 는 [replicas, tier].
openAPIV3Schema 안의 properties.spec.properties 아래에 필드별 type 과 minimum/maximum/enum 을 답니다. required 는 값이 아니라 그 오브젝트 레벨의 배열입니다.
검증이 거부하는 순간 확인하기
spec.replicas 가 99 인 Widget too-big 을 만들어 보고, 거부된 에러 출력을 /root/cka-crd/reject.txt 에 저장한다. too-big 은 생성되지 않아야 한다.
에러는 표준출력이 아니라 표준에러로 나갑니다. 리다이렉트할 때 2>&1 을 잊지 마세요. 거부된 리소스는 만들어지지 않아야 정상입니다.
kubectl get 출력에 컬럼 추가하기
v1alpha1 에 additionalPrinterColumns 두 개를 추가한다. 이름 REPLICAS (type integer, jsonPath .spec.replicas), 이름 TIER (type string, jsonPath .spec.tier).
additionalPrinterColumns 는 versions 배열의 각 버전 안에 들어갑니다. name, type, jsonPath 세 필드가 필요하고 jsonPath 는 점으로 시작합니다.
클러스터 스코프 CRD 만들기
CRD clusterwidgets.labhub.io 를 만든다. scope Cluster, kind ClusterWidget, plural clusterwidgets, group labhub.io, 버전 v1alpha1. 그리고 ClusterWidget global 을 만든다.
scope 는 CRD 를 만든 뒤에는 바꿀 수 없습니다. 클러스터 스코프 리소스는 -n 옵션을 받지 않습니다.
Aggregated ClusterRole 로 권한 넓히기
ClusterRole cka-widget-viewer 를 만든다. 라벨 rbac.labhub.io/aggregate-to-widget=true, 규칙은 apiGroups labhub.io 의 widgets 에 대해 get, list, watch. 그리고 ClusterRole cka-widget-aggregate 를 만들어 aggregationRule 이 그 라벨을 셀렉터로 고르게 한다.
aggregationRule 이 있는 ClusterRole 의 rules 는 직접 쓰지 않습니다. 라벨이 붙은 다른 ClusterRole 을 컨트롤러가 찾아 합쳐 줍니다.