① kubectl apply -f deployment.yaml
│
│ HTTP POST
▼
② K8s API Server
├── Authentication (누구냐)
├── Authorization (RBAC 권한 있냐)
├── Admission Controller
│ ├── Mutating Webhook
│ └── Validating Webhook
└── etcd에 Deployment 객체 저장
│
│ watch event 발행
▼
③ Deployment Controller (Controller Manager 내부)
"replicas: 3인데 ReplicaSet이 없네?"
→ API Server에 ReplicaSet 생성 요청 → etcd 저장
│
│ watch event 발행
▼
④ ReplicaSet Controller (Controller Manager 내부)
"Pod 0개인데 3개 필요하네?"
→ API Server에 Pod 3개 생성 요청 → etcd 저장
(이 시점에 Pod는 nodeName이 비어있는 Pending 상태)
│
│ watch event 발행
▼
⑤ Scheduler
├── Filtering: 리소스 충분한가, taint/toleration 맞는가
├── Scoring: 가장 적합한 노드 선택
└── pod.spec.nodeName 업데이트 → API Server에 요청 → etcd 저장
(Pod 1 → Node A, Pod 2 → Node B, Pod 3 → Node A)
│
│ watch event 발행
▼
⑥ Kubelet (해당 노드의)
API Server에서 "내 노드에 배정된 Pod" 수신
│
│ CRI (gRPC)
▼
⑦ containerd
├── 이미지 pull (registry에서)
├── 이미지 언팩 → rootfs 생성
├── OCI 번들 생성 (config.json + rootfs)
└── shim 프로세스 생성
│
│ ttrpc (경량 gRPC)
▼
⑧ containerd-shim-runc-v2
runc 바이너리를 exec으로 실행
│
│ exec (프로세스 실행)
▼
⑨ runc
OCI 번들을 입력으로 받아서
├── libcontainer를 사용해서
│ ├── namespace 생성
│ ├── cgroup 설정
│ ├── pivot_root
│ ├── seccomp, capabilities 설정
│ └── 컨테이너 프로세스 시작
└── runc 프로세스 종료 (exit) ← runc는 빠진다
│
▼
⑩ shim이 컨테이너 관리 인수
├── 컨테이너 프로세스의 부모가 됨 (runc가 exit했으므로)
├── stdin/stdout/stderr 관리
├── 컨테이너 상태 모니터링
└── containerd에 "생성 완료" 보고
│
│ ttrpc
▼
⑪ containerd → Kubelet에 CRI 응답 "컨테이너 생성 완료"
│
▼
⑫ Kubelet
├── app container만 실행 (sidecar 없음)
├── readiness probe 체크
└── Pod 상태를 Running으로 API Server에 보고
│
│ watch event 발행
▼
⑬ Endpoints Controller(controller manager 중 1개)
"Pod가 Ready됐네?"
→ 해당 Pod IP를 Service의 Endpoints에 추가
→ API Server에 요청 → etcd 저장
│
│ watch event 발행
▼
⑭ kube-proxy (각 노드의)
Endpoints 변경 감지
→ iptables/IPVS 규칙 업데이트
→ ClusterIP로 오는 트래픽을 실제 Pod IP로 NAT
→ 트래픽 수신 가능 상태 완료