Chapter 18

쿠버네티스 확장

  • 18.1 CustomResourceDefinition으로 새 리소스 만들기
  • 18.2 Service Catalog — 외부 서비스를 K8s 자원처럼
  • 18.3 K8s 위에 만든 플랫폼들 — OpenShift, Deis, Helm

마지막 장이야. 책 전체에서 배운 K8s가 "끝"이 아니라 "기반"이라는 걸 보여주는 장이지. K8s가 이 정도로 빠르게 표준이 된 진짜 이유는 확장 가능하기 때문이야. KServe·Knative·Istio가 K8s를 뼈대로 쓰는 것도 같은 메커니즘이거든 — CRD + Controller, 그리고 그 위의 플랫폼.

먼저 CustomResourceDefinition. 지금까지 본 Pod, Service, Deployment, ConfigMap은 저수준 일반 개념이야. 실무에선 더 도메인스러운 개념이 필요해져 — "메시지 큐", "데이터베이스 인스턴스", "ML 학습 잡" 같은 거. 이걸 K8s 리소스로 만들 수 있게 해주는 게 CRD야. 책 시점 v1.7 이전엔 ThirdPartyResource였고 1.8에서 CRD로 교체됐어.

CRD를 만들 때는 apiVersion: apiextensions.k8s.io/v1, kind: CustomResourceDefinition으로 시작해서 metadata.nameplural.group 형식(예: websites.extensions.example.com)으로 적어. spec에는 group, scope(Namespaced 또는 Cluster), versions, names(kind, singular, plural)를 적고. CRD 이름이 plural.group 형식인 이유는 충돌 방지야. 이걸 kubectl apply하면 그 순간부터 클러스터는 Website 리소스를 알아먹고 저장·조회·삭제가 가능해져. 단 — 저장만 해. 아무 일도 안 일어나.

CRD는 그릇일 뿐이야. 실제로 뭔가 일어나려면 그 객체를 watch하면서 반응하는 컨트롤러가 필요해. 이게 Operator pattern의 출발점이야. 컨트롤러 동작은 단순해 — API 서버에 ?watch=true로 long-polling을 걸고, ADDED 이벤트 받으면 Deployment(예를 들면 nginx + git-sync 사이드카)와 Service(NodePort)를 생성하고, DELETED 이벤트 받으면 해당 리소스들을 삭제해. 컨트롤러는 보통 파드로 배포해. 내부에서 직접 API 서버 통신을 하거나, ambassador 패턴으로 같은 파드 안의 kubectl proxy 사이드카를 통해 호출해(인증·TLS를 proxy에 위임). 이 패턴을 잘 만든 게 지금의 Operator 생태계야 — Prometheus Operator(Prometheus, ServiceMonitor CRD), cert-manager(Certificate, Issuer CRD), Strimzi(Kafka), Postgres Operator, KServe(InferenceService), Argo(Workflow) 같은 거.

검증의 한계도 짚어두면, 책 시점엔 CRD에 스키마 검증이 거의 없어서 잘못된 필드도 통과했지만, 현재는 OpenAPI v3 schema를 CRD에 박을 수 있어. schema.openAPIV3Schema에 type, properties, required 같은 걸 정의하면 잘못된 필드면 API 서버가 즉시 거부해. 이게 운영성을 결정적으로 올렸어. 그리고 CRD 대신 자체 API 서버를 띄우고 메인 API 서버에 등록(APIService 리소스)하는 방법도 있어. 이게 Aggregated API Server 방식인데, 클라이언트는 메인 API 서버에 요청하고 그게 알아서 forwarding해. metrics-server, 일부 Service Catalog 구현이 이 방식을 써. CRD보다 복잡하지만 자체 검증·스토리지를 가질 수 있어 더 유연해.

다음은 Service Catalog. 참고로 Kubernetes Service Catalog 프로젝트는 사실상 archived됐어. 이 절은 컨셉만 이해하면 돼. 현재의 동등한 패턴은 Crossplane, AWS Controllers for K8s(ACK), Operator로 외부 자원 관리 같은 거야. 컨셉은, "파드에서 PostgreSQL 쓰고 싶다"고 하면 누군가 DB를 띄우고 접속 정보를 Secret에 넣고 알려줘야 하잖아. Service Catalog는 이걸 셀프 서비스로 만들어. 사용자는 "이 카탈로그에서 free PostgreSQL 하나 줘" 하고, 클러스터 외부의 broker가 실제 프로비저닝을 해.

4가지 리소스가 있어. ClusterServiceBroker(외부 서비스 제공자 등록), ClusterServiceClass(broker가 제공할 수 있는 서비스 종류, 자동 생성), ServiceInstance(사용자가 만드는 "이거 하나 띄워줘" 요청), ServiceBinding(그 인스턴스의 접속 정보를 Secret으로 만들기). broker는 표준 REST API(GET /v2/catalog, PUT /v2/service_instances/:id 같은 거)를 구현해야 해. 이게 OpenServiceBroker(OSB) API야 — 클라우드 벤더 중립적 표준이지. 흐름은 admin이 ClusterServiceBroker 등록 → Service Catalog가 broker에 catalog 요청 → ClusterServiceClass 자동 생성 → 사용자가 ServiceInstance 만들기 → broker가 실제 자원 프로비저닝 → 사용자가 ServiceBinding 만들기 → broker가 credential 반환 → Secret 생성 → 파드가 그 Secret을 마운트해서 사용. 이 패턴 자체는 살아있어 — Crossplane이 같은 아이디어를 더 K8s 네이티브하게 구현했거든. 클라우드 리소스(RDS, S3, GCS)를 K8s 리소스로 표현하고 컨트롤러가 클라우드 API를 호출해. 멀티 클라우드 추상화의 표준 접근이야.

