Skip to content
Published on

etcd와 Kubernetes: API Server 통합 분석

Authors

etcd와 Kubernetes: API Server 통합 분석

Kubernetes API Server는 etcd를 유일한 데이터 저장소로 사용합니다. 이 글에서는 API Server가 etcd를 어떻게 활용하는지, 키 구조, Watch Cache, 사이징, 암호화 등을 분석합니다.


1. kube-apiserver의 etcd 사용

1.1 Storage Backend

kube-apiserver는 etcd v3 API를 사용하여 모든 Kubernetes 리소스를 저장합니다:

// storage backend 인터페이스 (간략화)
type Interface interface {
    Create(ctx context.Context, key string, obj runtime.Object, ...) error
    Delete(ctx context.Context, key string, ...) error
    Get(ctx context.Context, key string, ...) error
    List(ctx context.Context, key string, ...) error
    Watch(ctx context.Context, key string, ...) (watch.Interface, error)
    GuaranteedUpdate(ctx context.Context, key string, ...) error
}

1.2 Codec (직렬화/역직렬화)

Kubernetes 리소스는 etcd에 저장되기 전에 직렬화됩니다:

  • protobuf: 기본 저장 형식 (효율적인 바이너리)
  • JSON: 대체 형식 (디버깅 용이)
  • CBOR: 실험적 지원

API Server는 리소스를 저장할 때 내부 버전(internal version)에서 저장 버전(storage version)으로 변환한 뒤 직렬화합니다.

1.3 Transformer (암호화)

Transformer는 etcd에 저장되기 전/후에 데이터를 변환합니다:

  • Identity: 변환 없음 (기본)
  • AES-CBC: AES 대칭 키 암호화
  • AES-GCM: AES 인증 암호화
  • KMS: 외부 Key Management Service 사용
  • Secretbox: NaCl Secretbox 암호화
Write: Object -> Serialize -> Encrypt -> etcd
Read:  etcd -> Decrypt -> Deserialize -> Object

2. etcd 키 계층 구조

2.1 /registry/ 접두사

모든 Kubernetes 리소스는 /registry/ 접두사 아래에 저장됩니다:

/registry/pods/default/my-pod
/registry/pods/kube-system/coredns-xxx
/registry/services/specs/default/kubernetes
/registry/deployments/default/my-deployment
/registry/configmaps/default/my-config
/registry/secrets/default/my-secret
/registry/namespaces/default
/registry/nodes/node-1

2.2 키 구조 패턴

네임스페이스 리소스:

/registry/RESOURCE_TYPE/NAMESPACE/NAME

클러스터 리소스:

/registry/RESOURCE_TYPE/NAME

2.3 리소스 인코딩

etcd에 저장된 데이터의 구조:

# etcdctl로 실제 저장된 데이터 확인
etcdctl get /registry/pods/default/my-pod --print-value-only | \
  head -c 50
# k8s(protobuf binary prefix)...

protobuf로 인코딩된 바이너리 데이터입니다. 디코딩하면 PodSpec, PodStatus 등의 구조체를 확인할 수 있습니다.

2.4 키 목록 확인

# 모든 키 접두사 확인
etcdctl get /registry --prefix --keys-only | head -30

# 특정 리소스 타입의 키 확인
etcdctl get /registry/deployments --prefix --keys-only

3. Watch Cache

3.1 Watch Cache가 필요한 이유

API Server가 모든 Watch 요청을 직접 etcd에 전달하면:

  • etcd에 과도한 부하 발생
  • 네트워크 대역폭 낭비
  • 확장성 제한

Watch Cache는 API Server 내부에서 etcd Watch를 캐싱하여 이 문제를 해결합니다.

3.2 Cacher 구조

// Cacher는 etcd watch를 캐싱하는 계층
type Cacher struct {
    storage     storage.Interface    // 실제 etcd backend
    watchCache  *watchCache          // 캐시된 이벤트 히스토리
    reflector   *cache.Reflector     // etcd watch 리플렉터
    watchers    indexedWatchers       // 등록된 watcher 목록
}

3.3 동작 방식

  1. Reflector: API Server 시작 시 각 리소스 타입에 대해 etcd Watch를 설정
  2. Watch Cache: etcd에서 수신한 이벤트를 링 버퍼에 캐싱
  3. 클라이언트 Watch: 클라이언트의 Watch 요청은 캐시에서 서비스
