쿠버네티스의 확장 기능인 커스텀 리소스와 커스텀 컨트롤러에 대해 알아보자.
Controller와 선언형 리소스
쿠버네티스의 모든 리소스는 선언형으로 관리된다. 그리고 모든 쿠버네티스 리소스는 다음의 형식을 띈다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: account-service
namespace: saga
labels:
...
annotations:
...
spec:
...
status
...
- apiVersion: 리소스 API 버전
- kind: 리소스 종류
- metadata: 리소스 메타데이터로, 특정 리소스를 식별하기위해 사용
- spec: 리소스의 의도한 상태
- status: 리소스의 현재 상태, 쿠버네티스는 리소스의 현재 상태를 의도한 상태로 변경하려고 지속적으로 작업한다.
그리고 쿠버네티스에는 Controller Manager가 내장되어있다. Controller Manager는 쿠버네티스가 기본으로 제공해주는 API (Deployment, CronJob, ...) 에 대한 컨트롤러의 집합체이다. 여기에 내장된 컨트롤러들은 쿠버네티스의 리소스 상태를 주기적으로 확인하여 현재 status를 spec으로 맞추기 위한 작업을 지속적으로 수행한다.
쿠버네티스에서 가장 간단한 배포 단위인 Deployment를 예를 들어보자. Deployment는 특정 스펙을 만족하는 파드를 여러개 (replicas) 배포함과 동시에 버전 관리 및 롤링배포 등을 지원한다. 사용자가 kubectl 등으로 Deployment를 생성하면 API Server가 요청을 받아서 ETCD에 Deployment를 저장한다.

그리고 Controller Manager는 주기적으로 Deployment의 상태를 체크하여 status를 spec으로 맞추기 위한 작업을 수행한다. 컨트롤러는 먼저 Deployment의 상태를 확인한 후 ReplicaSet이 없다면 ReplicaSet을 생성하게 된다.

컨트롤러는 주기적으로 ReplicaSet을 확인한 후 ReplicaSet의 replicas 갯수만큼 Pod를 유지시킨다. (증설 or 감축)

처음에는 Pod가 없기 때문에 Pod가 생성되는데, 생성된 Pod는 Scheduler에 의해 적절한 노드로 스케줄링되며, kubelet에 의해 파드 스펙에 맞게 컨테이너가 구동된다. 그리고 kubelet은 주기적으로 파드 상태를 확인하여 API Server에 보고한다.

컨트롤러는 주기적으로 Deployment, ReplicaSet의 상태를 확인하여, Pod 상태를 확인한 뒤 현재 생성된 파드 및 준비된 파드 등의 상태를 변경한다.

이것이 Deployment를 생성했을 때 대략적인 컨트롤러의 흐름이다. 실제로 Controller Manager에는 Deployment, ReplicaSet을 포함한 워크로드 및 Service, PV 등의 인프라 자원에 대한 여러가지 컨트롤러가 포함되어 있다. 이러한 Spec/Status를 가지는 거의 모든 기본 리소스들은 Controller Manager에 의해 관리된다.
Controller 매커니즘
Controller는 내부적으로 다음과 같이 작동한다.

Resource
Controller가 관리하는 리소스이며, 원하는 상태 (Spec)과 현재 상태 (Status)를 기술한다.
API Server
쿠버네티스의 API Server는 먼저 외부에서 쿠버네티스 오브젝트의 생성/삭제/변경 요청을 받으며, 이러한 이벤트가 발생하면 오브젝트를 ETCD에 반영한 후 오브젝트의 이벤트를 컨트롤러에 전달하게 된다. 그리고 컨트롤러가 쿠버네티스 오브젝트의 status를 spec으로 맞추는 작업을 진행할 때에도 API Server를 이용하게 된다.
WorkQueue
API Server 및 컨트롤러에 의해 spec이나 status가 변경된 오브젝트를 저장하는 queue이다.
Reconcile
Controller는 해당 queue에 쌓인 오브젝트의 status를 spec으로 맞추는 작업을 진행한다. 이러한 작업을 reconcile이라고 한다. Controller는 status를 spec으로 맞추기 위한 작업을 수행한 후 변경된 오브젝트의 상태를 API Server를 통해 저장하고, 작업이 완료되지 않았다면 다시 WorkQueue에 적재한다.
Custom Resource와 Custom Controller
쿠버네티스는 확장성이 매우 뛰어나며, 쿠버네티스에서 제공하는 기능 외에도 쿠버네티스 개발자 및 관리자가 직접 선언형 API를 구현할 수 있다. 쿠버네티스에서 선언형 API를 Resource와 Controller로 제공하고 있는데, 직접 선언형 API를 구현하고 싶다면 Custom Resource와 Custom Controller를 만들어야 한다. 즉, Custom Resource와 Custom Controller를 만들면 하면 쿠버네티스 리소스와 같은 방식으로 리소스를 관리할 수 있다는 장점이 있다.
구성 요소
Custom API의 구성요소는 다음과 같다.