마지막으로 K8s 위에 만든 플랫폼들. OpenShift는 Red Hat이 K8s 위에 얹은 PaaS야. 개발자 경험에 집중했고, K8s 등장 후 v3부터는 K8s 위에 재구축됐어 (그만큼 K8s가 표준이 됐다는 뜻이지). 추가 리소스들이 있는데, User / Group / Project는 RBAC 이전부터 있었던 멀티테넌트 기능이고 Project는 어노테이션 붙은 Namespace야. Template은 파라미터화 가능한 매니페스트 묶음(지금은 Helm/Kustomize에 흡수된 컨셉), BuildConfig는 Git push만 해도 OpenShift가 코드를 빌드해서 이미지를 생성해주는 거고 **Source-to-Image(S2I)**가 코드 종류(pom.xml이면 Maven 등)를 자동 인식해. ImageStream은 빌드된 이미지의 스트림이고 새 이미지가 들어오면 트리거되고, DeploymentConfig는 Deployment의 OpenShift 선조로 ImageStream을 watch해서 새 이미지 나오면 자동 롤아웃을 해. Route는 Ingress의 선조인데 TLS termination, traffic split까지 내장돼 있어. 핵심은 Git push → 자동 빌드 → 자동 배포까지 클러스터 안에서 완결된다는 거야. CI/CD 도구를 따로 안 붙여도 돼.

Deis Workflow는 마이크로소프트 인수 후 사실상 종료됐지만, Helm은 살아남아 K8s 패키지 매니저의 표준이 됐어. Helm은 CLI + Tiller(서버 컴포넌트, 책 시점) 구조였는데 Tiller는 Helm v3에서 제거됐어 — 현재는 클라이언트만 있고 K8s에 직접 통신해. 개념은 Chart(매니페스트 템플릿 묶음, 패키지), Config(values.yaml의 값들), Release(Chart + Config의 실행 인스턴스)로 구성돼. helm install my-database stable/mysql 한 줄로 MySQL 띄우는 데 필요한 Deployment, Service, Secret, PVC가 다 만들어져. 자기가 직접 매니페스트 짜지 마 — 누군가 이미 만들어둔 차트가 거의 항상 있어. 지금은 Artifact Hub(artifacthub.io)가 차트 검색의 표준 장소야. Helm Chart는 Operator 설치, 모니터링 스택 배포, EFK 설치 등 거의 모든 곳에서 써.

CRD/Operator vs Helm 언제 뭘 쓰냐면, Helm은 "이미 만들어진 매니페스트들을 한 번에 배포"하는 패키지 매니저야. 정적 리소스를 묶어 배포할 때 쓰고. **Operator(CRD + Controller)**는 "동작하는 무언가"가 필요할 때 써. 파드 죽었을 때 데이터 이전, 백업 자동화, 클러스터 리밸런싱 같은 운영 지식을 코드로 표현하는 거야. 둘은 경쟁이 아니라 보완이야. 보통 Operator도 Helm 차트로 설치해.


정리

18장 읽고 기억할 거 세 가지:

  1. CRD + Controller가 K8s 확장의 본질이다. 직접 만든 도메인 객체(Website, InferenceService, Certificate 등)를 API 서버에 등록하고, 그걸 watch하는 컨트롤러가 저수준 리소스로 변환. 이게 Operator pattern이고, 지금 K8s 생태계의 거의 모든 고급 기능(Prometheus, cert-manager, Strimzi, KServe, Argo)이 이 방식으로 동작한다. CRD에 OpenAPI 스키마를 박아 검증하는 게 운영 필수.
  2. 외부 자원도 K8s 객체처럼 다루는 패턴이 산업 표준이 됐다. 책의 Service Catalog는 archived됐지만, 같은 아이디어가 Crossplane, ACK, 각 클라우드의 Operator로 이어진다. "DB든 S3 버킷이든 K8s YAML로 선언하면 생긴다"가 멀티 클라우드/IaC 통합의 방향.
  3. Helm은 매니페스트 직접 작성을 거의 지워버렸다. 운영 환경에서 PostgreSQL, Kafka, Prometheus, ELK 같은 걸 직접 매니페스트로 짜는 건 시간 낭비. Artifact Hub에서 이미 잘 다듬어진 차트를 쓰고 values.yaml만 조정. Helm은 단순 배포(정적 묶음)고, 운영 지식이 필요한 건 Operator — 둘은 보완 관계라는 것도 기억.

책 전체 마무리

Kubernetes in Action 18장 완주. 이 책의 진짜 가치는 1~10장의 사용자 매뉴얼이 아니라, **11장 이후의 "왜 이렇게 동작하는가"**다. K8s 기반 플랫폼을 운영하거나 디버깅할 때 이 책의 내용을 알고 있으면 "왜 파드가 Pending이지?", "왜 종료가 graceful하지 않지?", "왜 HPA가 안 도지?" 같은 질문에서 추측이 아니라 진단을 할 수 있게 된다. 그게 이 책이 시간이 지난 지금도 추천되는 이유.