근묵자흑
Kubernetes Patterns : Operator (Datadog Operator) 본문
Controller 패턴(Chapter 27)에서는 Annotation 기반으로 ConfigMap 변경을 감지하고 Pod를 재시작하는 구조를 살펴보았습니다.
이 방식은 동작하지만, Annotation은 자유 형식 문자열이라 유효성 검증이 없고, 어떤 ConfigMap이 어떤 Pod와 연결되는지 파악하기 어렵습니다.
Operator 패턴은 Custom Resource Definition(CRD) 을 도입하여 이 한계를 해결합니다.
도메인 특화 리소스를 Kubernetes API의 일급 객체로 등록하고, 커스텀 Controller가 이를 관리하는 것이 Operator의 핵심입니다.
이 글에서는 책의 ConfigWatcher 예제로 개념을 이해한 뒤, Datadog Operator의 코드 레벨 아키텍처를 분석하여 프로덕션 Operator가 실제로 어떻게 설계되는지 살펴봅니다.
1. Operator 개요
1.1 문제
Controller 패턴은 기존 Kubernetes 리소스(ConfigMap, Pod, Deployment 등)만을 감시합니다. 설정 정보를 Annotation에 저장하면 다음과 같은 한계가 있습니다.
- 스키마 검증 불가: Annotation은 자유 형식 문자열이므로 잘못된 값이 들어가도 에러가 발생하지 않습니다
- 관계 파악 어려움: ConfigMap의 Annotation에 Pod 선택자가 묻혀 있어 전체 매핑을 한눈에 볼 수 없습니다
- 도메인 지식 부재: Kubernetes API가 도메인 특화 개념을 이해하지 못합니다
- 1:1 제약: Annotation 기반 접근은 하나의 ConfigMap에 하나의 애플리케이션만 연결할 수 있습니다
예를 들어 Datadog를 Kubernetes의 옵저버빌리티 솔루션으로 채택했다고 가정합니다. 메트릭 수집, APM, 로그 수집, 보안 모니터링을 모두 관리해야 하는데, 이 설정을 Annotation이나 ConfigMap에 흩뿌리면 전체 상태를 파악하기 어렵습니다. "클러스터의 모니터링 설정"이라는 도메인 개념을 Kubernetes 리소스처럼 선언적으로 정의할 수 있다면 운영이 훨씬 편리해집니다.
1.2 해결책
CRD(Custom Resource Definition) 로 새로운 리소스 타입을 정의하고, 이 리소스의 변화를 감시하는 커스텀 Controller를 작성합니다. CRD와 Controller의 조합이 Operator 입니다.
Jimmy Zelinskie의 정의가 Operator의 특성을 잘 설명합니다.
An operator is a Kubernetes controller that understands two domains: Kubernetes and something else. By combining knowledge of both areas, it can automate tasks that usually require a human operator that understands both domains.
Datadog Operator는 "Kubernetes"와 "옵저버빌리티 도메인" 두 영역을 이해하는 전형적인 사례입니다. 단일 DatadogAgent CRD에서 DaemonSet(Node Agent), Deployment(Cluster Agent), ClusterChecksRunner를 선언적으로 생성하며, 35개 이상의 기능 토글로 메트릭 수집 파이프라인을 구성합니다.
flowchart LR
subgraph "Controller 패턴"
C1[기존 리소스 감시] --> C2[Annotation 읽기] --> C3[Pod 재시작]
end
subgraph "Operator 패턴"
O1[기존 리소스 감시] --> O2[CRD 조회] --> O3[Pod 재시작]
O4[CRD 등록] -.-> O2
end
2. Controller vs Operator
Operator는 Controller의 상위 개념(is-a 관계)입니다. CRD를 통해 Kubernetes API를 확장하고, 도메인 특화 운영 지식을 코드로 표현합니다.
| 구분 | Controller | Operator |
|---|---|---|
| API 확장 | 기존 리소스만 사용 | CRD로 새 리소스 타입 정의 |
| 설정 방식 | Annotation 기반 (자유 형식) | CR 인스턴스 (스키마 검증) |
| 관계 표현 | ConfigMap Annotation에 매핑 정보 내장 | 별도 CR 리소스로 매핑 관계 명시 |
| 조회 가능성 | kubectl get cm에서 Annotation 확인 필요 |
kubectl get cw로 전체 매핑 조회 |
| 도메인 지식 | 범용적 | 도메인 특화 |
| 유효성 검증 | 없음 | OpenAPIV3Schema로 검증 |
| 매핑 구조 | 1:1 (ConfigMap → 단일 앱) | N:M (CR로 임의 조합 가능) |
다만 이 경계가 항상 명확한 것은 아닙니다. ConfigMap을 CRD 대신 사용하여 도메인 로직을 담는 중간 형태도 존재합니다. CRD 등록에 cluster-admin 권한이 필요하므로, 공유 클러스터에서 CRD를 등록할 수 없는 경우에는 ConfigMap 기반 Controller가 현실적인 대안이 됩니다.
flowchart LR
subgraph "Controller 분류 스펙트럼"
direction LR
A["Simple Controller<br/>(기존 리소스 감시)"] --> B["ConfigMap 기반<br/>Controller<br/>(CRD 없이 도메인 로직)"] --> C["Operator<br/>(CRD + Controller)"] --> D["API Aggregation<br/>(커스텀 API 서버)"]
end
style A fill:#e8f5e9
style B fill:#fff3e0
style C fill:#e3f2fd
style D fill:#f3e5f5
3. Operator 동작 원리
Operator도 Controller와 동일한 Observe-Analyze-Act 사이클을 따릅니다. 핵심 차이는 Analyze 단계에서 Annotation 대신 CRD를 조회한다는 점입니다.
sequenceDiagram
participant User
participant API as API Server
participant Op as Operator
participant CRD as ConfigWatcher CR
participant Pod
Note over API: CRD 등록 (configwatchers.k8spatterns.com)
User->>API: ConfigMap 수정
API->>Op: MODIFIED 이벤트 전송
Op->>API: ConfigWatcher CRD 조회
API-->>Op: spec.configMap 매칭 CR 반환
Op->>Op: podSelector.matchLabels 추출
Op->>API: Pod 삭제 요청 (labelSelector)
API->>Pod: Pod 종료
Note over API,Pod: Deployment가 새 Pod 생성
3.1 Level-Triggered vs Edge-Triggered
Operator의 Reconciliation은 Level-Triggered 방식입니다. 개별 이벤트에 반응하는 것이 아니라, 매 Reconciliation 사이클마다 현재 상태와 원하는 상태를 비교하여 수렴시킵니다. 이 설계가 멱등성(Idempotency) 을 자연스럽게 요구합니다.
- Edge-Triggered: "이벤트 A가 발생했으니 A에 대한 처리를 수행" → 이벤트 유실 시 상태 불일치 발생
- Level-Triggered: "현재 상태가 원하는 상태와 다르니 수렴시킴" → 이벤트가 유실되어도 다음 Reconcile에서 차이를 감지하여 보정
flowchart TB
subgraph "Edge-Triggered (비권장)"
E1[이벤트 A 발생] --> E2[A에 대한 처리]
E3[이벤트 B 발생] --> E4[B에 대한 처리]
E5[이벤트 유실] --> E6["❌ 상태 불일치"]
end
subgraph "Level-Triggered (Operator 방식)"
L1[Reconcile 호출] --> L2[현재 상태 조회]
L2 --> L3[원하는 상태와 비교]
L3 --> L4[차이 있으면 수렴]
L4 --> L5["✅ 항상 일관된 상태"]
end
controller-runtime 내부에서 이 사이클은 다음과 같이 동작합니다.
API Server → Watch → SharedInformer → Local Cache → Event Handler → Work Queue → Reconciler → API Server (writes)
읽기는 로컬 캐시(Eventually Consistent)를 통하고, 쓰기는 API Server로 직접 전달됩니다. Reconcile() 함수는 namespace/name 키만 받으며, 어떤 이벤트가 트리거했는지 알지 못합니다. 이 설계가 Level-Triggered 동작을 자연스럽게 강제합니다.
4. Custom Resource Definition (CRD)
CRD는 Kubernetes API를 확장하여 새로운 리소스 타입을 등록하는 메커니즘입니다. 등록된 CRD는 네이티브 리소스와 동일하게 kubectl, API Server, RBAC을 통해 관리됩니다.
4.1 CRD 구조
Prometheus Operator의 CRD를 예로 핵심 필드를 살펴보겠습니다.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: prometheuses.monitoring.coreos.com # ① 이름: <plural>.<group>
spec:
group: monitoring.coreos.com # ② API 그룹
names:
kind: Prometheus # ③ 리소스 타입명
plural: prometheuses # ④ 복수형 (URL 경로에 사용)
singular: prometheus
scope: Namespaced # ⑤ 네임스페이스/클러스터 범위
versions:
- name: v1 # ⑥ 버전
storage: true # ⑦ 정확히 하나만 storage version
served: true # ⑧ REST API에서 제공 여부
schema:
openAPIV3Schema: .... # ⑨ 유효성 검증 스키마
| 항목 | 설명 |
|---|---|
metadata.name |
<plural>.<group> 형식으로 고유 이름을 구성합니다 |
spec.group |
API 그룹으로, 리소스의 소유 도메인을 나타냅니다 |
names.kind |
리소스 타입명으로, CR 인스턴스의 kind 필드에 사용됩니다 |
scope |
Namespaced 또는 Cluster 범위를 지정합니다 |
versions[].storage |
정확히 하나의 버전만 true로 설정하여 etcd에 저장되는 형식을 결정합니다 |
versions[].served |
REST API에서 해당 버전을 제공할지 결정합니다 |
openAPIV3Schema |
OpenAPI V3 스키마로 CR 생성 시 유효성을 자동 검증합니다 |
4.2 CRD 분류
CRD는 용도에 따라 크게 두 가지로 나뉩니다.
- Installation CRD: 애플리케이션 자체의 설치와 운영을 관리합니다. Prometheus CRD,
DatadogAgentCRD가 대표적인 예시로, 각각 Prometheus 서버와 Datadog Agent의 배포 설정을 선언적으로 정의합니다. - Application CRD: 애플리케이션 도메인 개념을 표현합니다.
ServiceMonitorCRD는 Prometheus가 스크래핑할 대상 서비스를,DatadogMonitorCRD는 메트릭 기반 알림 규칙을 정의합니다. Operator가 이를 읽어 시스템 설정을 자동으로 갱신합니다.
하나의 Operator가 여러 종류의 CRD를 관리할 수 있습니다. Datadog Operator는 DatadogAgent, DatadogMonitor, DatadogSLO, DatadogDashboard, DatadogAgentProfile 등 5개 이상의 CRD를 관리합니다.
5. 구현 예제: ConfigWatcher Operator
5.1 CRD 정의
ConfigWatcher라는 새 리소스를 Kubernetes에 등록합니다. 이 리소스는 "어떤 ConfigMap이 변경되면 어떤 Pod를 재시작할 것인가"를 선언적으로 정의합니다.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: configwatchers.k8spatterns.com
spec:
scope: Namespaced
group: k8spatterns.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
configMap:
type: string
description: "감시할 ConfigMap 이름"
podSelector:
type: object
description: "재시작할 Pod의 라벨 선택자"
properties:
matchLabels:
type: object
additionalProperties:
type: string
required:
- configMap
- podSelector
additionalPrinterColumns:
- name: ConfigMap
type: string
jsonPath: .spec.configMap
names:
kind: ConfigWatcher
singular: configwatcher
plural: configwatchers
shortNames:
- cw
| 항목 | 값 | 설명 |
|---|---|---|
| API Group | k8spatterns.com |
리소스 소유 도메인 |
| Kind | ConfigWatcher |
리소스 타입명 |
| Short Name | cw |
kubectl get cw로 조회 가능 |
spec.configMap |
string, required | 감시 대상 ConfigMap |
spec.podSelector |
object, required | 재시작 대상 Pod 라벨 |
| additionalPrinterColumns | ConfigMap | kubectl get cw 출력에 ConfigMap 이름 표시 |
5.2 CR 인스턴스
Controller 패턴에서는 ConfigMap에 k8spatterns.com/podDeleteSelector: "app=webapp" Annotation을 직접 넣었습니다. Operator 패턴에서는 별도의 ConfigWatcher CR로 이 매핑을 분리합니다.
apiVersion: k8spatterns.com/v1
kind: ConfigWatcher
metadata:
name: webapp-config-watcher
spec:
configMap: webapp-config
podSelector:
matchLabels:
app: webapp
5.3 Operator Script
Controller 패턴과의 핵심 차이는 ConfigMap MODIFIED 이벤트 수신 후 Annotation이 아닌 ConfigWatcher CRD를 조회하는 것입니다.
#!/bin/bash
namespace=${WATCH_NAMESPACE:-default}
base=http://localhost:8001
ns=namespaces/$namespace
start_event_loop() {
echo "::: Starting to watch ConfigMaps in namespace $namespace"
curl -N -s $base/api/v1/${ns}/configmaps?watch=true | while read -r event
do
event=$(echo "$event" | tr '\r\n' ' ')
local type=$(echo "$event" | jq -r .type)
local config_map=$(echo "$event" | jq -r .object.metadata.name)
if [ "$type" = "MODIFIED" ]; then
# ★ 핵심: Annotation 대신 ConfigWatcher CRD를 조회
local watchers=$(curl -s \
$base/apis/k8spatterns.com/v1/${ns}/configwatchers | \
jq -r ".items[] | select(.spec.configMap == \"$config_map\")")
if [ -n "$watchers" ]; then
echo "$watchers" | jq -r \
'.spec.podSelector.matchLabels | to_entries |
map(.key + "=" + .value) | join(",") | @uri' | \
while read -r selector; do
delete_pods_with_selector "$selector"
done
fi
fi
done
}
| 항목 | Controller | Operator |
|---|---|---|
| Pod 선택자 획득 | ConfigMap Annotation에서 추출 | ConfigWatcher CRD 조회 |
| API 엔드포인트 | /api/v1/.../configmaps |
/apis/k8spatterns.com/v1/.../configwatchers |
| 매핑 정보 위치 | ConfigMap 자체에 내장 | 별도 CR 리소스 |
| ConfigMap 의존성 | ConfigMap이 Controller를 알아야 함 | ConfigMap은 변경 없음 |
5.4 RBAC 구성
Controller 패턴에서는 기본 edit ClusterRole만으로 충분했습니다. Operator 패턴에서는 CRD 리소스에 대한 접근 권한이 추가로 필요합니다.
# ★ CRD 접근 권한 (Controller에 없는 부분)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: config-watcher-crd
rules:
- apiGroups: ["k8spatterns.com"]
resources: ["configwatchers"]
verbs: ["get", "list", "watch"]
flowchart LR
SA[ServiceAccount<br/>config-watcher-operator]
SA -->|RoleBinding| CR1["ClusterRole: edit<br/>Pod 삭제, ConfigMap 감시"]
SA -->|RoleBinding| CR2["ClusterRole: config-watcher-crd<br/>ConfigWatcher get/list/watch"]
style CR2 fill:#fff3e0
5.5 적용된 패턴
flowchart TB
Operator[ConfigWatcher Operator]
Operator --> P1["Singleton Service<br/>replicas: 1"]
Operator --> P2["Ambassador<br/>kubeapi-proxy"]
Operator --> P3["Self Awareness<br/>Downward API"]
Operator --> P4["Controller<br/>Watch + Reconcile"]
Operator --> P5["CRD (API 확장)"]
P1 -.- D1[동시성 문제 방지]
P2 -.- D2[API Server 접근 단순화]
P3 -.- D3[네임스페이스 자동 인식]
P4 -.- D4[Observe-Analyze-Act 사이클]
P5 -.- D5[도메인 특화 리소스 정의]
style P5 fill:#fff3e0
6. 테스트 결과
minikube 환경에서 총 56개 테스트를 수행하여 전부 통과했습니다.
6.1 테스트 환경
Kubernetes: minikube v1.37.0
kubectl: v1.34.1
Namespace: operator-test
6.2 오프라인 테스트 (Test 1-5)
| 테스트 | 항목 수 | 결과 |
|---|---|---|
| Test 1: YAML 구문 검증 | 4 | 전체 통과 |
| Test 2: CRD 구조 검증 | 14 | 전체 통과 |
| Test 3: Operator 스크립트 로직 검증 | 12 | 전체 통과 |
| Test 4: 매니페스트 구조 검증 | 18 | 전체 통과 |
| Test 5: README 핵심 개념 검증 | 8 | 전체 통과 |
6.3 클러스터 배포 테스트 (Test 6)
minikube에서 Operator의 실제 동작을 E2E로 검증합니다.
CRD 등록 및 CR 조회
$ kubectl get crd configwatchers.k8spatterns.com
NAME CREATED AT
configwatchers.k8spatterns.com 2026-02-07T...
$ kubectl get cw -n operator-test
NAME CONFIGMAP
webapp-config-watcher webapp-config
kubectl get cw로 전체 ConfigWatcher 매핑을 한눈에 확인할 수 있습니다. Controller 패턴에서는 kubectl get cm으로 각 ConfigMap의 Annotation을 일일이 확인해야 했던 것과 비교됩니다.
ConfigMap 수정 후 Operator 로그
::: Starting to watch ConfigMaps in namespace operator-test
::: Event: ADDED on ConfigMap config-watcher-operator
::: Event: ADDED on ConfigMap kube-root-ca.crt
::: Event: ADDED on ConfigMap webapp-config
::: Event: MODIFIED on ConfigMap webapp-config
::: ConfigMap webapp-config modified, checking ConfigWatcher CRDs...
::::: Deleting pods with selector: app%3Dwebapp
::::: Deleted pod webapp-f4ddf5b47-gwzm8
flowchart LR
subgraph Before
CM1["ConfigMap<br/>message: Welcome..."]
Pod1["Pod<br/>webapp-...-gwzm8"]
end
subgraph "ConfigMap 수정"
Patch[kubectl patch]
end
subgraph After
CM2["ConfigMap<br/>message: Updated..."]
Pod2["Pod<br/>webapp-...-8kcmf"]
end
CM1 --> Patch --> CM2
Pod1 -.->|Operator가 삭제| Patch
Patch -.->|Deployment가 생성| Pod2
| 단계 | Pod 이름 | MESSAGE |
|---|---|---|
| 수정 전 | webapp-f4ddf5b47-gwzm8 | Welcome to Kubernetes Patterns ! |
| 수정 후 | webapp-f4ddf5b47-8kcmf | Updated at 193701 |
클러스터 배포 테스트: 14개 항목 전부 통과.
7. 프로덕션 Operator 심층 분석: Datadog Operator
Shell Script 기반 ConfigWatcher는 학습용으로 적합하지만, 프로덕션 Operator는 훨씬 복잡한 아키텍처를 가집니다. Datadog Operator를 통해 프로덕션 수준의 Operator가 어떻게 설계되는지 코드 레벨에서 분석합니다.
7.1 왜 Datadog Operator인가
Datadog Operator는 단일 DatadogAgent CRD로 전체 옵저버빌리티 스택을 관리하는 대규모 Operator입니다. 이 Operator를 분석하면 다음의 프로덕션 패턴을 학습할 수 있습니다.
| 학습 포인트 | ConfigWatcher | Datadog Operator |
|---|---|---|
| CRD 복잡도 | 필드 2개 (configMap, podSelector) | 3개 최상위 섹션, 35+ 기능 토글 |
| 생성하는 리소스 | 없음 (Pod 삭제만) | DaemonSet, Deployment, RBAC, Secret, Service, NetworkPolicy |
| Reconcile 복잡도 | ConfigMap → CRD 조회 → Pod 삭제 | 8단계 파이프라인, 43개 Feature 핸들러 |
| 컨테이너 구성 | 해당 없음 | 최대 5개 사이드카 + 동적 구성 |
7.2 CRD 스펙 구조 (v2alpha1)
DatadogAgentSpec은 세 개의 최상위 섹션으로 구성됩니다.
apiVersion: datadoghq.com/v2alpha1
kind: DatadogAgent
metadata:
name: datadog
spec:
global: # 클러스터 전역 설정
site: datadoghq.com
credentials:
apiKey: <secret-ref>
appKey: <secret-ref>
clusterName: my-cluster
kubelet:
tlsVerify: false
features: # 기능 토글 (35+ 기능)
apm:
enabled: true
dogstatsd:
hostPortConfig:
enabled: true
hostPort: 8125
logCollection:
enabled: true
containerCollectAll: true
kubeStateMetricsCore:
enabled: true
admissionController:
enabled: true
mutateUnlabelled: true
override: # 컴포넌트별 오버라이드
nodeAgent:
tolerations:
- operator: Exists
containers:
agent:
resources:
requests:
cpu: 200m
memory: 256Mi
clusterAgent:
replicas: 2
| 섹션 | 역할 | 주요 필드 |
|---|---|---|
spec.global |
클러스터 전역 설정 | site, credentials, clusterName, kubelet, tags |
spec.features |
기능별 활성화/설정 | apm, dogstatsd, logCollection, kubeStateMetricsCore 등 35+ |
spec.override |
컴포넌트별 커스터마이징 | nodeAgent, clusterAgent, clusterChecksRunner별 resources, tolerations 등 |
ConfigWatcher의 spec.configMap + spec.podSelector 2개 필드와 비교하면, 프로덕션 CRD의 복잡도가 어떤 수준인지 체감할 수 있습니다. 그러나 근본적인 구조는 동일합니다. CRD에 원하는 상태를 선언하면, Operator가 실제 상태를 그에 맞게 수렴시킵니다.
7.3 Reconciliation 8단계 파이프라인
ConfigWatcher Operator의 Reconcile은 "CRD 조회 → Pod 삭제"라는 단순 흐름이었습니다. Datadog Operator는 이를 8단계 파이프라인으로 확장합니다.
flowchart TB
S1["1단계: CR 페치<br/>client.Get()으로 DatadogAgent CR 조회"]
S2["2단계: 삭제 처리<br/>DeletionTimestamp 확인 → Finalizer 처리"]
S3["3단계: 설정 검증 & 기본값<br/>spec 유효성 검증, 누락 필드 기본값 적용"]
S4["4단계: Feature 처리<br/>43개 Feature의 Configure() 호출<br/>→ RequiredComponents 결정"]
S5["5단계: 컴포넌트 매니페스트 생성<br/>기본 PodTemplateSpec 생성<br/>→ Feature들이 순차적으로 수정<br/>→ Override 적용"]
S6["6단계: 리소스 적용<br/>RBAC, Secret, ConfigMap, Service,<br/>DaemonSet, Deployment Create/Update"]
S7["7단계: Status 업데이트<br/>Conditions: Active, ReconcileError, SecretError"]
S8["8단계: 결과 반환<br/>Result{} 또는 RequeueAfter"]
S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 --> S8
style S4 fill:#e3f2fd
style S5 fill:#e3f2fd
4단계와 5단계가 Datadog Operator의 핵심입니다. ConfigWatcher가 "ConfigMap 이름이 일치하는 CR을 찾아 Pod를 삭제"하는 단일 로직이라면, Datadog Operator는 43개 Feature가 하나의 PodTemplateSpec을 협력적으로 구성하는 복잡한 조합 로직을 수행합니다.
7.4 Feature-as-Plugin 아키텍처
Datadog Operator의 가장 주목할 만한 설계는 Feature-as-Plugin 아키텍처입니다. 43개의 Feature가 동일한 인터페이스를 구현하고, Go의 init() 함수로 자기 등록합니다.
Feature 인터페이스
// internal/controller/datadogagent/feature/types.go
type Feature interface {
ID() IDType
// CRD spec을 읽고 이 Feature에 필요한 컴포넌트를 선언
Configure(ddaMetaObj metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpec,
ddaRCStatus *v2alpha1.RemoteConfigConfiguration) RequiredComponents
// RBAC, Secret, ConfigMap 등 의존 리소스 관리
ManageDependencies(managers ResourceManagers, provider string) error
// 각 컴포넌트의 PodTemplateSpec 수정
ManageClusterAgent(managers PodTemplateManagers, provider string) error
ManageNodeAgent(managers PodTemplateManagers, provider string) error
ManageSingleContainerNodeAgent(managers PodTemplateManagers, provider string) error
ManageClusterChecksRunner(managers PodTemplateManagers, provider string) error
}
자기 등록 패턴
// internal/controller/datadogagent/feature/dogstatsd/feature.go
func init() {
feature.Register(feature.DogstatsdIDType, buildDogstatsdFeature)
}
이 패턴으로 새로운 기능(예: GPU 모니터링)을 추가할 때 기존 코드를 변경하지 않고 Feature 패키지만 추가하면 됩니다. 개방-폐쇄 원칙(Open-Closed Principle) 의 실현입니다.
ConfigWatcher와 비교하면 다음과 같습니다.
flowchart TB
subgraph "ConfigWatcher: 단일 로직"
CW1["ConfigMap MODIFIED"] --> CW2["CRD 조회"] --> CW3["Pod 삭제"]
end
subgraph "Datadog Operator: Feature Plugin 조합"
DD1["DatadogAgent CR 변경"]
DD1 --> F1["enabledefault Feature<br/>기본 환경변수 설정"]
DD1 --> F2["DogStatsD Feature<br/>포트 8125 추가"]
DD1 --> F3["APM Feature<br/>trace-agent 컨테이너 추가"]
DD1 --> F4["Log Collection Feature<br/>볼륨 마운트 추가"]
DD1 --> F5["KSM Core Feature<br/>Cluster Agent RBAC 확장"]
DD1 --> FN["... 43개 Feature"]
F1 --> M["Merger 시스템<br/>충돌 없이 합성"]
F2 --> M
F3 --> M
F4 --> M
F5 --> M
FN --> M
M --> R["최종 DaemonSet/<br/>Deployment 생성"]
end
style M fill:#fff3e0
PodTemplateManagers — Feature가 Pod 스펙을 수정하는 메커니즘
Feature가 직접 PodTemplateSpec을 수정하면 충돌이 발생할 수 있습니다. Datadog Operator는 31개의 Merger를 통해 여러 Feature의 동시 수정을 안전하게 합성합니다.
type PodTemplateManagers interface {
PodTemplateSpec() *corev1.PodTemplateSpec
EnvVar() merger.EnvVarManager // DD_* 환경변수 추가
Volume() merger.VolumeManager // hostPath, emptyDir 볼륨 추가
VolumeMount() merger.VolumeMountManager // 컨테이너별 마운트 추가
Port() merger.PortManager // 8125, 8126 등 포트 노출
SecurityContext() merger.SecurityContextManager
Annotation() merger.AnnotationManager
}
예를 들어 DogStatsD Feature가 Node Agent에 설정을 추가하는 코드는 다음과 같습니다.
// DogStatsD Feature의 ManageNodeAgent()
managers.EnvVar().AddEnvVar(&corev1.EnvVar{
Name: "DD_DOGSTATSD_PORT", Value: "8125",
})
managers.EnvVar().AddEnvVar(&corev1.EnvVar{
Name: "DD_DOGSTATSD_NON_LOCAL_TRAFFIC", Value: "true",
})
managers.Port().Add(&corev1.ContainerPort{
Name: "dogstatsd", ContainerPort: 8125, Protocol: "UDP",
})
APM Feature, Log Collection Feature 등 다른 Feature도 같은 Managers 인터페이스를 통해 환경변수와 볼륨을 추가합니다. EnvVarManager가 이름 기반으로 중복을 관리하므로 Feature 간 충돌이 발생하지 않습니다.
7.5 3단계 변환 파이프라인: CRD spec → 실제 Pod
Datadog Operator는 CRD spec을 실제 Pod 스펙으로 변환하는 3단계 파이프라인을 사용합니다.
flowchart LR
subgraph "1단계: Base"
B1["기본 PodTemplateSpec 생성<br/>agent, process-agent,<br/>trace-agent 등 컨테이너<br/>+ hostPath 볼륨"]
end
subgraph "2단계: Feature"
B2["43개 Feature 순차 호출<br/>ManageNodeAgent()<br/>ManageClusterAgent()<br/>→ Merger로 안전한 합성"]
end
subgraph "3단계: Override"
B3["spec.override 적용<br/>사용자 커스터마이징<br/>(resources, tolerations 등)<br/>★ 최우선 순위"]
end
B1 --> B2 --> B3
style B2 fill:#e3f2fd
style B3 fill:#fff3e0
1단계 — Base Phase
Node Agent의 기본 PodTemplateSpec이 생성됩니다. 최대 5개의 사이드카 컨테이너가 포함될 수 있습니다.
| 컨테이너 | 역할 |
|---|---|
agent |
코어 Agent — 메트릭 수집, 체크 실행 |
process-agent |
프로세스/컨테이너 모니터링 |
trace-agent |
APM 트레이스 수집 |
system-probe |
eBPF 기반 네트워크·보안 프로브 |
security-agent |
CWS/CSPM 보안 모니터링 |
기본 hostPath 볼륨 마운트는 시스템 레벨 가시성을 위해 구성됩니다.
| 볼륨 이름 | 호스트 경로 | 용도 |
|---|---|---|
procdir |
/proc |
프로세스 파일시스템 접근 |
cgroups |
/sys/fs/cgroup |
cgroup 메트릭 수집 |
runtimesocketdir |
/var/run/ |
Docker/containerd 소켓 |
dsdsocket |
/var/run/datadog/ |
DogStatsD Unix 소켓 |
2단계 — Feature Phase
43개 Feature가 순차적으로 호출되며, Merger 시스템을 통해 환경변수, 볼륨, 포트, RBAC을 추가합니다. enabledefault Feature가 가장 먼저 실행되어 기반 환경변수를 설정합니다.
| 환경변수 | 값 | 설명 |
|---|---|---|
DD_KUBERNETES_KUBELET_HOST |
fieldRef: status.hostIP |
kubelet 접근 주소 |
DD_CLUSTER_AGENT_ENABLED |
"true" |
Cluster Agent 연동 활성화 |
DD_API_KEY |
Secret 참조 | Datadog API 인증 |
DD_SITE |
datadoghq.com |
데이터 전송 대상 사이트 |
3단계 — Override Phase
CRD의 spec.override 섹션이 최우선 순위로 적용됩니다. Feature가 설정한 값도 Override로 덮어쓸 수 있습니다. 이를 통해 사용자는 Operator의 기본 동작을 변경하지 않고도 환경에 맞는 커스터마이징을 할 수 있습니다.
7.6 메트릭 수집 파이프라인: Operator가 구성하는 4대 경로
Operator 자체는 메트릭을 수집하지 않습니다. 수집 인프라를 선언적으로 구성하는 역할을 합니다. Operator가 배포한 Agent들이 실제 메트릭을 수집합니다.
flowchart TB
subgraph "Operator가 배포"
NA["Node Agent<br/>(DaemonSet)"]
CA["Cluster Agent<br/>(Deployment)"]
CCR["ClusterChecksRunner<br/>(Deployment, 선택적)"]
end
subgraph "경로 1: 인프라 메트릭"
NA -->|"15초 주기"| KL["kubelet API<br/>/metrics/resource<br/>/stats/summary<br/>/metrics/cadvisor"]
end
subgraph "경로 2: 클러스터 메트릭"
CA -->|"30초 주기"| APIS["Kubernetes API Server<br/>KSM Core 체크<br/>메타데이터 캐시"]
end
subgraph "경로 3: 커스텀 메트릭"
APP1["애플리케이션"] -->|"UDP 8125"| DSD["DogStatsD<br/>(Node Agent 내장)<br/>10초 flush 주기"]
end
subgraph "경로 4: APM 트레이스"
APP2["애플리케이션"] -->|"포트 8126"| TA["trace-agent<br/>(Node Agent 사이드카)"]
end
style NA fill:#e3f2fd
style CA fill:#e3f2fd
| 경로 | 컴포넌트 | 수집 주기 | 데이터 소스 |
|---|---|---|---|
| 인프라 메트릭 | Node Agent | 15초 | kubelet/cAdvisor REST API |
| 클러스터 메트릭 | Cluster Agent | 30초 | Kubernetes API Server |
| 커스텀 메트릭 | DogStatsD (Node Agent) | 10초 flush | 애플리케이션 UDP/UDS |
| APM 트레이스 | trace-agent (Node Agent) | 실시간 | 트레이싱 라이브러리 |
Cluster Agent의 핵심 역할
Cluster Agent는 단순한 메트릭 수집 이상의 역할을 수행합니다.
KSM Core 체크: 별도의 kube-state-metrics 배포 없이 Cluster Agent 내부에서 Kubernetes API를 직접 쿼리하여 kubernetes_state.* 메트릭을 생성합니다. Deployment 레플리카 수, Pod 상태, Node 조건 등 클러스터 레벨 메트릭을 수집합니다.
메타데이터 캐시: Kubernetes API Server에서 30초 주기로 메타데이터를 수집하고 캐싱합니다. Node Agent는 이 캐시에서 Pod 태그 등의 메타데이터를 조회하여 메트릭에 풍부한 태그를 부착합니다.
External Metrics Provider: external.metrics.k8s.io APIService로 등록되어 HPA가 Datadog 메트릭을 기반으로 스케일링할 수 있게 합니다. 이것은 API Aggregation 패턴의 실제 적용 사례입니다.
Admission Controller: MutatingWebhookConfiguration을 통해 Pod 생성 시 DD_AGENT_HOST, DD_ENTITY_ID 환경변수와 트레이싱 라이브러리 init 컨테이너를 자동 주입합니다.
7.7 Autodiscovery: 런타임 자산 발견
Operator가 배포한 Agent는 kubelet /pods 엔드포인트를 10초마다 폴링하여 실행 중인 컨테이너를 발견합니다. 각 컨테이너에 대해 Autodiscovery 템플릿과 매칭하고, %%host%%, %%port%% 같은 템플릿 변수를 치환하여 체크 설정을 동적으로 생성합니다.
# Pod Annotation 기반 Autodiscovery 설정 예시
annotations:
ad.datadoghq.com/redis.checks: |
{
"redisdb": {
"instances": [{"host": "%%host%%", "port": "%%port%%"}]
}
}
Operator는 DD_EXTRA_CONFIG_PROVIDERS=kubelet,kube_services와 DD_EXTRA_LISTENERS=kubelet,kube_services를 자동 설정하여 Agent의 Autodiscovery 엔진을 구성합니다. 이것이 "Kubernetes 도메인과 모니터링 도메인을 모두 이해하는 Operator"의 구체적인 동작 방식입니다.
7.8 RBAC 자동 관리
각 Feature는 ManageDependencies()에서 자신에게 필요한 RBAC 규칙을 동적으로 추가합니다.
// KSM Core Feature의 ManageDependencies() 내부
managers.RBACManager().AddClusterPolicyRule(
rbacv1.PolicyRule{
APIGroups: []string{"apps"},
Resources: []string{"deployments", "replicasets", "daemonsets", "statefulsets"},
Verbs: []string{"get", "list", "watch"},
},
)
ConfigWatcher에서는 하나의 고정된 ClusterRole을 수동으로 작성했습니다. Datadog Operator에서는 활성화된 Feature에 따라 RBAC이 동적으로 구성됩니다. APM을 비활성화하면 trace-agent 관련 RBAC이 생성되지 않고, KSM Core를 활성화하면 Deployment/ReplicaSet 읽기 권한이 자동으로 추가됩니다.
| 컴포넌트 | ServiceAccount | 핵심 권한 |
|---|---|---|
| Node Agent | <name>-agent |
pods, nodes, endpoints get/list/watch |
| Cluster Agent | <name>-cluster-agent |
광범위한 읽기 + events/leases 쓰기 + webhooks 관리 |
7.9 핵심 타이밍 상수
| 컴포넌트 | 주기 | 설명 |
|---|---|---|
| 체크 수집 (min_collection_interval) | 15초 | 모든 Agent 체크의 기본 수집 간격 |
kubelet /pods 폴링 |
10초 | Autodiscovery 컨테이너 발견 |
| Cluster Agent 메타데이터 캐시 | 30초 | API Server 메타데이터 갱신 |
| DogStatsD 집계 flush | 10초 | 커스텀 메트릭 Agent 내부 집계 |
| External Metrics 쿼리 | 30초 | HPA용 Datadog API 메트릭 조회 |
| Forwarder flush | 10~20초 | HTTPS 배치 전송 |
7.10 ConfigWatcher → Datadog Operator: 설계 원칙 비교
| 설계 원칙 | ConfigWatcher (학습용) | Datadog Operator (프로덕션) |
|---|---|---|
| CRD 복잡도 | 필드 2개 | 3개 섹션, 35+ 기능 토글 |
| Reconcile 구조 | 단일 이벤트 루프 | 8단계 파이프라인 |
| 확장성 | 기능 추가 시 스크립트 수정 | Feature Plugin 추가 (개방-폐쇄 원칙) |
| 리소스 생성 | 없음 (Pod 삭제만) | DaemonSet, Deployment, RBAC, Service 등 |
| RBAC | 고정된 ClusterRole | Feature별 동적 RBAC 생성 |
| Pod 구성 | 해당 없음 | 3단계 변환 (Base → Feature → Override) |
| 상태 보고 | 로그 출력 | Status Conditions (Active, ReconcileError) |
| 멱등성 | curl 기반 (비보장) | controller-runtime 기반 (보장) |
8. Operator Capability Levels
Operator Framework는 다섯 단계의 Operator Capability Level을 정의합니다.
flowchart TB
L1["Level 1: Basic Install<br/>CR로 프로비저닝"]
L2["Level 2: Seamless Upgrades<br/>무중단 업그레이드"]
L3["Level 3: Full Lifecycle<br/>백업/복원, 장애조치"]
L4["Level 4: Deep Insights<br/>메트릭, 알림, 로그"]
L5["Level 5: Auto Pilot<br/>자동 스케일링, 자가 치유"]
L1 --> L2 --> L3 --> L4 --> L5
style L1 fill:#c8e6c9
style L2 fill:#c8e6c9
style L3 fill:#fff9c4
style L4 fill:#fff9c4
style L5 fill:#ffccbc
| Level | 설명 | 예시 |
|---|---|---|
| Level 1 | CR로 자동 프로비저닝 | ConfigWatcher Operator |
| Level 2 | Operator/Operand 무중단 업그레이드 | Helm 기반 Operator |
| Level 3 | 백업, 복원, 장애조치 | CloudNativePG, Strimzi |
| Level 4 | Prometheus 메트릭, 커스텀 알림 | Prometheus Operator, Datadog Operator |
| Level 5 | 자동 스케일링, 자가 치유 | Strimzi + Cruise Control |
Datadog Operator는 Level 4에 해당합니다. DatadogMonitor CRD로 메트릭 기반 알림을 선언적으로 관리하고, DatadogSLO CRD로 SLO를 정량화하며, External Metrics Provider로 HPA 자동 스케일링(Level 5에 근접)을 지원합니다.
9. Operator 개발 프레임워크 현황 (2025-2026)
| 프레임워크 | 버전 | 언어 | 특징 |
|---|---|---|---|
| Kubebuilder | v4.11 | Go | 레퍼런스 구현, controller-runtime 기반 |
| Operator SDK | v1.42 | Go/Ansible/Helm | OLM 통합, Scorecard 테스트 |
| Java Operator SDK | v5.2 | Java | Strimzi, Keycloak에서 사용 |
| kube-rs | v3.0 | Rust | CNCF Sandbox, 고성능 |
| Metacontroller | v4.12 | Any (webhook) | 빠른 프로토타이핑 |
Datadog Operator는 controller-runtime 기반으로 구현되어 있습니다. cmd/main.go에서 ctrl.NewManager()로 Manager를 초기화하고, internal/controller/setup.go에서 WatchOptions에 따라 CRD별 컨트롤러를 조건부로 등록합니다.
// Datadog Operator의 WatchOptions
type WatchOptions struct {
DatadogAgentEnabled bool
DatadogMonitorEnabled bool
DatadogSLOEnabled bool
DatadogAgentProfileEnabled bool
DatadogDashboardEnabled bool
}
Metacontroller는 독특한 접근을 취합니다. Kubernetes API와의 모든 상호작용을 대행하고, 사용자는 비즈니스 로직만 담긴 Webhook 함수를 작성합니다. HTTP와 JSON을 이해하는 어떤 언어로든 Controller 함수를 구현할 수 있어 Go에 익숙하지 않은 팀에 적합합니다.
controller-runtime 기반 구현
Go 기반 controller-runtime을 사용하면 ConfigWatcher를 다음과 같이 구현할 수 있습니다.
func (r *ConfigWatcherReconciler) Reconcile(
ctx context.Context, req ctrl.Request,
) (ctrl.Result, error) {
configMap := &corev1.ConfigMap{}
if err := r.Get(ctx, req.NamespacedName, configMap); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
var watchers v1.ConfigWatcherList
if err := r.List(ctx, &watchers,
client.InNamespace(req.Namespace)); err != nil {
return ctrl.Result{}, err
}
for _, watcher := range watchers.Items {
if watcher.Spec.ConfigMap != configMap.Name {
continue
}
selector := labels.SelectorFromSet(
watcher.Spec.PodSelector.MatchLabels)
var pods corev1.PodList
r.List(ctx, &pods,
client.InNamespace(req.Namespace),
client.MatchingLabelsSelector{Selector: selector})
for _, pod := range pods.Items {
r.Delete(ctx, &pod)
}
}
return ctrl.Result{}, nil
}
Reconcile 에러 처리 패턴
controller-runtime의 반환 값에 따라 재시도 동작이 결정됩니다.
| 반환 값 | 동작 |
|---|---|
ctrl.Result{}, err |
지수 백오프로 재시도 (최대 약 16.7분) |
ctrl.Result{Requeue: true}, nil |
지수 백오프로 재시도 |
ctrl.Result{RequeueAfter: 5*time.Second}, nil |
고정 간격 후 재시도 |
ctrl.Result{}, nil |
성공, 재시도 없음 |
10. 프로덕션 핵심 요소
10.1 Status Subresource와 ObservedGeneration
/status로 사용자 의도(spec)와 관측 결과(status)를 분리합니다. Datadog Operator는 Active, ReconcileError, SecretError 등의 Condition 타입으로 시스템 상태를 보고합니다.
status:
conditions:
- type: Active
status: "True"
lastTransitionTime: "2026-02-08T10:00:00Z"
- type: ReconcileError
status: "False"
observedGeneration: 5 # metadata.generation과 비교
10.2 Finalizer
Finalizer는 CR 삭제 시 외부 리소스 정리가 필요한 경우 사용합니다. Datadog Operator는 2단계에서 DeletionTimestamp 확인 후 handleFinalizer()를 호출합니다.
flowchart TB
A["CR 삭제 요청<br/>deletionTimestamp 설정"] --> B{Finalizer 존재?}
B -->|Yes| C[외부 리소스 정리]
C --> D[Finalizer 제거]
D --> E[Kubernetes가 CR 삭제]
B -->|No| E
10.3 Server-Side Apply (SSA)
GET → UPDATE 대신 PATCH로 필드 소유권을 관리합니다. 여러 액터(Operator, GitOps, Webhook)가 같은 객체의 서로 다른 필드를 안전하게 수정할 수 있습니다.
desired := buildStatefulSet(cr)
err := r.Patch(ctx, desired, client.Apply,
client.FieldOwner("my-operator"), client.ForceOwnership)
10.4 CEL Validation (Kubernetes 1.29+ GA)
CRD에 CEL 검증 규칙을 직접 내장하여 Validating Webhook을 대체할 수 있습니다.
x-kubernetes-validations:
- rule: "self.spec.configMap.size() > 0"
message: "configMap name must not be empty"
- rule: "size(self.spec.podSelector.matchLabels) > 0"
message: "at least one label selector required"
10.5 Validation Ratcheting (Kubernetes 1.33 GA)
스키마 위반이 있는 기존 리소스라도, 변경되지 않은 필드의 위반은 무시하여 업데이트를 허용합니다. CRD 스키마 진화를 크게 용이하게 합니다.
11. CRD vs API Aggregation
| 항목 | CRD | API Aggregation |
|---|---|---|
| 복잡도 | 낮음 (YAML 정의) | 높음 (별도 API 서버 구현) |
| 인프라 | 추가 없음 | TLS, 배포, 모니터링 필요 |
| 검증 | CEL, OpenAPIV3Schema | 코드로 구현 |
| 커스텀 서브리소스 | /status, /scale만 |
자유롭게 정의 가능 |
| 저장소 | etcd (Kubernetes가 관리) | 자유 선택 |
| 적합한 경우 | 대부분의 Operator | metrics-server, 커스텀 메트릭 |
CRD가 기본 선택지입니다. Datadog Operator의 External Metrics Provider는 API Aggregation의 실제 사용 사례입니다. Cluster Agent가 external.metrics.k8s.io APIService로 등록되어, HPA가 Datadog 메트릭을 기반으로 스케일링할 수 있게 합니다.
# API Aggregation 예시
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1beta1.external.metrics.k8s.io
spec:
group: external.metrics.k8s.io
service:
name: datadog-cluster-agent-metrics-api
version: v1beta1
12. Operator Lifecycle Manager (OLM)
CRD는 클러스터 범위 리소스이므로 등록에 cluster-admin 권한이 필요합니다. OLM은 이 문제를 해결합니다.
OLM v1 (2025 GA)
OLM v1은 6개의 CRD를 ClusterExtension과 ClusterCatalog 2개로 단순화했으며, 보안 모델을 근본적으로 강화했습니다.
apiVersion: olm.operatorframework.io/v1
kind: ClusterExtension
metadata:
name: datadog-operator
spec:
namespace: datadog-system
serviceAccount:
name: datadog-installer-sa # ★ 필수: 명시적 ServiceAccount
source:
sourceType: Catalog
catalog:
packageName: datadog-operator
channels: [stable]
version: ">=1.0.0 <2.0.0"
13. Operator를 사용하지 말아야 하는 경우
flowchart TB
Q1{"런타임 조정이<br/>필요한가?"}
Q2{"도메인 특화<br/>운영 로직이 있는가?"}
Q3{"CRD 수준의<br/>API 확장이 필요한가?"}
Q1 -->|No| H["Helm / Kustomize<br/>배포 시점만 관리"]
Q1 -->|Yes| Q2
Q2 -->|No| C["Simple Controller<br/>기존 리소스 감시"]
Q2 -->|Yes| Q3
Q3 -->|No| C
Q3 -->|Yes| O["Operator<br/>CRD + Controller"]
style H fill:#e8f5e9
style C fill:#fff3e0
style O fill:#e3f2fd
| 도구 | 적합한 경우 |
|---|---|
| Helm | Stateless 앱 배포, 환경별 설정 템플릿 |
| Kustomize | 템플릿 없는 오버레이 기반 커스터마이징 |
| Simple Controller | 기존 리소스 감시, 라벨/Annotation 자동 추가 |
| Operator | Stateful 앱 라이프사이클, 모니터링 스택, 도메인 특화 스케일링 |
| Crossplane | 클라우드 인프라 선언적 프로비저닝 |
Datadog Agent를 Helm으로 설치할 수도 있습니다. 그러나 Operator를 사용하면 단일 CR로 전체 옵저버빌리티 스택의 상태를 관리할 수 있고, Feature 활성화/비활성화 시 RBAC, 볼륨, 환경변수가 자동으로 조정됩니다. 이러한 런타임 조정 로직이 Operator를 선택하는 핵심 이유입니다.
14. 실제 운영 Operator 사례
| Operator | 버전 (2025-2026) | 관리 대상 | CRD 수 | Capability Level |
|---|---|---|---|---|
| Datadog Operator | v1.x | 옵저버빌리티 스택 | 5+ | Level 4 |
| Prometheus Operator | v0.89 | 모니터링 스택 | 10+ | Level 3-4 |
| Strimzi | v0.50 | Kafka 클러스터 | 10+ | Level 4+ |
| cert-manager | v1.19 | TLS 인증서 | 6 | Level 3 |
| CloudNativePG | v1.28 | PostgreSQL HA | 3 | Level 4 |
15. Operator 보안 모범 사례
RBAC 최소 권한
Datadog Operator의 Feature별 동적 RBAC 생성은 최소 권한 원칙의 좋은 구현 사례입니다. 활성화된 Feature만큼의 권한만 생성됩니다.
- 와일드카드(
*) verb나 리소스 그룹을 사용하지 않습니다 - Kubebuilder RBAC 마커(
//+kubebuilder:rbac:...)로 ClusterRole을 자동 생성합니다 - 클러스터 범위 리소스를 관리하지 않는다면 네임스페이스 스코프 Role/RoleBinding을 우선합니다
Pod Security
Operator Pod에는 restricted Pod Security Standard를 적용합니다.
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
16. 정리
이론: ConfigWatcher로 이해하는 핵심 개념
- CRD로 새 리소스 타입을 정의하여 스키마 검증과
kubectl네이티브 조회가 가능합니다 - Annotation 기반 설정을 별도 CR로 분리하여 관계의 가시성이 향상됩니다
- Level-Triggered Reconciliation으로 이벤트 유실에도 일관된 상태를 유지합니다
실무: Datadog Operator로 이해하는 프로덕션 설계
- Feature-as-Plugin 아키텍처: 43개 Feature가 동일한 인터페이스를 구현하고
init()으로 자기 등록 → 개방-폐쇄 원칙 - 3단계 변환 파이프라인: Base → Feature → Override로 CRD spec을 실제 Pod 스펙으로 변환
- 31개 Merger: 여러 Feature의 동시 수정을 충돌 없이 합성
- 동적 RBAC 생성: Feature 활성화 상태에 따라 최소 권한 자동 구성
- 4대 메트릭 수집 경로: Operator는 수집 인프라를 구성하고, 실제 수집은 Agent가 수행
기술 생태계
- 프로덕션에서는 Kubebuilder v4 또는 Operator SDK v1.42 사용을 권장합니다
- CEL Validation(GA in 1.29)으로 Webhook 없이 CRD 유효성 검증이 가능합니다
- Validation Ratcheting(GA in 1.33)으로 기존 리소스를 깨뜨리지 않고 스키마를 강화할 수 있습니다
- OLM v1이 GA에 도달하여 보안이 강화된 Operator 라이프사이클 관리를 제공합니다
- Operator가 필요 없는 경우 Helm, Kustomize, Simple Controller가 더 적합합니다
참고
'k8s > kubernetes-pattern' 카테고리의 다른 글
| Kubernetes Patterns: ImageBuilder (0) | 2026.02.28 |
|---|---|
| Kubernetes Patterns : Elastic Scale (0) | 2026.02.21 |
| Kubernetes Patterns: Operator (0) | 2026.02.07 |
| Kubernetes Pattern: Controller (0) | 2026.01.31 |
| Kubernetes Pattern: Access Control (0) | 2026.01.24 |