Split View: etcd와 Kubernetes: API Server 통합 분석
etcd와 Kubernetes: API Server 통합 분석
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 동작 방식
- Reflector: API Server 시작 시 각 리소스 타입에 대해 etcd Watch를 설정
- Watch Cache: etcd에서 수신한 이벤트를 링 버퍼에 캐싱
- 클라이언트 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-50 | 1000 이하 | 3노드, 2 CPU, 8GB | 50GB SSD |
| 중규모 | 50-200 | 5000 이하 | 3노드, 4 CPU, 16GB | 100GB SSD |
| 대규모 | 200-1000 | 50000 이하 | 5노드, 8 CPU, 32GB | 200GB 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 배열에서 첫 번째 프로바이더가 쓰기에 사용되고, 모든 프로바이더가 읽기에 사용됩니다. 이를 통해 키 순환이 가능합니다:
- 새 키를 첫 번째 위치에 추가
- kube-apiserver 재시작
- 기존 Secret을 모두 다시 쓰기 (새 키로 암호화)
- 이전 키 제거
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의 건강 상태를 지속적으로 모니터링하고, 정기적인 백업과 유지보수를 수행하는 것이 중요합니다.
etcd and Kubernetes: API Server Integration Analysis
etcd and Kubernetes: API Server Integration Analysis
The Kubernetes API Server uses etcd as its sole data store. This post analyzes how the API Server utilizes etcd, including key structure, Watch Cache, sizing, and encryption.
1. kube-apiserver etcd Usage
1.1 Storage Backend
kube-apiserver stores all Kubernetes resources using the etcd v3 API through a storage interface supporting Create, Delete, Get, List, Watch, and GuaranteedUpdate operations.
1.2 Codec (Serialization/Deserialization)
Kubernetes resources are serialized before storage in etcd:
- protobuf: Default format (efficient binary)
- JSON: Alternative format (easier debugging)
- CBOR: Experimental support
1.3 Transformer (Encryption)
Transformers convert data before/after etcd storage: Identity (none), AES-CBC, AES-GCM, KMS, or Secretbox encryption.
2. etcd Key Hierarchy
2.1 /registry/ Prefix
All Kubernetes resources are stored under the /registry/ prefix:
/registry/pods/default/my-pod
/registry/services/specs/default/kubernetes
/registry/deployments/default/my-deployment
/registry/secrets/default/my-secret
/registry/namespaces/default
/registry/nodes/node-1
2.2 Key Structure Patterns
Namespaced resources: /registry/RESOURCE_TYPE/NAMESPACE/NAME
Cluster resources: /registry/RESOURCE_TYPE/NAME
2.3 Resource Encoding
Data is stored as protobuf-encoded binary. Decoding reveals PodSpec, PodStatus, and other structures.
3. Watch Cache
3.1 Why Watch Cache is Needed
Without Watch Cache, all Watch requests would go directly to etcd causing excessive load, wasted bandwidth, and limited scalability.
3.2 Cacher Structure
type Cacher struct {
storage storage.Interface // actual etcd backend
watchCache *watchCache // cached event history
reflector *cache.Reflector // etcd watch reflector
watchers indexedWatchers // registered watcher list
}
3.3 How It Works
- Reflector: Sets up etcd Watch for each resource type at API Server startup
- Watch Cache: Caches events from etcd in a ring buffer
- Client Watch: Client Watch requests are served from cache
etcd --[watch]--> Reflector --[events]--> Watch Cache --[events]--> Client Watchers
3.4 List Request Processing
List requests are also served from Watch Cache when the cache is current, avoiding etcd access.
4. etcd Sizing
4.1 Object Count Based Sizing
| Cluster Scale | Nodes | Pods | Recommended etcd | Disk |
|---|---|---|---|---|
| Small | 10-50 | Under 1000 | 3 nodes, 2 CPU, 8GB | 50GB SSD |
| Medium | 50-200 | Under 5000 | 3 nodes, 4 CPU, 16GB | 100GB SSD |
| Large | 200-1000 | Under 50000 | 5 nodes, 8 CPU, 32GB | 200GB SSD |
4.2 Request Rate Considerations
Factors affecting etcd load: Pod creation/deletion frequency, ConfigMap/Secret updates, Watch count, Custom Resource count and size.
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 Provider Priority
The first provider in the array is used for writes; all providers are used for reads. This enables key rotation:
- Add new key at first position
- Restart kube-apiserver
- Rewrite all Secrets (encrypted with new key)
- Remove old key
5.3 KMS Provider (v2)
KMS v2 provides more efficient key management: local DEK generation/caching, remote KEK management, no API server restart for rotation, minimal overhead.
5.4 Verifying Encryption Status
etcdctl get /registry/secrets/default/my-secret | hexdump -C | head
# Encrypted: 'k8s:enc:aescbc:v1:key1' prefix visible
# Unencrypted: 'k8s' protobuf prefix visible
6. API Server etcd Connection Configuration
6.1 Key Flags
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
7. Summary
The integration between Kubernetes API Server and etcd is central to cluster operations. Efficient caching through Watch Cache, understanding key structure, configuring Encryption at Rest, and proper etcd sizing are essential for stable cluster operations. Continuous monitoring of etcd health and regular backup/maintenance are critical.