LabHub
배우기 러닝패스 코스

CNPA — クラウドネイティブプラットフォームエンジニアリングアソシエイト

CRDでプラットフォームAPIを作る

LabHub 에서 이어서 보기

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

목표

쿠버네티스 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, 버전 v1alpha1served: 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: bluepod-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 만 쓰고 replicaspublic쓰지 마세요. 만든 뒤 다시 읽어 두 값이 채워졌는지 확인하세요.
  6. 스키마 위반을 확인하세요. spec.replicas: 20 인 WebService badtenant-blue 에 만들어 보고, 그 실패 출력(표준 에러 포함)을 /root/cnpa-platform/reject.txt 에 저장하세요. bad 는 클러스터에 남아 있으면 안 됩니다.
  7. ServiceAccount blue-devtenant-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-blueblue-devtenant-green 에는 WebService 를 만들 수 없어야 합니다.

참고

CRD 등록 — 그룹·스코프·이름

/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, 버전 v1alpha1served: true, storage: true.

CRD 이름은 <복수형>.<그룹> 형식이어야 합니다. 테넌트가 만드는 리소스이므로 스코프 선택에 주의하세요.

스키마와 프린터 컬럼

같은 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) 두 열을 추가하세요.

OpenAPI v3 스키마는 versions 배열 안의 각 버전에 붙습니다. required, minimum/maximum, default 를 각각 어디에 쓰는지 구분하세요. 프린터 컬럼도 버전마다 정의합니다.

테넌트 네임스페이스

네임스페이스 tenant-blue 를 만드세요 — 라벨 platform.labhub.io/tenant: bluepod-security.kubernetes.io/enforce: baseline.

네임스페이스 자체가 테넌트 경계입니다. 소속을 나타내는 라벨과 파드 보안 표준 라벨을 함께 붙이세요.

ResourceQuota 와 LimitRange

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.

둘은 역할이 다릅니다. 하나는 네임스페이스 총량의 상한이고, 다른 하나는 개별 컨테이너의 기본값과 범위입니다. 둘 다 있어야 '요청을 안 쓴 파드'가 쿼터를 통과합니다.

CR 생성과 서버 사이드 기본값

tenant-blue 에 WebService shop 을 만드세요 — spec.image: ghcr.io/labhub/shop:1.0.0 만 쓰고 replicaspublic쓰지 마세요. 만든 뒤 다시 읽어 두 값이 채워졌는지 확인하세요.

replicas 를 아예 쓰지 말고 만들어 보세요. 저장된 오브젝트를 다시 읽으면 값이 들어가 있어야 합니다.

스키마 위반이 거절되는지

스키마 위반을 확인하세요. spec.replicas: 20 인 WebService badtenant-blue 에 만들어 보고, 그 실패 출력(표준 에러 포함)을 /root/cnpa-platform/reject.txt 에 저장하세요. bad 는 클러스터에 남아 있으면 안 됩니다.

범위를 벗어난 값으로 만들어 보고, 그때 나오는 에러 메시지를 파일로 남기세요. 표준 에러도 함께 저장해야 합니다.

셀프서비스 권한과 가드레일

ServiceAccount blue-devtenant-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 에 연결)를 만드세요. 쿼터를 고칠 권한은 주지 마세요.

새 리소스에도 기존 RBAC 이 그대로 적용됩니다. 규칙의 apiGroups 와 resources 에 무엇을 쓰는지 확인하고, 쿼터는 손대지 못하게 남겨 두세요.

두 번째 테넌트와 격리 증명

같은 패턴으로 두 번째 테넌트를 만드세요 — 네임스페이스 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-blueblue-devtenant-green 에는 WebService 를 만들 수 없어야 합니다.

같은 패턴을 한 번 더 적용하는 것이 플랫폼입니다. 그리고 첫 테넌트의 권한이 두 번째 테넌트에는 닿지 않아야 합니다.