이전 글에서 CRD(CustomResourceDefinition) 를 만들어 Ticket 같은 커스텀 리소스를 Kubernetes API에 등록하면,
kubectl apply/get/delete로 리소스 생성/조회/삭제- 리소스 데이터는 etcd에 저장
까지는 가능하다고 했습니다.
하지만 여기서 중요한 질문이 남습니다.
“Ticket 리소스를 만들면, 실제로 항공권 예약 API(booking API)를 호출해서 예약/변경/취소를 자동으로 수행하게 하려면?”
이 “실제 행동”은 Kubernetes가 CRD만으로 해주지 않습니다.
그 역할을 하는 것이 바로 커스텀 컨트롤러(Custom Controller) 입니다.
1) 컨트롤러란 무엇인가
컨트롤러는 한마디로:
- Kubernetes 클러스터(정확히는 API Server의 오브젝트 상태)를 지속적으로 관찰(watch)
- 특정 리소스(여기서는 Ticket)의 생성/변경/삭제 이벤트를 받아
- “원하는 상태(Desired State)”를 “현재 상태(Actual State)”로 맞추도록 조정(reconcile) 하는 프로세스입니다.
Deployment를 만들면 Pod가 자동으로 맞춰지는 것도 같은 원리입니다.
- Deployment 오브젝트는 etcd에 저장될 뿐이고
- 실제로 ReplicaSet/Pod를 생성해 상태를 맞추는 건 Deployment Controller 입니다.
Ticket도 똑같습니다.
- Ticket 오브젝트는 etcd에 저장될 뿐이고
- 실제로 외부 예약 API를 호출해 예약/변경/취소를 수행하는 건 Ticket Controller 입니다.
2) “그럼 Python으로도 컨트롤러 만들 수 있지 않나?”
가능합니다. 예를 들어 Python으로:
- Kubernetes API를 주기적으로 조회(polling)하고
- 변경을 감지해서
- 외부 API를 호출하는 방식
으로도 만들 수 있습니다.
다만 강의에서 말한 것처럼, 이런 방식은 실무에서 곧 어려워집니다.
- 이벤트 기반 처리/재시도/중복처리 방지(멱등성)
- 캐시(cache)와 큐(queue) 설계
- 리소스 변경이 폭주할 때의 rate limiting
- 워치(watch) 끊김 처리, 리스트-워치(list-watch) 패턴 등
그래서 Kubernetes 생태계에서는 보통 Go 기반 라이브러리(client-go / controller-runtime) 를 사용해 컨트롤러를 만드는 게 표준에 가깝습니다.
3) Go로 컨트롤러를 만들면 뭐가 편해지나 (핵심만)
Go 기반 컨트롤러는 보통 아래 구조로 동작합니다.
- Informer(Shared Informer)
- API Server를 계속 polling하지 않고
- list + watch 기반으로 이벤트를 받고
- 로컬 캐시를 유지
- Workqueue
- 이벤트를 바로 처리하지 않고 큐에 넣어
- 순서/재시도/Rate limit을 관리
- Reconcile Loop
- “현재 Ticket의 상태를 읽고 → 필요한 외부 동작 수행 → status 업데이트”를 반복
- 컨트롤러는 “한 번만 실행”이 아니라 계속 루프를 돌며 상태를 맞춥니다.
컨트롤러 구현에서 가장 중요한 실무 원칙은 딱 2개입니다.
- 멱등성(idempotency): 같은 이벤트가 여러 번 와도 결과가 깨지지 않게
- status로 상태를 기록: spec은 사용자의 의도, status는 컨트롤러의 결과/진행상태
4) 커스텀 컨트롤러 개발 시작 방법 (강의 흐름 그대로)
강의에서는 “샘플 컨트롤러(sample-controller) 레포지토리”를 예로 듭니다. 흐름은 다음과 같습니다.
4.1 준비물
- Go 설치
- GitHub에서 sample-controller clone
git clone <sample-controller-repo-url>
cd sample-controller
4.2 코드 커스터마이징
controller.go같은 파일에서- Ticket 리소스 생성/변경/삭제를 감지했을 때
- 외부 예약 API를 호출하도록 커스터마이징합니다.
강의는 여기서 “코드 디테일”을 깊게 다루진 않고, 큰 흐름을 이해하는 데 집중합니다.
4.3 로컬에서 실행(개발 단계)
로컬에서 컨트롤러를 실행할 수도 있습니다. 이때 컨트롤러가 클러스터에 인증하기 위해 kubeconfig가 필요합니다.
# 예시: kubeconfig 지정
export KUBECONFIG=~/.kube/config
# 실행(레포 구조에 따라 go run ./... 또는 go run main.go 등)
go run .
이렇게 실행해두고, 다른 터미널에서 Ticket CR을 만들면:
kubectl apply -f my-ticket.yaml
컨트롤러가 Ticket 이벤트를 감지하고 외부 예약 API 호출 로직을 수행하는 형태입니다.
5) 컨트롤러를 “클러스터 안에서” 배포하기 (실무에서 대부분 이렇게 함)
매번 로컬에서 go run 하기보다는, 컨트롤러를 Docker 이미지로 패키징한 뒤 Deployment로 띄우는 방식이 일반적입니다.
5.1 컨트롤러 이미지 빌드/푸시(개념)
docker build -t myrepo/ticket-controller:0.1 .
docker push myrepo/ticket-controller:0.1
5.2 컨트롤러는 어떤 인증으로 API Server에 붙나?
클러스터 내부 Pod로 실행하면 컨트롤러는 kubeconfig 대신 보통 ServiceAccount 토큰(in-cluster config) 으로 API Server에 인증합니다.
즉, 컨트롤러 배포에는 거의 항상 다음이 같이 따라옵니다.
- ServiceAccount
- (Cluster)Role / (Cluster)RoleBinding (컨트롤러가 무엇을 읽고/쓰는지)
- Deployment
예시(개념용, 최소 형태):
apiVersion: v1
kind: ServiceAccount
metadata:
name: ticket-controller-sa
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ticket-controller-role
rules:
- apiGroups: ["flights.com"]
resources: ["tickets"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["flights.com"]
resources: ["tickets/status"]
verbs: ["update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ticket-controller-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ticket-controller-role
subjects:
- kind: ServiceAccount
name: ticket-controller-sa
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ticket-controller
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: ticket-controller
template:
metadata:
labels:
app: ticket-controller
spec:
serviceAccountName: ticket-controller-sa
containers:
- name: controller
image: myrepo/ticket-controller:0.1
포인트: 컨트롤러는 보통
tickets/status업데이트도 해야 하므로 status 권한을 별도로 포함하는 경우가 많습니다.
6) Operator Framework: CRD + Controller를 “하나의 설치 단위”로 패키징
여기까지 보면 커스텀 리소스를 쓰려면 보통 이렇게 해야 합니다.
- CRD 적용
- CR 생성
- 컨트롤러 배포(Deployment, RBAC, SA 등)
즉, CRD와 컨트롤러가 별개의 엔티티이고 설치/업데이트도 따로 관리해야 합니다.
6.1 Operator가 하는 일(핵심)
Operator는 보통 다음을 “한 패키지”처럼 제공합니다.
- CRD
- Controller(Deployment)
- RBAC/ServiceAccount
- 설치/업그레이드 매니페스트(버전 관리)
그래서 “Flight Operator”를 설치하면:
- CRD가 설치되고
- 컨트롤러가 같이 배포되며
- 사용자는 CR만 만들면 되도록 구성되는 방향입니다.
6.2 Operator는 단순 설치를 넘어 “운영 작업”까지 자동화
강의에서 예로 든 etcd operator 같은 경우(개념적으로):
- 클러스터 설치/스케일링/업그레이드
- 백업 생성
- 복구(restore)
- 장애 감지 후 조치
처럼 사람이 하던 운영 절차를 코드로 자동화하는 방향이 Operator의 목표입니다.
7) OperatorHub / OLM(Operator Lifecycle Manager) 흐름(강의 수준 요약)
강의에서 말하는 설치 흐름은 대략 이 패턴입니다.
- OLM 설치
- Operator 설치(구독/설치 지침 따라)
- CR 생성하면 Operator가 알아서 애플리케이션을 구성
여기서 중요한 메시지는:
- Operator는 “CRD+Controller”를 묶어 배포/업데이트/수명주기 관리까지 쉽게 해주는 생태계라는 점입니다.
- 다만 강의에서도 말하듯, Operator 자체는 깊게 들어가면 별도의 코스가 필요할 정도로 주제가 커집니다.
8) 시험 관점 메모(강의 톤 유지)
강의에서는 보통:
- CRD 작성/조회/다루는 문제는 나올 수 있다
- 커스텀 컨트롤러를 직접 코딩하라는 문제는 보통 기대하지 않는다
라는 뉘앙스를 줍니다.
실무에서는 “컨트롤러/오퍼레이터를 만들고 운영”하는 일이 중요하지만, 자격시험에서는 대개 CRD 리소스 모델 이해 쪽이 더 중심이 됩니다.
9) 정리
- CRD: Kubernetes에 “새 리소스 타입”을 등록 → 저장/조회/삭제 가능
- Custom Controller: 그 리소스의 변화를 감시하고 실제 행동(외부 API 호출 등)을 수행
- 컨트롤러는 보통 Go(client-go/controller-runtime)로 작성하는 게 표준에 가깝고, watch/queue/cache 기반으로 동작
- Operator: CRD + Controller + RBAC + 배포 매니페스트를 “하나의 설치 단위”로 패키징하고, 운영 자동화까지 확장하는 개념
'CKA' 카테고리의 다른 글
| Storage - Docker의 Storage (0) | 2026.01.03 |
|---|---|
| Security - 정리(2) (1) | 2026.01.02 |
| Security - Custom Resource Definition (0) | 2026.01.02 |
| Security - Context & 네임스페이스 전환을 빠르게 하는 도구 (0) | 2026.01.02 |
| Security - NetworkPolicy (0) | 2026.01.02 |