Custom Resource
Custom API에 해당하는 리소스이다. 실제 쿠버네티스 리소스와 필드 구성이 같다. 대신에 apiVersion, kind를 직접 지정하여야 하며, spec, status 의 필드를 직접 설계해야 한다.
Custom Controller
직접 설계한 Custom Resource의 상태를 관리하는 컨트롤러 부분이다. Custom Controller를 개발하기 위해서는 Custom Resource를 감시하여 현재 상태(status)를 원하는 상태(spec)으로 조정하는 컨트롤 루프를 작접 구현해야 한다. 언어는 어떤 언어든 상관이 없으며, Kubernetes API Server와 통신하여 Custom Resource를 변경할 수 있어야 하며, 필요에 따라 다른 외부 서버의 자원을 필요로 할 수도 있다.
Custom Resource Definition (CRD)
사실 Kubernetes API Server에서는 Custom Resource에 대해 알지 못한다. 따라서 직접 설계한 Custom Resource를 API Server에게 알려줘야 하는데, Custom Resource를 쿠버네티스에 정의하기 위해서 쿠버네티스는 CRD라는 API를 제공해준다. Custom Resource의 필드 구조를 CRD를 통해 구성하면 된다.
CRD 구성하기
Custom API를 만들기 위해서 가장 먼저 해야할 일은 Custom Resource를 설계하여 CRD를 구성하는 것이다. 하지만 CRD를 구성하는 것은 상당한 노가다가 필요하다. (yaml 상하차) 실제로 Custom API를 설계하고 개발했을 때 spec이 몇십줄 안되는 Custom Resource지만 CRD는 9000줄이 넘었다.

