Kubernetes 내부 들여다보기: 스케줄링부터 Service Mesh, 스토리지·보안까지
kube-scheduler의 필터링·점수화 과정, Pod 생명주기와 Health Check, Istio Service Mesh, PV/PVC, RBAC까지 Kubernetes 운영의 핵심 구조를 정리한다
2026-08-12 · 최초 발행 2026-01-16
Pod 수가 수백 개를 넘어가면 사람이 어디에 뭘 띄울지 손으로 정하는 건 불가능해진다. Kubernetes가 하는 일은 결국 이 배치·감시·복구를 자동화하는 것인데, 그 안을 들여다보면 스케줄러가 어떻게 노드를 고르고, Pod가 어떤 상태를 거치며, Service Mesh가 왜 필요해지는지가 하나로 이어진다.
Control Plane과 Worker Node가 나누는 역할
클러스터의 두뇌는 Control Plane이다. kube-apiserver는 모든 작업의 진입점으로 RESTful API를 통해 클러스터 상태를 조회·변경하고 인증·인가를 처리하며 etcd와 통신해 상태를 저장한다. etcd는 Raft 알고리즘 기반의 분산 키-값 저장소로, 고가용성을 위해 3·5·7개처럼 홀수 개 노드로 구성한다. kube-scheduler는 새 Pod를 실행할 최적의 노드를 고르는데, 리소스 요구사항·친화성(Affinity)·Taint/Toleration을 고려하고 우선순위·선점 정책까지 적용한다. kube-controller-manager는 여러 컨트롤러의 묶음이다 — Node Controller가 노드 상태를, Replication Controller가 Pod 복제본 수를, Endpoint Controller가 Service와 Pod 연결을, ServiceAccount Controller가 네임스페이스별 기본 계정을 관리한다.
실제 컨테이너가 도는 곳은 Worker Node다. kubelet은 각 노드에서 돌아가는 에이전트로 PodSpec에 따라 컨테이너를 실행하고 상태·Health Check를 감시하며 Control Plane에 보고한다. kube-proxy는 iptables나 IPVS 모드로 트래픽을 라우팅하며 Service에 가상 IP를 할당·관리한다. 실제 컨테이너 실행과 이미지 관리는 containerd, CRI-O, Docker 같은 Container Runtime이 담당한다.
스케줄러는 어떻게 노드를 고르는가
kube-scheduler는 두 단계를 거친다. 먼저 필터링으로 애초에 Pod를 못 올릴 노드를 걸러낸다 — CPU·메모리 요구사항을 충족하는지(PodFitsResources), 포트가 충돌하지 않는지(PodFitsHostPorts), 볼륨 마운트가 충돌하지 않는지(NoDiskConflict), 노드 레이블 기반 배치 제약을 만족하는지(NodeAffinity)를 확인한다. 남은 후보 중에서 점수화 단계가 최적 노드를 고른다 — 리소스 사용률이 낮은 노드를 선호하는 LeastRequestedPriority, CPU와 메모리 사용을 균형 있게 분산하는 BalancedResourceAllocation, 이미 이미지가 있는 노드를 우대하는 ImageLocalityPriority, 특정 노드를 회피하는 NodePreferAvoidPods 같은 기준이 점수를 매긴다.
이 기본 로직 위에 세밀한 제어를 얹을 수 있다. Node Affinity는 특정 조건의 노드에만 Pod를 배치한다.
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- ap-northeast-2a
Pod Anti-Affinity는 반대로 특정 Pod와 같은 노드에 배치되지 않도록 해서 가용 영역(Availability Zone)에 분산 배치하고 고가용성을 확보하는 데 쓴다. Taint와 Toleration은 한 쌍으로 동작한다 — 노드에 Taint를 걸면(예: GPU 전용 노드) 그 조건을 허용하는 Toleration을 가진 Pod만 스케줄링되며, 효과는 NoSchedule·PreferNoSchedule·NoExecute 세 가지로 나뉜다.
Pod가 살아있는 동안 벌어지는 일
Pod는 스케줄링이 끝나고 컨테이너가 시작되면 Pending에서 Running으로 넘어가고, 정상 종료면 Succeeded, 비정상 종료면 Failed, 노드와 통신이 끊기면 Unknown 상태가 된다. Unknown은 노드가 복구되면 다시 Running으로, 타임아웃이 나면 Failed로 넘어간다.
이 상태를 건강하게 유지하는 게 세 종류의 Probe다. Liveness Probe는 컨테이너가 정상 작동하는지 확인하고 실패하면 kubelet이 컨테이너를 재시작한다. Readiness Probe는 트래픽을 받을 준비가 됐는지 확인해서 실패하면 Service Endpoint에서 빠지는데, 초기화 작업이 끝날 때까지 기다리는 용도로도 쓴다. Startup Probe는 시작이 느린 컨테이너를 보호하는 역할로, 이게 성공하기 전까지는 Liveness·Readiness Probe가 비활성화된다. 세 Probe 모두 HTTP GET, TCP Socket, Exec 방식을 지원한다.
리소스 관리는 Requests(보장받는 최소 리소스)와 Limits(사용 가능한 최대 리소스)로 이뤄지고, 이 설정에 따라 Pod는 Guaranteed·Burstable·BestEffort 중 하나의 QoS 클래스를 갖는다. 트래픽에 따라 Pod 수를 자동으로 조정하는 Horizontal Pod Autoscaler(HPA)는 CPU/메모리 메트릭뿐 아니라 큐 길이 같은 커스텀 메트릭도 활용할 수 있고, 급격한 변동을 막기 위한 Cooldown 기간을 둔다.
트래픽이 Pod까지 도달하는 경로
Service에는 네 가지 타입이 있다. 클러스터 내부에서만 접근되는 기본값 ClusterIP, 각 노드의 30000~32767 범위 포트로 외부 접근을 여는 NodePort, 클라우드 프로바이더의 로드 밸런서를 만들어 외부 트래픽을 분산하는 LoadBalancer, 그리고 DNS CNAME 레코드를 반환해 외부 서비스를 추상화하는 ExternalName이다.
여러 Service를 도메인·경로 기준으로 정리해서 노출하려면 Ingress가 필요하다. 호스트 기반·경로 기반 라우팅 규칙을 정의하고 TLS/SSL 인증서를 관리하며, 이걸 실제로 동작시키려면 Nginx나 Traefik 같은 Ingress Controller가 있어야 한다.
Service Mesh가 필요해지는 시점
마이크로서비스가 늘어나면 서비스 간 통신 자체를 관리하는 인프라 레이어가 필요해진다. Service Mesh는 이 통신을 애플리케이션 코드와 독립적으로 제어해 보안·관찰성·신뢰성을 강화한다.
Istio가 대표적인 구현체다. Data Plane은 각 Pod에 Envoy Proxy를 사이드카로 주입해 모든 인바운드·아웃바운드 트래픽을 가로채고, L7 로드 밸런싱·서킷 브레이커·타임아웃을 적용한다. Control Plane인 Istiod는 이 설정을 배포하고 Envoy를 관리하며, 서비스 디스커버리 정보를 동기화하고 mTLS용 인증서를 발급·관리한다.
트래픽 관리 쪽에서는 Virtual Service로 라우팅 규칙을, Destination Rule로 로드 밸런싱 정책과 서킷 브레이커를, Gateway로 클러스터 진입점을 정의하며 A/B 테스팅과 Canary 배포를 지원한다. 보안 쪽에서는 mTLS를 자동 적용해 서비스 간 통신을 암호화하고 Authorization Policy로 세밀하게 접근을 제어한다. 관찰성 쪽에서는 Jaeger·Zipkin으로 분산 추적을, Prometheus로 메트릭을 수집하고 Kiali로 서비스 메시 전체를 시각화한다.
상태를 유지하는 스토리지
Kubernetes는 기본적으로 Pod가 언제든 죽고 다시 뜨는 걸 전제하지만, DB나 큐처럼 상태를 유지해야 하는 애플리케이션도 있다. Persistent Volume(PV)은 클러스터 수준의 스토리지 리소스로 NFS, iSCSI, EBS·GCE PD 같은 클라우드 스토리지를 지원하며 Reclaim Policy로 Retain·Delete·Recycle 중 하나를 선택한다. Persistent Volume Claim(PVC)은 사용자가 스토리지를 요청하는 방식으로, Storage Class를 통해 동적으로 프로비저닝되고 Pod에 볼륨으로 마운트된다. StatefulSet은 이런 상태 유지 애플리케이션을 위한 워크로드 타입으로, 안정적인 네트워크 ID와 영구 스토리지를 보장하며 순차적으로 배포·종료한다.
보안은 여러 겹으로 쌓는다
RBAC(Role-Based Access Control)는 네임스페이스 범위의 권한인 Role과 클러스터 전체 권한인 ClusterRole을 RoleBinding·ClusterRoleBinding으로 사용자에게 연결하는 구조다. Pod 자체의 보안은 Pod Security Standards(Privileged·Baseline·Restricted)와 runAsUser·fsGroup 같은 Security Context, 그리고 Network Policy로 트래픽 자체를 격리하는 방식으로 강화한다. 민감 정보는 Secrets로 관리하는데, 기본은 Base64 인코딩으로 저장해 환경 변수나 볼륨으로 주입하지만, 더 강한 보안이 필요하면 Vault나 AWS Secrets Manager 같은 외부 시크릿 관리 도구와 연동한다.
스케줄링 알고리즘이 자원을 효율적으로 배치하고 Service Mesh가 서비스 간 통신의 복잡성을 코드 밖으로 빼내는 걸 이해하면, 대규모 컨테이너 환경도 손이 덜 가는 방식으로 운영할 수 있다. Service Mesh는 필수는 아니지만, 마이크로서비스가 수십 개를 넘어가는 시점부터는 관찰성과 보안에서 얻는 이득이 도입 비용을 넘어선다.