Post

Part 25/26: CRD와 Operator

Part 25/26: CRD와 Operator

Kubernetes는 Custom Resource Definition(CRD)를 통해 API를 확장할 수 있다. Operator 패턴은 CRD와 컨트롤러를 결합하여 복잡한 애플리케이션을 자동으로 관리한다.

Custom Resource Definition (CRD)

개념

CRD를 사용하면 Kubernetes API에 새로운 리소스 타입을 추가할 수 있다.

1
2
3
기본 리소스: Pod, Deployment, Service, ...
     +
CRD로 추가: Database, Certificate, VirtualService, ...

사용 사례:

  • 데이터베이스 클러스터 (PostgresCluster, MySQLCluster)
  • 인증서 관리 (Certificate)
  • 네트워크 정책 (VirtualService, DestinationRule)
  • 백업 정책 (Backup, Schedule)

CRD 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com  # plural.group
spec:
  group: example.com
  versions:
  - name: v1
    served: true      # API에서 제공
    storage: true     # etcd에 저장되는 버전
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            required:
            - engine
            - size
            properties:
              engine:
                type: string
                enum: ["mysql", "postgres"]
              size:
                type: string
                enum: ["small", "medium", "large"]
              replicas:
                type: integer
                minimum: 1
                maximum: 10
                default: 1
          status:
            type: object
            properties:
              state:
                type: string
              message:
                type: string
    subresources:
      status: {}      # /status 서브리소스 활성화
    additionalPrinterColumns:
    - name: Engine
      type: string
      jsonPath: .spec.engine
    - name: Size
      type: string
      jsonPath: .spec.size
    - name: State
      type: string
      jsonPath: .status.state
    - name: Age
      type: date
      jsonPath: .metadata.creationTimestamp
  scope: Namespaced   # 또는 Cluster
  names:
    plural: databases
    singular: database
    kind: Database
    shortNames:
    - db

CRD 적용 및 확인

1
2
3
4
5
6
7
8
9
# CRD 적용
kubectl apply -f database-crd.yaml

# CRD 목록
kubectl get crd
kubectl describe crd databases.example.com

# API 리소스에 추가됨 확인
kubectl api-resources | grep database

Custom Resource (CR) 생성

1
2
3
4
5
6
7
8
9
apiVersion: example.com/v1
kind: Database
metadata:
  name: my-database
  namespace: default
spec:
  engine: postgres
  size: medium
  replicas: 3
1
2
3
4
5
6
7
8
9
10
# CR 생성
kubectl apply -f my-database.yaml

# CR 조회
kubectl get databases
kubectl get db  # shortName 사용
kubectl describe database my-database

# CR 삭제
kubectl delete database my-database

CRD 스키마 검증

1
2
3
4
# 스키마 위반 시 거부됨
spec:
  engine: mongodb      # enum에 없음 → 에러
  replicas: 100        # maximum 초과 → 에러

버전 관리

1
2
3
4
5
6
7
8
9
versions:
- name: v1
  served: true
  storage: false  # 이전 버전
  schema: ...
- name: v2
  served: true
  storage: true   # 현재 저장 버전
  schema: ...

Operator 패턴

개념

Operator는 CRD + Controller의 조합으로, 애플리케이션의 운영 지식을 코드화한다.

1
2
3
4
5
6
7
8
9
10
11
12
┌────────────────────────────────────────────────────────────┐
│                      Operator Pattern                       │
├────────────────────────────────────────────────────────────┤
│                                                             │
│  Custom Resource ──────→ Controller ──────→ Managed        │
│  (원하는 상태)           (조정 로직)         Resources       │
│                                                             │
│  예: Database CR    →  DB Operator   →  Pod, Service,      │
│      replicas: 3                        StatefulSet,       │
│      engine: postgres                   ConfigMap...       │
│                                                             │
└────────────────────────────────────────────────────────────┘

Operator가 하는 일:

  1. Custom Resource 변경 감시
  2. 현재 상태와 원하는 상태 비교
  3. 차이를 해소하기 위한 작업 수행 (Reconciliation)
  4. 상태 업데이트

Operator 예시: 데이터베이스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 사용자가 원하는 상태 정의
apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: my-postgres
spec:
  postgresVersion: 15
  instances:
  - name: instance1
    replicas: 3
    dataVolumeClaimSpec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
  backups:
    pgbackrest:
      repos:
      - name: repo1
        schedules:
          full: "0 1 * * 0"
          incremental: "0 1 * * 1-6"

Operator가 자동으로 생성/관리:

  • StatefulSet (Postgres 인스턴스)
  • Service (읽기/쓰기 엔드포인트)
  • PVC (데이터 저장소)
  • ConfigMap (설정)
  • Secret (인증 정보)
  • CronJob (백업 스케줄)

주요 Operator들

Operator용도
Prometheus Operator모니터링
Cert-Manager인증서 관리
StrimziKafka 클러스터
Rook스토리지 (Ceph)
ArgoCDGitOps
Elastic Cloud on K8sElasticsearch
Redis OperatorRedis 클러스터

Operator 설치 (예: Cert-Manager)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Helm으로 설치
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --set installCRDs=true

# 또는 kubectl apply
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# CRD 확인
kubectl get crd | grep cert-manager
# certificates.cert-manager.io
# clusterissuers.cert-manager.io
# issuers.cert-manager.io

