1. CRD 정의하기
todo-crd.yaml 파일을 만들어서 다음 내용을 저장:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: todos.example.com
spec:
group: example.com
# group: example.com
# 이 리소스가 속한 API 그룹 이름입니다.
# 기본 쿠버네티스 리소스는 보통 apps, batch, core 등의 그룹을 가지는데
# 여기서는 사용자가 정의한 example.com 그룹입니다.
# 실제로 사용할 때는 이런 식으로 씁니다:
# 최상위 선언 예) apiVersion: example.com/v1
kind: Todo
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
task:
type: string
done:
type: boolean
scope: Namespaced
names:
plural: todos
singular: todo
kind: Todo
shortNames:
- td
✅ 이제 쿠버네티스는 Todo라는 새로운 리소스 타입을 인식하게 된다.
$ kubectl get crd
2. CR(Custom Resource) 생성하기
이제 우리가 만든 타입으로 “객체”를 만들어 보자.
todo-sample.yaml 파일:
apiVersion: example.com/v1
kind: Todo
metadata:
name: buy-milk
spec:
task: "Buy some milk"
done: false
3. 생성 CR 내용 보기
결과 예시:
apiVersion: example.com/v1
kind: Todo
metadata:
name: buy-milk
spec:
task: "Buy some milk"
done: false
4. 파라미터 업데이트 테스트
이제 “할 일 완료”로 변경:
kubectl patch todo buy-milk --type merge -p '{"spec":{"done":true}}'
✅ done: true 로 바뀐 걸 확인.
5. CR만 있을 때
- 그냥 저장된 데이터 덩어리.
- 예제: Todo CR 안에 task랑 done 값이 저장되어 있음
- kubectl get todo / kubectl edit todo로 조회·수정 가능
- 쿠버네티스는 데이터 구조를 검증하고 저장해주는 역할만 함
- 실제 동작(자동 삭제, 알림 발송 등)은 안 일어남
6. CR + 컨트롤러의 연동
컨트롤러 / 오퍼레이터를 만들면 CR을 액션과 연결할 수 있다.
예를 들어:
CR 동작 | 컨트롤러 처리 |
done: true | “이 Todo 삭제” |
task: "Deploy app" | 실제 Deployment 생성 |
새로운 Todo 생성 | Slack 알림 전송 |
즉, CRD+CR은 데이터 정의와 데이터, 컨트롤러는 행동 정의라고 생각하면 이해가 쉽다
비유
- CRD = “상품의 설계도”
- CR = “실제 만든 상품”
- 컨트롤러 = “상품이 만들어지면 자동으로 포장, 배송, 알림까지 처리해주는 로봇”
7. Todo CRD + CR + 컨트롤러 예제
Todo가 done: true가 되면 자동으로 삭제하는 컨트롤러를 만들어보겠다.
Python과 kopf 라이브러리를 사용하면 쉽게 가능
# 파이썬 가상환경 셋업
python -m venv venv
source venv/bin/activate
# Kubernetes Operator Framework for Python 쿠버네티스 API 라이브러리
pip install kopf kubernetes
7-1. 위에서 만든 CRD인 todo-crd.yaml 생성:
$ kubectl apply -f todo-crd.yaml
7-2. 위에서 만든 CR인 todo-sample.yaml 생성:
$ kubectl apply -f todo-sample.yaml
7-3. 조회:
$ kubectl get todos
7-4. Python controller 생성
import kopf
from kubernetes import client, config
# 로컬 테스트 시
config.load_kube_config()
@kopf.on.create('example.com', 'v1', 'todos')
def todo_create(spec, name, namespace, **kwargs):
print(f"New Todo created: {name} - {spec['task']}")
@kopf.on.update('example.com', 'v1', 'todos')
def todo_update(spec, name, namespace, **kwargs):
if spec.get('done', False):
print(f"Todo done! Deleting: {name}")
api = client.CustomObjectsApi()
api.delete_namespaced_custom_object(
group="example.com",
version="v1",
namespace=namespace,
plural="todos",
name=name,
)
7-5. 컨트롤러 실행 (Python)
$ kopf run todo_controller.py
kopf run todo_controller.py
/home/sunsh/k8s/study_crd/todo/venv/lib/python3.10/site-packages/kopf/_core/reactor/running.py:180: FutureWarning: Absence of either namespaces or cluster-wide flag will become an error soon. For now, switching to the cluster-wide mode for backward compatibility.
warnings.warn("Absence of either namespaces or cluster-wide flag will become an error soon."
[2025-10-13 15:36:11,284] kopf._core.engines.a [INFO ] Initial authentication has been initiated.
[2025-10-13 15:36:11,290] kopf.activities.auth [INFO ] Activity 'login_via_client' succeeded.
[2025-10-13 15:36:11,290] kopf._core.engines.a [INFO ] Initial authentication has finished.
New Todo created: buy-milk - Buy some milk
[2025-10-13 15:36:11,415] kopf.objects [INFO ] [default/buy-milk] Handler 'todo_create' succeeded.
[2025-10-13 15:36:11,415] kopf.objects [INFO ] [default/buy-milk] Creation is processed: 1 succeeded; 0 failed.
# buy-milk의 done: true로 변경
kubectl patch todo buy-milk --type merge -p '{"spec":{"done":true}}'
# controller에서 변경사항을 인지
Todo done! Deleting: buy-milk
[2025-10-14 10:09:34,806] kopf.objects [INFO ] [default/buy-milk] Handler 'todo_update' succeeded.
[2025-10-14 10:09:34,806] kopf.objects [INFO ] [default/buy-milk] Updating is processed: 1 succeeded; 0 failed.
if spec.get('done', False):
# buy-milk CR 삭제 완료
CRD를 정의하고, CR을 생성하면 CR 값의 변화에 따라
Controller(Python kopf)에서 인지하고, 정의한 행위를 실행한다.
CRD + Controller를 합쳐서 Operator라고 한다.
8. 배포 방식
구성 요소 | 역할 | 예시 |
① CRD (CustomResourceDefinition) | 새로운 리소스 타입 정의 | Todo 타입 정의 (todos.example.com) |
② Controller (Deployment or Pod) | CR을 감시하고 처리하는 컨트롤러 | kopf나 Go 기반 operator |
③ CR (Custom Resource) | 실제 데이터 객체 | buy-milk, deploy-app 같은 실제 Todo |
8-1. Helm 차트 / Kustomize / 매니페스트 묶음
보통은 Operator를 설치 단위(패키지)로 묶어 배포합니다.
예를 들어 디렉터리 구조는 이렇게 됩니다.
todo-operator/
├── crd/
│ └── todo-crd.yaml
├── controller/
│ └── deployment.yaml
└── examples/
└── todo-sample.yaml
배포 명령:
(manifest 묶음) kubectl apply -f my-operator/
- CRD 등록
- 컨트롤러 Pod(Deployment) 생성
- 샘플 CR 생성
이 세 가지가 순서대로 한 번에 적용됩니다.
8-2. Operator Lifecycle Manager (OLM)
- 쿠버네티스에서 Operator들을 앱처럼 관리할 수 있게 하는 공식 관리 시스템
- OLM은 CRD, Controller, RBAC, ServiceAccount 등 모든 리소스를 묶어서 “하나의 Operator 번들(package)” 로 관리합니다.
- 예시:이 한 줄로 전체 Operator를 설치할 수 있음.
- kubectl apply -f todo-operator-bundle.yaml
비교 항목매니페스트 묶음Helm 차트
배포 명령 | kubectl apply -f | helm install |
템플릿 변수 | ❌ 없음 | ✅ 지원 (values.yaml) |
버전 관리 | 수동 | 자동 (helm upgrade, rollback 등) |
패키징 | 단순 폴더 | .tgz 패키지 |
실제 내부 동작 | API 서버에 YAML 적용 | 동일 (렌더링 후 apply) |
'Kubernetes > K8s' 카테고리의 다른 글
쿠버네티스 리소스(기본 + 커스텀)는 공통 구조 (0) | 2025.10.13 |
---|---|
클러스터가 파드를 제어하는 방식 (0) | 2025.08.26 |
ServiceAccount (1) | 2025.08.26 |
[K8s] 가상 IP 및 서비스 프록시 (1) | 2025.06.18 |
[K8s] Controler-node ip가 변경될 경우 (0) | 2025.06.18 |