Kubernetes 지속성 시리즈 파트 3: 컨트롤러와 복원력 — 왜 Kubernetes는 자체 치유되는가
I’m happy to translate the article for you, but I need the text you’d like translated. Could you please paste the content of the article (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you requested.
배울 내용
- 애플리케이션 컨트롤러(NGINX Ingress, cert‑manager)가 퇴거(eviction) 상황에서도 어떻게 지속되는지
- 컨트롤러가 무상태(stateless)이며 어디서든 재시작될 수 있는 이유
- 하드웨어부터 애플리케이션까지의 전체 지속성 체인
- 파드 퇴거 시 살아남는 것과 그렇지 않은 것
이전
- Part 1 – GKE 노드 업그레이드 후 사라진 인그리스를 디버깅했습니다.
- Part 2 –
systemd가kubelet을 감독하는 방식과kubelet이 정적 팟을 통해 컨트롤 플레인을 부트스트랩하는 방법을 탐구했습니다.
이제 최종 단계인 애플리케이션 컨트롤러에 도달했습니다—그리고 Kubernetes를 진정으로 탄력 있게 만드는 우아한 통찰력입니다.
Source:
Layer 4: Application Controllers
Application Controllers가 상태를 유지하는 방법
NGINX Ingress, cert‑manager, Prometheus Operator와 같은 컨트롤러는 일반적으로 Deployment 또는 StatefulSet으로 배포됩니다:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
template:
spec:
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.9.0
이 파드가 퇴거될 때:
- kubelet이 파드 보고를 중단 → 컨트롤 플레인이 파드를 Terminated 상태로 표시합니다.
- ReplicaSet controller가
currentReplicas (0)을 확인합니다 …
핵심 포인트: 컨트롤러 자체는 상태를 저장하지 않으며, API 서버(etcd에 백업됨)에서 모든 정보를 읽어옵니다.
Helm Release 영속성
Helm은 릴리스 정보를 Kubernetes Secret에 저장합니다:
kubectl get secret -n monitoring -l owner=helm -o yaml
apiVersion: v1
kind: Secret
metadata:
name: sh.helm.release.v1.prometheus.v3
labels:
owner: helm
name: prometheus
version: "3"
type: helm.sh/release.v1
data:
release: H4sIAAAAAAAAA... # Base64‑encoded release manifest
Secret에 포함되는 내용:
- 설치된 차트
- 사용된 값들
- 모든 리소스의 계산된 매니페스트
이 Secret이 API 서버를 통해 etcd에 저장되기 때문에, Helm 릴리스는 파드 퇴거가 발생해도 유지됩니다.
전체 지속성 체인
┌─────────────────────────────────────────────────────────────────────┐
│ Linux Host (Physical/VM) │
├─────────────────────────────────────────────────────────────────────┤
│ systemd (PID 1) │
│ ├── Supervises all system services │
│ ├── Restarts failed services automatically │
│ └── Config: /etc/systemd/system/ │
│ │ │
│ └── kubelet.service │
│ ├── Started and supervised by systemd │
│ ├── Watches /etc/kubernetes/manifests/ for static pods │
│ ├── Watches API server for scheduled pods │
│ └── Ensures containers match pod specs │
│ │ │
│ ├── Static Pods (/etc/kubernetes/manifests/) │
│ │ ├── etcd ──────────────────┐ │
│ │ ├── kube-apiserver ◄───────┤ Persistent │
│ │ ├── kube-controller-manager│ State Store │
│ │ └── kube-scheduler │ │
│ │ │ │
│ └── Regular Pods ◄─────────────┘ │
│ │ (scheduled via API server) │
│ │ │
│ ├── kube-system namespace │
│ │ ├── CoreDNS │
│ │ ├── kube-proxy │
│ │ └── CNI plugins │
│ │ │
│ ├── ingress-nginx namespace │
│ │ └── NGINX Ingress Controller │
│ │ └── Watches Ingress resources │
│ │ │
│ └── Application namespaces │
│ ├── cert-manager │
│ ├── Prometheus Operator │
│ └── Your applications │
└─────────────────────────────────────────────────────────────────────┘
Source:
핵심 통찰: 컨트롤러는 무상태다
이것이 설계의 우아한 핵심이다: 컨트롤러는 상태를 저장하지 않는다.
| 컨트롤러가 수행하는 작업 | 작동 방식 |
|---|---|
| 원하는 상태를 읽음 | API 서버(etcd가 백엔드)에서 |
| 변경 사항을 감시함 | API 서버의 워치 메커니즘을 통해 |
| 변경을 수행함 | API 서버에 업데이트를 제출함으로써 |
| 어디서든 재시작 가능 | 정보 손실이 없으며; API 서버가 단일 진실 소스 역할을 유지 |
API 서버 + etcd가 단일 진실 소스이며, 컨트롤러 자체가 아니다.

감독 계층 (Mermaid 다이어그램)
flowchart LR
subgraph Source["Source of Truth"]
etcd[(etcd)]
api[API Server]
end
subgraph StatelessControllers["Stateless Controllers"]
deploy[Deployment Controller]
rs[ReplicaSet Controller]
nginx[NGINX Ingress]
cert[cert-manager]
end
etcd -->> api
api -->> deploy
api -->> rs
api -->> nginx
api -->> cert
style etcd fill:#e67700,color:#fff
style api fill:#e67700,color:#fff
(다이어그램이 렌더링되지 않으면 위 코드를 사용하여 Mermaid Live Editor에서 직접 확인하세요.)
왜 이것이 중요한가
- 컨트롤러 포드 삭제 → 재시작하고 상태를 따라잡습니다.
- 컨트롤러를 노드 간 이동 → API 서버에 단순히 재연결합니다.
- 컨트롤러를 여러 복제본으로 확장 → API 서버를 통해 조정합니다.
- 컨트롤러 업그레이드 → 새 버전이 etcd에서 동일한 상태를 읽습니다.
What Survives vs. What Doesn’t
Survives Any Pod Eviction
| Resource | Why It Survives |
|---|---|
| etcd에 저장된 Kubernetes 객체 | 파드와 독립적으로 저장됨 |
| Helm 릴리스 | etcd에 시크릿으로 저장됨 |
| Operator‑managed CRD | Operator가 지속적으로 조정함 |
| PersistentVolumes | 스토리지는 클러스터 외부에 존재 |
| ConfigMaps / Secrets | etcd에 저장됨 |
Doesn’t Survive Without Help
| Resource | Why It Doesn’t Survive |
|---|---|
파드 로컬 EmptyDir 볼륨 | 파드와 함께 삭제됨 |
| 의존성이 누락된 수동 적용 리소스 | 재생성 시 검증 웹훅이 거부 |
| 인메모리 캐시 | 프로세스 재시작 시 메모리 손실 |
| 노드 로컬 상태 | 명시적으로 영구화하지 않으면 손실 |
디자인의 우아함
Kubernetes의 아키텍처는 여러 핵심 설계 원칙을 따릅니다:
- 선언형이 명령형보다 우선 – 원하는 상태를 설명하고, 그 상태에 도달하기 위한 단계는 기술하지 않습니다.
- 조정이 트랜잭션보다 우선 – 지속적으로 원하는 상태로 수렴합니다.
- 무상태 컨트롤러 – 상태는 컨트롤러 프로세스가 아니라 etcd에 저장됩니다.
- 계층적 감독 – 각 계층은 위의 계층을 감시합니다.
- 실패는 정상 – 실패를 방지하기보다 복구를 설계합니다.
이러한 원칙 덕분에 Kubernetes 클러스터는 다음과 같은 상황을 견딜 수 있습니다:
- 노드가 예기치 않게 사라짐.
- 리소스 압박으로 인해 파드가 퇴출됨.
- 네트워크 파티션 발생.
- 롤링 업그레이드 수행.
…그리고 여전히 애플리케이션 가용성을 유지합니다.
결론
Ingress가 누락된 것을 디버깅하는 과정에서 전체 감독 계층을 이해하게 되면, Kubernetes가 회복력을 갖추게 하는 정교한 메커니즘을 알 수 있습니다.
systemd → kubelet → static pods → control plane → controllers → your apps
각 레이어는 다음 레이어를 감독하며, etcd는 어떤 구성 요소가 실패하더라도 살아남는 영구 메모리 역할을 합니다.
핵심 인사이트: Kubernetes는 실패를 방지하지는 않지만 레이어드 감독, etcd에 저장된 영구 상태, 그리고 지속적인 조정 루프를 통해 자동으로 복구합니다.
이것이 Kubernetes의 진정한 힘입니다: 문제가 절대 발생하지 않는 것이 아니라, 문제가 발생했을 때 시스템이 원하는 상태로 스스로 복원할 수 있다는 점입니다.
Series Recap
- Part 1: When Our Ingress Vanished – 모든 것을 시작한 사건.
- Part 2: The Foundation –
systemd → kubelet → control plane. - Part 3: Controllers & Resilience – 쿠버네티스가 자체 복구하는 이유.
추가 읽을거리
이 시리즈가 유용했나요? 쿠버네티스 내부 내용 더 보려면 팔로우하세요!