Custom Resource 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Cert-Manager Issuer
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          class: nginx
---
# Certificate 요청
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
spec:
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: Issuer
  commonName: example.com
  dnsNames:
  - example.com
  - www.example.com

Operator SDK

Operator 개발 도구

1
2
3
4
5
6
7
8
9
10
# Operator SDK 설치
brew install operator-sdk

# Go 기반 Operator 생성
operator-sdk init --domain example.com --repo github.com/example/myoperator
operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller

# Helm 기반 Operator
operator-sdk init --plugins helm --domain example.com
operator-sdk create api --group cache --version v1alpha1 --kind Memcached --helm-chart ./helm-charts/memcached

Reconciliation Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 간단한 Reconcile 함수 예시 (Go)
func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // 1. Custom Resource 가져오기
    var database myv1.Database
    if err := r.Get(ctx, req.NamespacedName, &database); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // 2. 원하는 상태 정의
    desiredDeployment := r.deploymentForDatabase(&database)

    // 3. 현재 상태 확인
    var currentDeployment appsv1.Deployment
    err := r.Get(ctx, types.NamespacedName{...}, &currentDeployment)

    // 4. 상태 조정 (Reconcile)
    if errors.IsNotFound(err) {
        // 생성
        r.Create(ctx, desiredDeployment)
    } else {
        // 업데이트
        r.Update(ctx, desiredDeployment)
    }

    // 5. 상태 업데이트
    database.Status.State = "Running"
    r.Status().Update(ctx, &database)

    return ctrl.Result{}, nil
}

Aggregated API Server

CRD의 대안으로, 자체 API Server를 추가할 수 있다.

1
2
3
4
5
6
7
┌─────────────────────────────────────────────────────────────┐
│                    kube-apiserver                            │
├─────────────────────────────────────────────────────────────┤
│  /api/v1             → core API                             │
│  /apis/apps/v1       → apps API                             │
│  /apis/custom.io/v1  → Aggregated API Server (Extension)    │
└─────────────────────────────────────────────────────────────┘

CRD vs Aggregated API:

특성CRDAggregated API
구현 복잡도낮음높음
배포CRD만 적용별도 서버 필요
검증OpenAPI 스키마코드로 구현
서브리소스제한적자유롭게 정의
사용 사례대부분특수 요구사항

Aggregated API가 필요한 경우:

  • metrics.k8s.io (Metrics Server)
  • custom.metrics.k8s.io (Prometheus Adapter)

트러블슈팅

CRD 관련 문제

1
2
3
4
5
6
7
8
9
# CRD가 없을 때 CR 생성 시도
# error: the server doesn't have a resource type "databases"

# CRD 상태 확인
kubectl get crd databases.example.com -o yaml

# CR 검증 에러
kubectl apply -f my-database.yaml
# The Database "my-database" is invalid: spec.engine: Unsupported value

Operator 문제

1
2
3
4
5
6
7
8
# Operator Pod 로그
kubectl logs -n operator-namespace deployment/my-operator

# Operator가 CR을 처리하지 않을 때
# - RBAC 권한 확인
kubectl get clusterrolebinding | grep my-operator
# - ServiceAccount 확인
kubectl get sa -n operator-namespace

기술 면접 대비

자주 묻는 질문

Q: CRD란 무엇이고 왜 사용하는가?

A: CRD(Custom Resource Definition)는 Kubernetes API를 확장하여 새로운 리소스 타입을 추가하는 방법이다. 이를 통해 도메인 특화 리소스(예: Database, Certificate)를 정의하고 kubectl로 관리할 수 있다. Operator 패턴의 기반이 되며, 선언적 API의 장점을 커스텀 애플리케이션에도 적용할 수 있다.

Q: Operator 패턴의 장점은?

A: 운영 지식(업그레이드, 백업, 복구, 스케일링 등)을 코드로 자동화한다. 사용자는 원하는 상태만 선언하면 Operator가 복잡한 운영 작업을 자동으로 처리한다. 일관된 운영 품질을 보장하고, 인적 오류를 줄인다.

Q: CRD와 ConfigMap의 차이는?

A: ConfigMap은 설정 데이터 저장용이고, CRD는 새로운 API 리소스 타입을 정의한다. CRD로 만든 리소스는 kubectl로 CRUD 가능하고, 스키마 검증이 적용되며, Controller와 연동하여 다른 리소스를 생성/관리할 수 있다. ConfigMap은 단순 데이터 저장소이다.

Q: Controller와 Operator의 차이는?

A: Controller는 Kubernetes의 핵심 패턴으로 리소스 상태를 조정한다. Operator는 Controller 패턴을 확장하여 특정 애플리케이션의 전체 생명주기(설치, 업그레이드, 백업, 복구)를 관리한다. 모든 Operator는 Controller이지만, 모든 Controller가 Operator는 아니다.

CKA 시험 대비

CKA에서 CRD/Operator는 심화 주제지만, 기본 개념과 명령어는 알아야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
# CRD 목록
kubectl get crd

# CRD 상세
kubectl describe crd <crd-name>

# Custom Resource 조회
kubectl get <resource-name>
kubectl describe <resource-name> <name>

# Custom Resource 삭제
kubectl delete <resource-name> <name>

다음 단계

This post is licensed under CC BY 4.0 by the author.