CNPA — 클라우드 네이티브 플랫폼 엔지니어링 어소시에이트 · 플랫폼 API 와 추상화 · 실습
CRD 로 플랫폼 API 만들기
목표
쿠버네티스 API 를 확장해 WebService 라는 플랫폼 API 를 직접 만들고, 스키마 검증·서버 사이드 기본값·테넌트 경계·셀프서비스 RBAC 까지 한 세트를 실제 클러스터에서 완성합니다.
왜 중요한가
플랫폼 API 를 사내 웹 앱으로 만들면 상태 저장, 동시성 제어, 인증·인가, 감사, watch 를 전부 다시 구현해야 합니다. CRD 를 등록하면 그것들이 전부 따라옵니다 — 그래서 쿠버네티스 API 가 플랫폼의 공용어가 됐습니다. 특히 OpenAPI 스키마는 셀프서비스의 세 조건 중 '빠른 피드백'을 가장 싸게 구현하는 장치입니다. maximum: 10 한 줄이면 잘못된 요청이 30 분 뒤 파이프라인 로그가 아니라 즉시, 사람이 읽을 수 있는 문장으로 거절됩니다. default 도 마찬가지로 '안전한 기본값'을 서버가 강제해 줍니다. 그리고 CRD 만으로는 플랫폼이 완성되지 않습니다 — 테넌트가 서로를 침범할 수 없다는 경계(네임스페이스·쿼터·RBAC)가 함께 있어야 비로소 티켓 없이 권한을 줄 수 있습니다. 이 실습의 모든 리소스는 쿠버네티스 내장 리소스이므로 실제로 적용하고 kubectl 로 채점합니다.
단계
1. /root/cnpa-platform/crd.yaml 에 CustomResourceDefinition 을 작성하고 적용하세요 — metadata.name: webservices.platform.labhub.io, spec.group: platform.labhub.io, spec.scope: Namespaced, spec.names 는 kind WebService, plural webservices, singular webservice, shortNames 첫 항목 ws, 버전 v1alpha1 은 served: true, storage: true.
2. 같은 CRD 의 v1alpha1 스키마를 완성하세요 — spec 객체에 image(string, 필수), replicas(integer, default: 2, minimum: 1, maximum: 10), public(boolean, default: false). 그리고 additionalPrinterColumns 에 이름 Image(jsonPath .spec.image, type string)와 Replicas(jsonPath .spec.replicas, type integer) 두 열을 추가하세요.
3. 네임스페이스 tenant-blue 를 만드세요 — 라벨 platform.labhub.io/tenant: blue 와 pod-security.kubernetes.io/enforce: baseline.
4. tenant-blue 에 ResourceQuota tenant-blue-quota 를 만드세요 — requests.cpu: "2", requests.memory: 4Gi, limits.cpu: "4", limits.memory: 8Gi, pods: "10". 같은 네임스페이스에 LimitRange tenant-blue-limits 를 만드세요 — type Container, default 는 cpu 200m / memory 256Mi, defaultRequest 는 cpu 100m / memory 128Mi.
5. tenant-blue 에 WebService shop 을 만드세요 — spec.image: ghcr.io/labhub/shop:1.0.0 만 쓰고 replicas 와 public 은 쓰지 마세요. 만든 뒤 다시 읽어 두 값이 채워졌는지 확인하세요.
6. 스키마 위반을 확인하세요. spec.replicas: 20 인 WebService bad 를 tenant-blue 에 만들어 보고, 그 실패 출력(표준 에러 포함)을 /root/cnpa-platform/reject.txt 에 저장하세요. bad 는 클러스터에 남아 있으면 안 됩니다.
7. ServiceAccount blue-dev 를 tenant-blue 에 만들고, 같은 네임스페이스에 Role webservice-editor(apiGroups platform.labhub.io, resources webservices, verbs get,list,watch,create,update,patch,delete)와 RoleBinding blue-devs(그 Role 을 blue-dev ServiceAccount 에 연결)를 만드세요. 쿼터를 고칠 권한은 주지 마세요.
8. 같은 패턴으로 두 번째 테넌트를 만드세요 — 네임스페이스 tenant-green(라벨 platform.labhub.io/tenant: green), ResourceQuota tenant-green-quota(pods: "10" 포함), 그리고 WebService api(spec.image: ghcr.io/labhub/api:1.0.0, replicas 는 지정하지 않음). tenant-blue 의 blue-dev 가 tenant-green 에는 WebService 를 만들 수 없어야 합니다.
참고
- CRD 를 적용한 직후에는
kubectl get ws -n tenant-blue처럼 축약형도 바로 동작해야 합니다. - 권한 확인은
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:tenant-blue:blue-dev -n <네임스페이스>로 합니다. - 실패 출력을 파일에 담으려면 표준 에러도 함께 리다이렉트해야 합니다.
- 흔한 실수 1: CRD 의
metadata.name을webservice.platform.labhub.io처럼 단수로 쓰는 것. 반드시 복수형이어야 합니다. - 흔한 실수 2:
default를spec객체 자체가 아니라 각 속성 안에 넣어야 한다는 점. 그리고required는 속성 이름들의 배열입니다.
단계 8개
- CRD 등록 — 그룹·스코프·이름
- 스키마와 프린터 컬럼
- 테넌트 네임스페이스
- ResourceQuota 와 LimitRange
- CR 생성과 서버 사이드 기본값
- 스키마 위반이 거절되는지
- 셀프서비스 권한과 가드레일
- 두 번째 테넌트와 격리 증명