etcd --[watch]--> Reflector --[events]--> Watch Cache --[events]--> Client Watchers

3.4 Watch Cache 크기

Watch Cache의 링 버퍼 크기는 리소스 타입별로 설정됩니다:

  • 기본값: 100개 이벤트
  • --watch-cache-sizes로 리소스별 커스텀 설정 가능
  • --watch-cache=false로 캐시 비활성화 가능 (비권장)

3.5 List 요청 처리

List 요청도 Watch Cache에서 서비스됩니다:

  • 캐시가 최신이면 etcd 접근 없이 응답
  • resourceVersion=0: 캐시에서 즉시 반환
  • resourceVersion 지정: 해당 버전 이상이 캐시에 있으면 반환

4. etcd 사이징

4.1 오브젝트 수 기반 사이징

Kubernetes 클러스터 규모에 따른 etcd 사이징:

클러스터 규모노드 수Pod 수권장 etcd디스크
소규모10-501000 이하3노드, 2 CPU, 8GB50GB SSD
중규모50-2005000 이하3노드, 4 CPU, 16GB100GB SSD
대규모200-100050000 이하5노드, 8 CPU, 32GB200GB SSD

4.2 요청 빈도 고려

etcd 부하에 영향을 미치는 요인:

  • Pod 생성/삭제 빈도
  • ConfigMap/Secret 업데이트 빈도
  • Watch 수 (컨트롤러, kubelet 등)
  • Custom Resource 수와 크기

4.3 DB 크기 관리

  • 기본 quota: 2GB (--quota-backend-bytes)
  • 최대 권장: 8GB
  • 정기적 컴팩션과 디프래그멘테이션 필수
  • 모니터링으로 DB 크기 추적

5. Encryption at Rest

5.1 EncryptionConfiguration

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: BASE64_ENCODED_KEY
      - identity: {}

5.2 프로바이더 우선순위

providers 배열에서 첫 번째 프로바이더가 쓰기에 사용되고, 모든 프로바이더가 읽기에 사용됩니다. 이를 통해 키 순환이 가능합니다:

  1. 새 키를 첫 번째 위치에 추가
  2. kube-apiserver 재시작
  3. 기존 Secret을 모두 다시 쓰기 (새 키로 암호화)
  4. 이전 키 제거

5.3 KMS 프로바이더 (v2)

KMS v2 프로바이더는 더 효율적인 키 관리를 제공합니다:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - kms:
          apiVersion: v2
          name: my-kms-plugin
          endpoint: unix:///var/run/kms-plugin/socket.sock

KMS v2의 장점:

  • DEK(Data Encryption Key)를 로컬에서 생성하고 캐싱
  • KEK(Key Encryption Key)만 원격 KMS에서 관리
  • 키 순환 시 API 서버 재시작 불필요
  • 성능 오버헤드 최소화

5.4 암호화 상태 확인

# Secret이 암호화되어 있는지 확인
etcdctl get /registry/secrets/default/my-secret | hexdump -C | head

# 암호화된 경우 'k8s:enc:aescbc:v1:key1' 같은 접두사가 보임
# 암호화되지 않은 경우 'k8s' protobuf 접두사가 보임

6. API Server와 etcd 연결 설정

6.1 주요 플래그

kube-apiserver \
  --etcd-servers=https://etcd1:2379,https://etcd2:2379,https://etcd3:2379 \
  --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt \
  --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt \
  --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key \
  --etcd-compaction-interval=5m \
  --encryption-provider-config=/etc/kubernetes/encryption-config.yaml \
  --watch-cache=true \
  --default-watch-cache-size=100

6.2 연결 상태 모니터링

# API Server의 etcd 연결 메트릭
- etcd_request_duration_seconds # etcd 요청 지연
- etcd_object_counts # 리소스별 오브젝트 수
- apiserver_storage_size_bytes # 저장소 크기

7. 정리

Kubernetes API Server와 etcd의 통합은 클러스터 운영의 핵심입니다. Watch Cache를 통한 효율적인 캐싱, 적절한 키 구조 이해, Encryption at Rest 설정, etcd 사이징은 안정적인 클러스터 운영에 필수적입니다. etcd의 건강 상태를 지속적으로 모니터링하고, 정기적인 백업과 유지보수를 수행하는 것이 중요합니다.