물론 kubebuilder라는 프레임워크를 사용하여 구성했기 때문에 노가다는 하지 않았지만 CRD에는 신경 쓸 것이 많다.
1. API Group, Kind 및 Version
spec:
conversion:
strategy: None
group: cluster-batch.beer1.com
names:
kind: ClusterJob
listKind: ClusterJobList
plural: clusterjobs
singular: clusterjob
scope: Namespaced
versions:
- name: v1alpha
schema:
...
먼저 Custom Resource의 API Group, Kind 및 Version을 지정해줘야 한다.
- Kind는 리소스의 종류를 의미하며 여기서는 ClusterJob이라고 명명하였다. 여기서 listKind는 list API를 사용할 떄의 리소스 종류를 의미하며, plural은 복수형 이름, singular은 단수형 이름으로 보면 된다.
- Group은 API의 그룹으로 일종의 네임스페이스 및 패키지와 비슷한 역할을 한다. 나는 여기서 ClusterJob이라는 리소스를 정의했는데, 우연히 어떤 오픈소스를 설치했는데 그 오픈소스에서 다른 역할로서의 ClusterJob이라는 Custom Resource를 사용하고 있을 수도 있다. 이러한 Kind 충돌을 막기 위해 API Group이 있다고 보면 될 것 같다.
- Version은 Custom Resource의 버전으로 컨트롤러에서 버전별로 reconcile 로직을 다르게 관리할 수 있다.
2. Spec, Status 필드 구성하기
Custom Resource의 실제 설계부분으로, spec.version[].schema 하위 부분이다. 이 부분에서는 필드의 구조를 구성하는 것 뿐 아니라 필드의 유효성 검증을 선언할 수도 있다.
spec:
versions:
- name: v1alpha
schema:
openAPIV3Schema:
description: ClusterJob is the Schema for the clusterjobs API
properties:
apiVersion:
description: ...
type: string
kind:
description: ...
type: string
metadata:
type: object
spec:
description: spec defines the desired state of ClusterJob
type: object
properties:
failureStrategy:
description: FailureStrategy defines how to handle failures (keepgoing
or exit)
enum:
- keepgoing
- exit
type: string
strategy:
...
jobTemplate:
...
required:
- failureStrategy
- jobTemplate
- strategy
openAPIV3Schema.properties.spec부분을 보면 ClusterJob의 spec 필드 구조를 정의한다. 필드 정의 부분은 다음 구조를 따른다.description: 필드 설명 부분type: 필드 타입, integer, string, object, list 등이 있다.enum: type이 string인데 열거형인 경우 가능한 값들을 정의한다. (유효성 검증)required: type이 object인 경우 하위 필드 중 필수로 지정해야 하는 필드명을 정의한다. (유효성 검증)
이 밖에도 CRD에는 여러가지 필드가 있기 떄문에 자세한 것은 문서를 참고하자.
https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
Extend the Kubernetes API with CustomResourceDefinitions
This page shows how to install a custom resource into the Kubernetes API by creating a CustomResourceDefinition. Before you begin You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.
kubernetes.io
CRD가 길어진 이유
ClusterJob 커스텀 리소스를 만들면서 CRD가 길어진 이유가 있다. 일단 ClusterJob은 쿠버네티스의 Job 리소스를 활용한 확장 기능을 구현하기 위해 만들었다. ClusterJob의 spec 부분에서의 jobTemplate가 있는데, 이 값은 쿠버네티스의 CronJob에 있는 jobTemplateSpec 과 동일한 필드 구성이다.
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#jobtemplatespec-v1-batch
Kubernetes API Reference Docs
kubernetes.io
jobTemplateSpec과 동일한 필드가 import되면서 코드가 길어졌던 것이다. kubebuilder에서는 이러한 import를 자동으로 해주기 때문에 신경쓰지 않아도 되었다.
kubebuilder
Custom API를 만들기 위해서는 CRD를 구성해야 하며, Controller도 구현해야 한다. 그리고 Controller에서 Custom Resource를 참조해야 하는데, Controller에서 Custom Resource를 참조하기 위한 구조체를 구성해야 하며, CRD에서 선언한 구조와 일치해야 한다. 하지만 이 두개를 관리하는 파일이 서로 다른데 서로 동기화가 안된다면 타입 오류가 나기 쉽다. 뿐만 아니라 CRD를 구성하는 것이 시간이 많이 걸리는 작업이기도 하다.
이외에도 Controller 자체를 구현해야 하며, Controller 구현 후에는 컨테이너 이미지를 빌드해야 하고, 실제로 Deployment 등으로 쿠버네티스로 배포까지 해야 한다.
이렇게 Custom API를 만드는 워크플로우가 상당히 까다로운 편인데, 이러한 어려움과 까다로움, 귀찮음을 해결하기 위해 kubebuilder라는 프레임워크가 있다. kubebuilder는 다음의 기능을 제공한다.
- 구성파일, CRD, 컨테이너 배포와 관련된 Dockerfile, Makefuile 등을 포함하여 프로젝트 구조를 제공한다.
- CRD 및 Controller 및 Custom Resource 구조체에 대한 코드를 자동으로 생성하며, Custom Resource 구조체를 통해 CRD를 자동으로 생성한다.
- kubernetes용 envtest와 같은 테스트 도구와의 통합을 지원한다.
https://github.com/kubernetes-sigs/kubebuilder
GitHub - kubernetes-sigs/kubebuilder: Kubebuilder - SDK for building Kubernetes APIs using CRDs
Kubebuilder - SDK for building Kubernetes APIs using CRDs - kubernetes-sigs/kubebuilder
github.com
마무리
이번장에는 Controller와 Custom Resource, Custom Controller, kubebuidler에 대한 소개를 하였다. 최근에 kubebuilder를 활용하여 ClusterJob이라는 커스텀 리소스를 직접 만들어봤는데, 그 과정을 정리하여 블로그 글을 작성할 예정이다.
2025.10.25 - [DevOps/Kubernetes] - kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [1]
kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [1]
이번 글에서는 kubebuilder를 사용하여 Custom Resource, Custom Controller를 직접 만들어보는 과정을 정리해보았다.주제 정하기Custom Resource, Custom Controller 만들기 전에 가장 먼저 해야 할 것은 어떤 것을 만
beer1.tistory.com
2025.10.25 - [DevOps/Kubernetes] - kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [2]
kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [2]
// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch이전 시간에는 kubebuilder를 사용하여 프로젝트를 구축하고, Custom Resource를 만들었다. 이번 시간에는 Custom Controller를 만들어서 ClusterJob의 기능을
beer1.tistory.com
2025.10.26 - [DevOps/Kubernetes] - kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [3]
kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [3]
이전 시간에는 kubebuilder를 사용하여 ClusterJob이라는 Custom Controller의 일부를 구현하였고, 실제로 쿠버네티스에 배포하여 동작을 확인하였다. 이번 시간에는 ClusterJob Custom Controller의 나머지 기능들
beer1.tistory.com
ClusterJob은 클러스터 내 모든 워커노드에서 파드를 한번씩 실행하는 워크로드이다. 관련 코드는 해당 레포에서 관리하고 있다.
https://github.com/beer-one/cluster-job
GitHub - beer-one/cluster-job: cluster-job CRD
cluster-job CRD. Contribute to beer-one/cluster-job development by creating an account on GitHub.
github.com
'DevOps > Kubernetes' 카테고리의 다른 글
| kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [2] (0) | 2025.10.25 |
|---|---|
| kubebuilder를 사용하여 Custom Resource, Custom Controller 만들어보기 [1] (0) | 2025.10.25 |
| Kubernetes Node ContainerGCFailed 트러블슈팅 (0) | 2025.09.30 |
| CoreDNS DNS Resolve timedout과 ndots (0) | 2025.09.27 |
| 쿠버네티스에서의 고가용성 (High Availability) (1) | 2025.01.26 |
댓글