CNPE — 클라우드 네이티브 플랫폼 엔지니어 (전문가) · 플랫폼 API 와 셀프서비스 · 실습
플랫폼 API 를 설계하고 담장을 세우기
목표
AppClaim 이라는 셀프서비스 API 를 CRD 로 설계해 적용하고, 스키마와 CEL 로 잘못된 요청을 거절하게 만들고, RBAC 으로 테넌트가 할 수 있는 일과 할 수 없는 일을 나눈 뒤, 발급 개수에 상한을 겁니다.
왜 중요한가
CNPE 에서 플랫폼 API 와 셀프서비스는 배점이 25% 로 가장 큰 영역입니다. 그리고 이 영역에서 묻는 것은 CRD 를 만들 줄 아는가가 아니라, 무엇을 API 서버가 거절하게 만들 것인가를 정할 줄 아는가 입니다.
이 판단이 중요한 이유는 거절하는 자리가 두 곳뿐이기 때문입니다. API 서버가 거절하면 사용자는 즉시 이유를 봅니다. 컨트롤러가 나중에 실패하면 사용자는 접수됐다고 믿고 기다립니다. 앞쪽에서 걸 수 있는 것을 뒤쪽으로 미루면 그만큼 사람이 헤맵니다.
이 실습의 클러스터에는 조정을 수행하는 컨트롤러가 없습니다. 그러나 kube-apiserver 는 진짜라서 CRD 등록, OpenAPI 검증, CEL 평가, RBAC 판정, ResourceQuota 어드미션이 전부 실제로 동작합니다. 그래서 여기서 확인하는 거절과 허용은 실제 클러스터에서 일어나는 것과 같습니다.
작업 디렉터리는 /root/cnpe-api 이고, 테넌트 네임스페이스는 tenant-blue 입니다.
단계
1. /root/cnpe-api/appclaim-crd.yaml 에 CRD 를 씁니다. 그룹은 platform.labhub.io, 종류는 AppClaim, 복수형은 appclaims, 범위는 Namespaced 입니다. 버전은 v1alpha1 과 v1 두 개이고 둘 다 served 이며 저장 버전은 v1 입니다. v1 에 status 서브리소스와 .spec.tier 를 보여 주는 출력 컬럼을 둡니다. 다 쓴 뒤 apply 합니다.
2. v1 의 spec 에 검증을 더합니다. tier 는 bronze, silver, gold 만 허용하고, CEL 규칙으로 replicas 가 maxReplicas 를 넘지 못하게 막습니다. 거절 메시지에는 maxReplicas 라는 필드 이름이 들어가야 합니다.
3. 네임스페이스 tenant-blue 를 만들고, /root/cnpe-api/claim-checkout.yaml 에 AppClaim checkout 을 씁니다. tier 는 silver, replicas 는 2, maxReplicas 는 6 입니다. apply 한 뒤 v1alpha1 로도 읽히는지 확인합니다.
4. v1 의 spec 에 전이 규칙을 더해 tier 를 불변으로 만듭니다. 규칙은 oldSelf 를 참조해야 하고, 거절 메시지에는 tier 가 들어가야 합니다. tier 를 그대로 둔 채 replicas 만 바꾸는 변경은 계속 통과해야 합니다.
5. /root/cnpe-api/tenant-rbac.yaml 에 ServiceAccount blue-dev, Role appclaim-author, RoleBinding appclaim-author 를 씁니다. 롤은 AppClaim 에 대해 get, list, watch, create, update, patch 를 허용합니다. 바인딩은 그 ServiceAccount 를 가리켜야 합니다.
6. 롤에 delete 가 없고, resourcequotas 와 roles 와 rolebindings 를 만들 수 없고, secrets 를 읽을 수 없는지 kubectl auth can-i 로 확인합니다. 롤의 verbs, resources, apiGroups 어디에도 * 가 없어야 합니다.
7. AppClaim search 를 하나 더 만들고, /root/cnpe-api/claim-quota.yaml 에 ResourceQuota blue-claims 를 씁니다. count/appclaims.platform.labhub.io 의 상한은 2 입니다. 쿼터의 status.used 가 2 로 채워지는지 확인하고, 비어 있으면 쿼터를 지웠다가 다시 걸어 채워질 때까지 반복한 뒤, 세 번째 청구가 실제로 막히는지 확인합니다.
8. /root/cnpe-api/api-report.txt 에 storage_version, claims, quota_hard, tenant_can_delete 네 줄을 키=값 형식으로 적습니다. 네 값 모두 클러스터에서 직접 조회한 것이어야 합니다.
참고
- 서버가 실제로 거절하는지 볼 때는
kubectl apply --dry-run=server를 쓰십시오. 검증 경로를 그대로 타면서 클러스터에는 아무것도 남기지 않습니다. - 쿼터 키에는 점이 들어 있어서 jsonpath 로 읽기가 번거롭습니다.
kubectl get resourcequota blue-claims -n tenant-blue -o json | jq로 읽는 편이 낫습니다. - CRD 를 적용한 직후에는
kubectl wait --for=condition=Established crd/...로 등록이 끝나기를 기다리십시오. - 흔한 실수 하나는 Role 만 만들고 RoleBinding 을 잊는 것입니다. 롤은 권한의 정의일 뿐이고, 붙이지 않으면 아무 권한도 생기지 않습니다.
- 또 하나는
self == oldSelf로 spec 전체를 묶어 버리는 것입니다. 그것은 불변이 아니라 동결이고, 레플리카도 못 바꾸게 됩니다.
단계 8개
- CRD 의 뼈대와 두 버전을 정하기
- 값의 집합과 필드 사이의 관계를 묶기
- 첫 셀프서비스 요청을 접수하기
- 한 번 정하면 못 바꾸는 필드 만들기
- 테넌트가 스스로 할 수 있는 일 정하기
- 닫아 둔 쪽을 판정으로 확인하기
- 발급에 상한을 걸고 막히는지 보기
- 플랫폼 API 의 현재 상태를 값으로 남기기