kubelet: 노드의 핵심 에이전트

쿠버네티스 각 노드에서 실행되는 kubelet의 역할, 파드 실행 과정, livenessProbe/readinessProbe/startupProbe 동작 방식, Static Pod를 다룹니다.

· 6 min read · PALDYN Team

지난 글에서 컨트롤러 매니저와 Reconcile Loop를 살펴봤다. 이번에는 Control Plane의 명령을 받아 실제로 파드를 실행하는 kubelet을 집중적으로 살펴본다.

kubelet의 위치

kubelet은 워커 노드(그리고 컨트롤 플레인 노드)마다 실행되는 노드 에이전트다. K8s 클러스터 내 컴포넌트 중 유일하게 컨테이너로 실행되지 않고 노드의 시스템 서비스로 직접 실행된다. 그 이유는 kubelet이 없으면 파드를 시작하는 것 자체가 불가능하기 때문이다.

# kubelet 서비스 상태 확인
systemctl status kubelet

# kubelet 로그 실시간 확인
journalctl -u kubelet -f

# kubelet 설정 확인 (kubeadm 기준)
cat /var/lib/kubelet/config.yaml

kubelet의 핵심 역할

kubelet 아키텍처

kubelet이 수행하는 주요 작업은 다음과 같다.

파드 스펙 수신: API Server의 Watch API를 통해 자신이 실행해야 할 파드 스펙을 지속적으로 감시한다. 새 파드가 자신의 노드로 스케줄되면 즉시 감지한다.

컨테이너 런타임 통신: CRI(Container Runtime Interface) gRPC를 통해 containerd나 CRI-O에 컨테이너 생성/시작을 지시한다.

볼륨 마운트: CSI(Container Storage Interface)를 통해 PVC에 연결된 볼륨을 마운트한다.

상태 보고: 파드와 노드의 상태를 API Server에 주기적으로 보고한다. 이 보고가 멈추면 Node Controller가 NotReady 처리를 시작한다.

Probe 실행: livenessProbe, readinessProbe, startupProbe를 주기적으로 실행해 파드 건강 상태를 관리한다.

파드 실행 과정

Scheduler가 파드의 nodeName을 설정하면 kubelet이 이를 감지하고 다음 단계를 수행한다.

① PodSpec 검증 및 준비
   - 볼륨 마운트 준비
   - ConfigMap / Secret 주입 준비

② Init Container 실행 (있는 경우)
   - 순서대로 하나씩 실행
   - 모두 성공해야 다음 단계 진행

③ 메인 컨테이너 실행
   - containerd에 이미지 풀(pull) 요청
   - 네트워크 네임스페이스 생성 (CNI 플러그인 호출)
   - 컨테이너 시작

④ Probe 시작
   - startupProbe → 성공 시 livenessProbe/readinessProbe 활성화
# 파드 실행 이벤트 확인 (각 단계 타임스탬프 포함)
kubectl describe pod <pod-name>
# Events:
#   Normal  Scheduled  10s   default-scheduler  Successfully assigned
#   Normal  Pulling    9s    kubelet            Pulling image "myapp:1.0"
#   Normal  Pulled     6s    kubelet            Successfully pulled image
#   Normal  Created    6s    kubelet            Created container app
#   Normal  Started    5s    kubelet            Started container app

Probe 심층 이해

kubelet 헬스 체크 Probe

세 가지 Probe의 용도와 동작 차이를 명확히 이해하는 것이 중요하다.

livenessProbe: “살아있는가?”

실패하면 kubelet이 컨테이너를 재시작한다. 데드락처럼 프로세스는 살아있지만 응답 불가한 상황에 사용한다.

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15   # 시작 후 첫 체크까지 대기
  periodSeconds: 10          # 체크 주기
  failureThreshold: 3        # 3회 연속 실패 시 재시작
  successThreshold: 1        # 1회 성공으로 복구 인정

readinessProbe: “트래픽 받을 준비가 됐는가?”

실패해도 컨테이너를 재시작하지 않는다. 대신 Service의 Endpoints에서 이 파드를 제거해 트래픽을 보내지 않는다. 준비가 완료되면 다시 Endpoints에 추가된다.

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

startupProbe: “시작이 완료됐는가?”

시작이 오래 걸리는 앱(JVM, 대용량 모델 로딩 등)을 위해 초기 유예 기간을 제공한다. startupProbe가 성공할 때까지 livenessProbe와 readinessProbe는 실행되지 않는다.

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30    # 최대 30 * periodSeconds(10) = 300초 대기
  periodSeconds: 10

Probe 방식

세 Probe 모두 다음 세 가지 방식으로 구현할 수 있다.

# HTTP GET
httpGet:
  path: /healthz
  port: 8080
  scheme: HTTPS  # 기본은 HTTP

# TCP 소켓 연결 시도
tcpSocket:
  port: 3306

# 컨테이너 내부 명령 실행 (exit 0이면 성공)
exec:
  command:
  - sh
  - -c
  - "redis-cli ping | grep PONG"

Static Pod

kubelet은 API Server와 완전히 독립적으로 Static Pod를 관리할 수 있다. 특정 디렉터리(/etc/kubernetes/manifests/)에 YAML 파일을 넣으면, kubelet이 감시하다가 자동으로 파드를 생성·관리한다.

kubeadm 방식으로 구성된 클러스터에서는 API Server, etcd, Scheduler, Controller Manager가 모두 Static Pod로 실행된다.

# Static Pod 매니페스트 위치 확인
ls /etc/kubernetes/manifests/
# etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

# Static Pod 수정 (컨트롤 플레인 컴포넌트 설정 변경 예시)
sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml
# 저장하면 kubelet이 자동으로 파드를 재시작

Static Pod는 API Server 없이도 kubelet이 직접 실행하므로, 컨트롤 플레인 자체를 부트스트랩할 때 사용한다.


지난 글: 컨트롤러 매니저(Controller Manager) 이해

다음 글: kube-proxy: 쿠버네티스 네트워크 프록시


읽어주셔서 감사합니다. 😊