Kubernetes를 쓰다 보면 “Deployment/Service 같은 내장 리소스 말고, 우리 도메인에 맞는 오브젝트를 Kubernetes에 등록해서 kubectl로 관리하고 싶다”는 요구가 생깁니다. 예를 들어 항공권(Ticket) 이라는 오브젝트를 만들어서 kubectl apply/get/delete로 관리하면서 “실제로 항공권 예약 API를 호출”하도록 자동화하고 싶을 수 있습니다.
이때 핵심 구성은 3가지입니다.
- CRD (CustomResourceDefinition): Kubernetes API에 “새로운 리소스 타입”을 등록하는 스키마/정의
- CR (Custom Resource): CRD로 등록된 타입으로 실제 생성하는 오브젝트 인스턴스
- Custom Controller (Operator): 해당 리소스(CR)의 생성/변경/삭제를 감시하고 실제 동작을 수행하는 프로세스
요약하면:
CRD만 있으면 “etcd에 저장/조회/삭제”까지만 되고, 실제 행동(예약/삭제 API 호출 등)은 “컨트롤러”가 있어야 한다.
1) Kubernetes 리소스와 컨트롤러: Deployment 예시로 이해
Deployment YAML을 생성하면 Kubernetes는:
- API Server가 Deployment 오브젝트를 저장(etcd)
- Deployment Controller가 그 상태를 감시
- 원하는 상태(예: replicas=3)를 만족하도록 ReplicaSet/Pod 생성
즉, “리소스(데이터)”와 “컨트롤러(동작)”가 짝입니다.
- 리소스: etcd에 저장되는 선언(Desired State)
- 컨트롤러: 선언을 보고 실제 상태(Actual State)를 원하는 상태로 맞추는 프로세스(reconciliation loop)
2) “Ticket” 같은 도메인 오브젝트를 Kubernetes 리소스로 만들고 싶다
예를 들어 아래처럼 Ticket을 만들고 싶다고 가정합니다.
apiVersion: flights.com/v1
kind: Ticket
metadata:
name: my-ticket
spec:
from: mumbai
to: london
number: 2
원하는 경험:
kubectl apply -f ticket.yaml하면 Ticket 생성kubectl get tickets하면 목록 조회kubectl delete ticket my-ticket하면 삭제
하지만 지금 상태에서 바로 만들면 보통 이런 에러가 납니다.
- “
flights.com/v1에Ticket리소스가 없다” (Kubernetes API에 등록되지 않았으니)
그래서 먼저 “이런 리소스 타입을 앞으로 만들 거다”를 Kubernetes에 등록해야 합니다. 이 역할이 CRD입니다.
3) group은 왜 flights.com 같은 형태로 쓰나?
apiVersion: flights.com/v1에서 앞부분인 flights.com이 API group입니다.
- group은 “이 리소스가 속한 API 네임스페이스” 입니다.
- Kubernetes 내장 리소스도
apps,batch,networking.k8s.io같은 group으로 나뉩니다. - 커스텀 리소스는 충돌을 피하기 위해 보통 DNS 서브도메인 형태(조직/프로젝트 도메인 기반) 로 group을 잡습니다.
- 예:
cert-manager.io,monitoring.coreos.com같은 식
- 예:
- 실제로 API 경로에도 영향을 줍니다:
flights.comgroup이면 대략/apis/flights.com/...형태로 노출됩니다.
즉, group을 저렇게 잡는 이유는 고유성(충돌 방지) + 관리 주체 명확화 때문입니다.
4) CRD(CustomResourceDefinition)로 리소스 타입 등록하기
CRD는 “Kubernetes API 확장”을 위한 오브젝트입니다.
apiVersion: apiextensions.k8s.io/v1kind: CustomResourceDefinition
CRD에서 정의해야 하는 핵심은:
(1) scope: Namespaced vs Cluster
- Namespaced: Pod/Deployment처럼 네임스페이스에 속하는 리소스
- Cluster: Node/PV/Namespace처럼 클러스터 범위 리소스
Ticket은 보통 환경/팀 단위로 격리하고 싶으니 Namespaced로 두는 편이 자연스럽습니다.
(2) group / names / versions
- group:
flights.com - kind:
Ticket - plural:
tickets - singular:
ticket - shortNames:
tk(옵션) - versions:
v1등
(3) schema(OpenAPI v3)
spec 아래에 어떤 필드를 받을지, 타입은 뭔지, 최소/최대값 같은 검증까지 정의합니다.
5) (간단 버전) version은 왜 필요하나?
버전은 “API가 발전하면서 스키마가 바뀔 수 있기 때문에” 둡니다.
- 처음엔
v1alpha1로 시작해 실험/변경을 빠르게 하고 - 안정화되면
v1beta1 - 충분히 안정적이면
v1(stable)로 가는 패턴이 흔합니다.
CRD에서는 버전별로 “이 버전을 제공(serve)할지”, “etcd에 어떤 버전으로 저장(storage)할지”를 지정할 수 있습니다. (보통 storage는 하나만)
처음 글 관점에서는 “버전은 리소스 스펙의 진화와 호환성을 위한 장치” 정도로 이해하면 충분합니다.
6) 실전 예제: Ticket CRD YAML
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: tickets.flights.com
spec:
group: flights.com
scope: Namespaced
names:
plural: tickets
singular: ticket
kind: Ticket
shortNames:
- tk
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required: ["from", "to", "number"]
properties:
from:
type: string
to:
type: string
number:
type: integer
minimum: 1
maximum: 10
적용:
kubectl apply -f ticket-crd.yaml
kubectl api-resources | grep -i ticket
7) 이제 Ticket(CR)을 생성/조회/삭제할 수 있다
Ticket 오브젝트(= CR):
apiVersion: flights.com/v1
kind: Ticket
metadata:
name: my-ticket
spec:
from: mumbai
to: london
number: 2
kubectl apply -f my-ticket.yaml
kubectl get tickets
kubectl delete ticket my-ticket
여기까지 하면 “Kubernetes가 Ticket을 저장/조회/삭제”는 해줍니다.
하지만 “실제로 항공권 예약 API를 호출해서 예약이 되지는 않습니다.”
왜냐하면 아직 Ticket을 보고 행동하는 컨트롤러가 없기 때문입니다.
8) CRD만으로는 “기능”이 없다: 컨트롤러(Operator)가 해야 하는 일
CRD/CR은 Kubernetes 입장에서는 “새로운 타입의 데이터”일 뿐입니다.
진짜로 “Ticket을 만들면 booking API를 호출해서 예약한다” 같은 동작은 Custom Controller가 수행합니다.
- Ticket 생성 감지 → 외부 예약 API 호출 → 결과를 기록
- Ticket 삭제 감지 → 예약 취소 API 호출
- Ticket 변경 감지 → 예약 변경 API 호출(가능한 경우)
이 조합을 보통 Operator 패턴이라고 부릅니다.
9) 정리
- Kubernetes의 리소스는 etcd에 저장되는 오브젝트(데이터)
- 컨트롤러는 그 오브젝트를 감시하며 실제 상태를 맞추는 프로세스(행동)
- CRD로 “새 리소스 타입”을 Kubernetes API에 등록
- group은 보통 도메인 기반으로 잡아 충돌을 피하고 관리 주체를 명확히
- version은 스펙의 “진화/호환성”을 위한 장치
- CR로 인스턴스를 생성하면 저장/조회/삭제는 가능
- 실제 동작은 Custom Controller(Operator) 가 수행
'CKA' 카테고리의 다른 글
| Security - 정리(2) (1) | 2026.01.02 |
|---|---|
| Security - Custom Controller & Operator (0) | 2026.01.02 |
| Security - Context & 네임스페이스 전환을 빠르게 하는 도구 (0) | 2026.01.02 |
| Security - NetworkPolicy (0) | 2026.01.02 |
| Security - 도커 보안 기초 + 쿠버네티스의 Security Context (0) | 2026.01.02 |