3. 워커 노드 분석: 근육은 어떻게 움직이는가?
지난 아티클에서는 컨트롤 플레인(뇌)이 어떻게 클러스터의 상태를 결정하고 명령을 내리는지 알아보았습니다. 하지만 결정만으로는 아무 일도 일어나지 않습니다. 그 명령을 받아 실제로 컨테이너를 띄우고 네트워크를 연결하는 ‘근육’의 역할이 필요합니다. 그 역할을 하는 것이 바로 ‘워커 노드(Worker Node)‘입니다.
이번 글에서는 컨트롤 플레인의 명령이 워커 노드에서 어떻게 실제 애플리케이션으로 실행되는지, 그 과정을 따라가 보겠습니다.
워커 노드의 구성 요소: 현장에서 뛰는 행동대장들
워커 노드는 실제 컨테이너들이 생성되고 실행되는 서버입니다. 각 워커 노드에는 다음과 같은 핵심 ‘에이전트’들이 상주하며 컨트롤 플레인의 명령을 수행합니다.
1. 큐블릿 (kubelet): 컨트롤 플레인의 현장 대리인
- 역할: 각 워커 노드에 딱 한 개씩 존재하는 ‘현장 감독관’입니다. 컨트롤 플레인의 API 서버와 직접 통신하며, 자신의 노드에 할당된 임무를 수행하고 노드의 상태를 보고하는 핵심 에이전트입니다.
- 어떻게 일하는가? (실무적 관점):
- 임무 수령: 큐블릿은 API 서버를 계속 지켜보다가, 자신에게 새로운 파드(Pod)가 할당된 것을 발견합니다. (지난 글에서 스케줄러가 파드를 특정 노드에 배정했던 것을 기억하세요.)
- 작업 지시: 큐블릿은 파드의 명세서(Pod Spec)를 읽습니다. “A 컨테이너는
nginx:1.19이미지로 만들고, B 컨테이너는redis:latest이미지로 만들어라” 같은 지시사항을 확인합니다. - 실행: 확인한 내용을 바탕으로, 컨테이너 런타임(예: Docker)에게 실제로 컨테이너를 생성하고 실행하라고 명령합니다.
- 상태 보고: 파드와 컨테이너가 정상적으로 실행되는지, 노드의 CPU나 메모리 상태는 어떤지 등을 주기적으로 체크하여 API 서버에 보고합니다. 이 보고 내용이
etcd에 ‘현재 상태’로 기록됩니다.
- 비유: 본사(컨트롤 플레인)로부터 설계도(파드 명세)를 받은 공장의 ‘현장 소장’. 현장 소장은 작업자(컨테이너 런타임)에게 지시하여 제품(컨테이너)을 만들게 하고, 진행 상황과 공장 상태를 본사에 계속 보고합니다.
2. 큐브 프록시 (kube-proxy): 클러스터의 네트워크 담당
- 역할: 각 워커 노드의 ‘네트워크 배관공’입니다. 클러스터 내의 복잡한 네트워크 규칙을 관리하며, 파드들이 서로, 그리고 외부와 통신할 수 있도록 길을 만들어주는 역할을 합니다.
- 왜 필요한가? (실무적 관점): 파드는 언제든 죽고 새로 생성될 수 있기 때문에 IP 주소가 계속 바뀝니다. 만약 프론트엔드 파드가 백엔드 파드의 IP 주소를 직접 알고 있다면, 백엔드 파드가 재시작될 때마다 통신이 끊길 겁니다.
kube-proxy는 중간에 ‘서비스(Service)‘라는 고정된 주소를 두고, 이 주소로 오는 요청을 실제 동작 중인 파드들의 IP로 연결해주는 ‘라우팅’ 규칙을 모든 노드에 설정합니다. 덕분에 파드의 IP가 바뀌어도 서비스 이름만 알면 안정적으로 통신할 수 있습니다. - 비유: 대형 빌딩의 ‘내선 교환원’. 교환원은 각 직원(파드)의 실제 자리(IP 주소)를 모두 알고 있습니다. 외부에서 “영업팀(서비스) 연결해주세요”라는 전화가 오면, 교환원은 현재 통화 가능한 영업팀 직원의 자리로 전화를 연결해줍니다. 직원의 자리가 바뀌어도 외부에서는 ‘영업팀’ 대표 번호로만 전화하면 됩니다.
3. 컨테이너 런타임 (Container Runtime): 실제 컨테이너 엔진
- 역할: 컨테이너를 실제로 생성하고 실행하는 ‘엔진’입니다. 가장 유명한 것이 ‘도커(Docker)‘이지만,
containerd,CRI-O등 다른 런타임도 있습니다. - 어떻게 일하는가?: 큐블릿이 컨테이너 런타임에게 “이 이미지로 컨테이너를 시작해줘”라고 표준화된 방식(CRI: Container Runtime Interface)으로 요청하면, 컨테이너 런타임이 그에 맞춰 컨테이너를 실행합니다. 큐블릿은 ‘지시’를, 컨테이너 런타임은 ‘실행’을 담당하는 철저한 역할 분담이 이루어집니다.
- 비유: 자동차의 ‘엔진’. 운전자(큐블릿)가 액셀을 밟으면(명령), 엔진(컨테이너 런타임)이 실제로 연료를 태워 바퀴를 굴립니다.
컨트롤 플레인과 워커 노드의 협업 완성 (스토리 완결)
지난 글의 마지막 장면에서 이어가 봅시다. 스케줄러는 ‘파드 A’를 ‘노드 1’에 배정했습니다.
- 큐블릿 (임무 발견): ‘노드 1’에 있던 큐블릿이 API 서버를 통해 자신에게 ‘파드 A’가 할당된 것을 확인합니다.
- 큐블릿 (작업 지시): 큐블릿은 파드 A의 명세서를 읽고, ‘컨테이너 런타임’에게 “
my-app:v1이미지로 컨테이너를 시작해줘”라고 명령합니다. - 컨테이너 런타임 (실행): 컨테이너 런타임은 이미지를 다운로드하고 컨테이너를 실행시킵니다.
- 큐브 프록시 (네트워크 준비): 한편, 클러스터의 모든 노드에 있던 큐브 프록시들은
my-app-service가 새로 생긴 ‘파드 A’를 포함해야 한다는 것을 API 서버를 통해 전달받고, 각자의 네트워크 규칙을 업데이트합니다. - 큐블릿 (상태 보고): ‘파드 A’가 성공적으로 실행되자, ‘노드 1’의 큐블릿은 API 서버에 “파드 A 정상 동작 중”이라고 보고합니다. 이로써
etcd의 ‘현재 상태’가 ‘원하는 상태’와 일치하게 됩니다. - 서비스 시작: 이제 외부 사용자가 서비스를 요청하면, 큐브 프록시가 만든 네트워크 길을 따라 새로 생성된 ‘파드 A’에게도 트래픽이 전달되기 시작합니다.
이처럼 쿠버네티스는 ‘뇌’의 결정과 ‘근육’의 실행이라는 명확한 역할 분담과 유기적인 협업을 통해, 복잡한 컨테이너 환경을 안정적으로 자동 관리합니다.
다음 아티클
다음 아티클
작성일: 2025-10-30