콘텐츠로 바로가기

Kubernetes Pod

Kubernetes의 최소 배포 단위. 하나 이상의 컨테이너가 네트워크와 스토리지를 공유하는 논리 호스트. 컨테이너는 격리 단위, Pod는 배포 단위. 사이드카 패턴(로깅, 프록시)이 Pod의 다중 컨테이너를 활용. `CrashLoopBackOff`: 컨테이너가 ...

Article
M

Me

hyunyoun's Blog

software-engineering-devopssoftware-engineeringdev-opsreliabilitykubernetes-podcicddelivery-platform10 min read

1. Overview

쿠버네티스 파드의 물리 법칙(Kubernetes Pod Physics)은 컨테이너 한두 개를 손으로 띄우며 만족하던 수준을 넘어, 수천 대의 서버 위에 흩뿌려진 컨테이너들의 생사와 네트워킹을 자율 주행으로 통제하는 K8s 오케스트레이션의 세포 분열 역학을 해부합니다.

학습자는 왜 쿠버네티스가 도커 컨테이너를 직접 관리하지 않고, 굳이 한 겹의 추상화 껍질인 **파드(Pod)**라는 고래 뱃속에 컨테이너들을 묶어 넣었는지 그 아키텍처적 의도를 뜯어봅니다. 나아가 파드 안의 컨테이너들이 1개의 IP와 볼륨을 완벽하게 공유하는 **공생(Symbiosis) 관계(사이드카 패턴)**를 장악합니다. 마지막으로 파드가 죽으면 가차 없이 새 파드를 띄워버리는 디플로이먼트(Deployment)의 선언적 복제술과, 휙휙 바뀌는 파드 IP를 하나의 불변 주소로 묶어주는 서비스(Service)의 로드밸런싱 역량을 확보합니다.

2. Scope & Boundaries

In-Scope

  • The Anatomy of Pod: K8s의 최소 배포 단위. 왜 컨테이너 1개가 아니라 Pod 1개인가?
  • Pod Networking: Pause 컨테이너의 역할, Pod 내 컨테이너 간의 localhost 통신과 포트 공유.
  • Sidecar Pattern: 비즈니스 로직(메인 컨테이너)과 로깅/모니터링(사이드카 컨테이너)의 물리적 결합.
  • Ephemeral Physics: 파드는 영원하지 않다(소모품). IP는 항상 바뀐다.

Out-of-Scope

  • K8s 클러스터 설치(Kubeadm): 컨트롤 플레인(Control Plane)과 워커 노드의 하드웨어적 구성 \rightarrow 09-05-01 IaC & Deployment 영역으로 위임.
  • Helm과 GitOps 배포 파이프라인: 템플릿 엔진 및 ArgoCD 동기화 \rightarrow 상위 모듈 09-05-01-04 GitOps로 분리.

Boundaries

  • Docker vs Kubernetes Pod: 도커는 "내 앱을 어떻게 얼려서 예쁘게 감쌀까(패키징)?"의 문제입니다. 쿠버네티스 파드는 "그 얼려진 패키지를 수천 대의 서버에서 어떻게 죽지 않고 돌아가게 할까(스케줄링)?"의 문제입니다. 컨테이너가 '총알'이라면 파드는 그 총알을 쏘는 가장 작은 '탄창' 단위이며, K8s는 그 탄창을 다루는 '군대'임을 명확히 긋습니다.

3. Counterexample

  • 불멸의 파드 (안티 패턴): 쿠버네티스를 처음 쓴 주니어가 DB 파드가 자꾸 죽자, 파드 안에 직접 접속(SSH/exec)해서 며칠 동안 설정을 고쳐 살려냈습니다(Pet 취급). 다음 날 노드(서버)가 통째로 재부팅되자, 공들여 고친 파드는 날아가고 초기 상태의 새 파드가 떠서 DB가 폭발합니다. 파드는 '고쳐 쓰는 애완동물(Pet)'이 아니라 '언제든 죽고 새로 복제되는 가축(Cattle)'이라는 소모품 철학을 무시한 대가입니다.
  • 거대한 메가 파드: 성능을 높이겠다며 하나의 파드 안에 웹서버(Nginx), 백엔드(Spring), 데이터베이스(MySQL) 컨테이너 3개를 몽땅 때려 박았습니다. 웹서버 트래픽이 폭주해서 파드를 10개로 늘리려(Scale-out) 하니, 트래픽이 전혀 없는 뚱뚱한 DB까지 10개로 복제되어 서버 메모리가 붕괴됩니다. 파드의 스케일링 단위를 뭉개버린 최악의 모놀리스 설계입니다.

4. Prerequisites

  • 컨테이너 격리 구조 (Basic): Docker, Image, Port 매핑, Namespace. (09-05-02 Docker)
  • 로드 밸런싱 (Basic): 트래픽 분산과 IP, DNS의 개념. (07. System Architecture)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Ephemeral Unit (Pod) 왜 K8s는 도커를 직접 안 다루고 Pod라는 껍질을 씌웠을까? IP와 디스크를 공유하는 운명 공동체의 탄생 비화를 쥡니다. P1
2 The Pause Container localhost 하나로 파드 안의 두 컨테이너가 대화할 수 있게 네트워크 네임스페이스를 묶어주는 보이지 않는 유령(Pause)을 뜯어봅니다. P5
3 Sidecar Physics 메인 앱은 로직만 돌리고, 옆에 붙은 찰거머리(사이드카)가 로그를 수집해 외부로 쏘는 관심사 분리(SoC)의 아키텍처를 장악합니다. Industry
4 Deployment & Service 10초마다 죽어 나가는 파드의 변덕스러운 IP를 무시하고, 하나의 불변 VIP(Virtual IP)로 묶어내는 서비스(Service)의 마법을 확보합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 운명 공동체의 탄생 (The Ephemeral Unit, Pod)

  • Why to Learn: "도커 컨테이너를 그냥 띄우면 되지, 왜 굳이 파드(Pod)라는 껍질로 한 번 더 감싸서 귀찮게 하는가?"에 대한 아키텍처적 당위성을 깨닫기 위함입니다.
  • What to Learn:
    • Concepts: Pod, Ephemeral (휘발성/소모품), Cattle vs Pet, 1 Pod = 1 IP, Multi-container Pod.
    • Skills: 여러 개의 컨테이너가 "마치 하나의 물리 서버 안에서 도는 것처럼" IP 1개를 나눠 쓰고(포트 분리), 볼륨(디스크)을 서로 공유할 수 있게 묶어내는(Pod) 스케줄링의 최소 단위 설계하기.
  • How to Learn:
    • 1단계: 도커의 한계: 도커 컨테이너 2개를 띄우면 각각 격리된 IP를 가집니다. 둘이 통신하려면 복잡하게 도커 네트워크를 묶어야 합니다.
    • 2단계: 파드의 마법: K8s는 두 컨테이너를 파드라는 고래 뱃속(하나의 논리적 호스트)에 집어넣습니다. 이제 둘은 똑같은 IP 주소를 가집니다! 컨테이너 A가 포트 8080을 쓰고, 컨테이너 B가 8081을 씁니다. 둘은 localhost:8081로 통신합니다. 완벽한 공생 구조입니다.
    • 3단계: 소모품의 철학: 파드는 고장 나면 고쳐 쓰지 않습니다. K8s가 가차 없이 파드를 죽여버리고(Terminate) 똑같은 복제본을 새로 띄웁니다. 따라서 파드 내부에 저장한 데이터는 파드가 죽을 때 함께 영원히 사라지는 휘발성(Ephemeral)의 무서움을 해부합니다.
  • Implement: 파드 내부망 localhost 통신 렌더링. Before (순수 Docker): 앱(IP 172.17.0.2) \rightarrow 로그수집기(IP 172.17.0.3)로 데이터를 보낼 때 상대방 IP를 알아야 함. After (K8s Pod): 앱과 로그수집기가 1개의 파드에 묶임(공용 IP 10.1.1.5). 앱은 고민 없이 localhost:9000으로 쏘면 옆에 있는 컨테이너가 받음. 복잡한 네트워크 매핑이 소멸하는 시각화.

Core Topic 02: 유령 컨테이너 (The Pause Container)

  • Why to Learn: 파드 안의 컨테이너 A가 죽었다 살아나도 어떻게 IP 주소가 바뀌지 않고 localhost 통신이 유지되는지, K8s의 숨겨진 흑마법(Pause Container)을 뜯어내기 위함입니다.
  • What to Learn:
    • Concepts: Pause Container (Infra Container), Network Namespace, PID 1, Lifecycle.
    • Skills: kubectl get pods를 쳐도 눈에 보이지 않지만, 모든 파드가 생성될 때 가장 먼저 떠서 네트워크(IP)를 선점하고 죽을 때까지 버티는 유령 컨테이너의 존재 증명하기.
  • How to Learn:
    • 1단계: 네트워크의 모순: 리눅스에서 컨테이너 A와 B가 localhost를 공유하려면 네트워크 네임스페이스(눈가리개)를 하나로 합쳐야 합니다. 그런데 A 컨테이너가 터져서 재시작하면, 합쳐놨던 네트워크가 붕괴되지 않을까요?
    • 2단계: 유령의 등장: K8s는 파드를 만들 때 무조건 Pause라는 텅 빈 컨테이너를 가장 먼저 띄웁니다. 이 녀석이 IP 주소를 받아옵니다.
    • 3단계: 기생 (Parasitism): 그 후 우리가 지정한 웹서버(Nginx)와 백엔드(Spring) 컨테이너가 뜹니다. 얘네들은 독자적인 IP를 안 받고, Pause 컨테이너의 네트워크에 기생(공유)합니다. 메인 컨테이너가 뻗어서 재시작해도 Pause 녀석이 IP를 꽉 잡고 버텨주므로 파드의 네트워크가 절대 붕괴하지 않는 극한의 설계술을 해부합니다.
  • Implement: Pause 컨테이너 라이프사이클 모델링. Event 1: 파드 스케줄링. K8s가 Pause 컨테이너 구동 \rightarrow IP 할당 완료 (10.5.2.1). Event 2: App 컨테이너 구동 \rightarrow Pause의 IP 공유. Event 3: App 에러로 CrashLoopBackOff 발생. App 컨테이너 종료 후 재시작. 결과: IP는 여전히 10.5.2.1로 불변. 인프라와 앱의 라이프사이클을 분리해 낸 K8s의 기적 렌더링.

Practical

Core Topic 03: 찰거머리 패턴 (Sidecar Physics)

  • Why to Learn: 개발자가 핵심 비즈니스 로직(결제, 로그인)을 짜는 데만 집중할 수 있도록, 지저분한 로그 수집과 모니터링 코드를 옆에 붙인 '찰거머리(Sidecar)'에게 완벽하게 떠넘기는 아키텍처를 구축하기 위함입니다.
  • What to Learn:
    • Concepts: Sidecar Pattern (사이드카 패턴), Ambassador, Adapter, Shared Volume (emptyDir), Separation of Concerns (관심사 분리).
    • Skills: 톰캣(Tomcat) 컨테이너가 뿜어내는 로그 파일을, 옆에 붙은 Fluentd(사이드카) 컨테이너가 공용 볼륨(Volume)을 통해 훔쳐보고 중앙 엘라스틱서치(ElasticSearch)로 쏴주는 2-Container 조합짜기.
  • How to Learn:
    • 1단계: 비즈니스의 오염: 백엔드 코드 안에 "로그를 AWS로 전송해라", "메트릭을 프로메테우스로 쏴라" 하는 잡다한 라이브러리를 덕지덕지 붙입니다. 로직이 더러워지고, 로그 라이브러리가 뻗으면 본체(결제 서버)까지 같이 뻗습니다.
    • 2단계: 사이드카 탑승: 1개의 파드 안에 [결제 컨테이너]와 [로그수집 컨테이너(사이드카)] 2개를 나란히 띄웁니다. 결제 컨테이너는 오직 파일 시스템(/var/log)에 로그 텍스트를 남기고 자기 할 일만 합니다.
    • 3단계: 공유 볼륨 (Shared Volume): 둘은 같은 파드에 있으므로 디스크(emptyDir)를 공유합니다. 사이드카가 디스크에서 로그를 실시간으로 퍼 날라 AWS로 보냅니다. 본체는 사이드카가 옆에 있는지조차 모르며(결합도 제로), 언어/프레임워크에 종속되지 않는 궁극의 모듈화를 뜯어봅니다.
  • Implement: Sidecar 공유 볼륨(emptyDir) 아키텍처 작성. Pod 스펙:
    • Volume: emptyDir (이름: log-volume).
    • Container 1 (Main): Nginx. /var/log/nginx에 마운트하여 로그 작성.
    • Container 2 (Sidecar): Fluentd. 동일한 log-volume을 읽기 전용으로 마운트하여 관제탑으로 전송. 단일 책임 원칙(SRP)을 클래스가 아닌 '인프라 컨테이너 레벨'로 끌어올린 시각화.

Advanced

Core Topic 04: 불변의 좌표 (Deployment & Service)

  • Why to Learn: 파드는 10초 만에 죽고, 새로 뜬 파드의 IP는 매번 바뀌는 미친 혼돈(Chaos) 속에서, 프론트엔드가 백엔드를 안정적으로 호출할 수 있는 '영원히 바뀌지 않는 단일 IP(Service)' 방어막을 구축하기 위함입니다.
  • What to Learn:
    • Concepts: Deployment (디플로이먼트), ReplicaSet (레플리카셋), Service (서비스), Label Selector, ClusterIP, NodePort.
    • Skills: "백엔드 파드 3개를 항상 유지하라(Deployment)"는 선언적(Declarative) 상태를 만들고, 이 3개의 파드 앞단에 1개의 변하지 않는 가상 IP(Service)를 띄워 로드밸런싱 통로 뚫기.
  • How to Learn:
    • 1단계: 맨몸 파드의 한계: kind: Pod로 띄운 파드가 죽으면 K8s는 살려주지 않습니다. 끝입니다.
    • 2단계: 디플로이먼트 (자율 주행): kind: Deployment로 감싸서 "파드 3개를 유지해"라고 선언합니다. 노드가 터져서 파드 2개가 날아가면, K8s 컨트롤러가 알아채고 즉시 다른 노드에 파드 2개를 새로 띄워 기어코 '3개'를 맞춥니다(Self-healing).
    • 3단계: 서비스 (추상화된 방어막): 새로 뜬 파드 2개의 IP는 예전과 다릅니다. 클라이언트는 바뀐 IP를 모릅니다. 그래서 K8s는 kind: Service를 만듭니다. 서비스는 고정된 ClusterIP(예: 10.96.0.1)를 가집니다. 클라이언트가 여기로 요청을 쏘면, 서비스가 라벨(app=backend)이 붙은 3개의 파드 중 하나로 트래픽을 토스(로드밸런싱)합니다. 파드가 100번 죽어 IP가 바뀌어도, 클라이언트는 평온하게 10.96.0.1만 찌르면 되는 경이로운 추상화를 뜯어봅니다.
  • Implement: Label Selector 기반의 동적 라우팅 역학 렌더링. Service 룰: 라벨이 tier=backend인 파드들에게 트래픽 분산. Event: 개발자가 kubectl run으로 새 파드(IP 10.1.5.5)를 띄우고 라벨에 tier=backend를 붙임. Action: Service가 이를 실시간으로 감지하여 로드밸런싱 풀(Endpoint)에 자동 편입. 사람의 개입 0%, 완벽한 자동 디스커버리 체계 시각화.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Kubernetes Pod (파드) 1개 이상의 컨테이너를 하나로 묶어 IP와 볼륨을 공유하게 만드는 쿠버네티스의 가장 작은 배포(스케줄링) 단위로, 언제든 죽고 새로 태어날 수 있는 소모품(Cattle)입니다. 기본 K8s의 컨테이너 그룹화 및 네트워크 캡슐화 Container / Ephemeral / Pause Container (컨테이너) "왜 1파드 1컨테이너를 쓰지 않느냐?" \rightarrow 대부분 1파드 1컨테이너를 씀. 다만 사이드카(로그 수집기)를 붙여야 할 때 1파드 2컨테이너 묶음이 강력한 무기가 됨 P1:CS2023 core
Sidecar Pattern (사이드카 패턴) 메인 애플리케이션 컨테이너 옆에, 로그 수집이나 프록시(Envoy) 통신 등을 전담하는 보조 컨테이너를 함께 띄워 관심사를 물리적으로 분리하는 아키텍처입니다. 권장 로직과 인프라 관심사 분리(Separation of Concerns) Service Mesh / emptyDir Ambassador / Adapter 사이드카 안 쓴다고 앱이 멈추진 않음. 하지만 앱 코드에 인프라 로직(로깅, 트레이싱)이 더럽게 떡칠되는 걸 막으려면 MSA 환경에선 필수임 P5:SFIA core
Deployment (디플로이먼트) "항상 파드 3개를 유지하라"는 선언(Desired State)을 K8s에 던져놓으면, 파드가 죽을 때마다 알아서 복제본(Replica)을 살려내는 자율 주행 컨트롤러입니다. 실무 상태 유지(Self-healing) 및 무중단 배포(Rolling Update) ReplicaSet / Declarative / Rolling Update Pod (맨몸 파드) 실무에서 kind: Pod 스펙을 직접 배포하는 일은 미친 짓임. 무조건 kind: Deployment로 감싸서 배포해야 K8s가 파드가 죽었을 때 좀비처럼 살려줌 Industry core
K8s Service (서비스) 파드가 재시작되어 IP가 휙휙 바뀌는 혼돈 속에서, 변하지 않는 영구적인 가상 IP(VIP)를 하나 띄워 뒤에 있는 파드들에게 트래픽을 뿌려주는 로드밸런서입니다. 심화 동적 IP 추상화 및 내부 로드밸런싱 ClusterIP / NodePort / Ingress Ingress (인그레스) Service는 보통 클러스터 '내부'에서 파드끼리 통신할 때 쓰고, Ingress는 '외부(인터넷)'에서 들어오는 트래픽을 도메인 단위로 쪼개어 Service로 넘겨주는 대문임 Industry core

8. References

Primary

  • [P1] CS2023 - Software Engineering (SE) - Distributed Systems (Container Orchestration)
  • [P5] SFIA - IT Operations (ITOP) - Deployment and provisioning (Kubernetes)

Secondary

  • [Kubernetes in Action] Marko Lukša - Pods, Services, Deployments
  • [Designing Distributed Systems] Brendan Burns - Sidecar, Ambassador, and Adapter Patterns

Industry

  • [Kubernetes Documentation] - Pods, Service, Deployments, Init Containers
  • [Google Cloud Architecture Center] - Kubernetes best practices: Resource requests and limits

9. Final Checklist

Primary

  • 도커 컨테이너를 쿠버네티스에 배포할 때, 왜 컨테이너 단독이 아니라 파드(Pod)라는 껍질로 감싸야 하며, 파드 내부의 여러 컨테이너가 어떻게 1개의 IP와 localhost를 공유하는지 설명할 수 있는가?
  • 파드를 "언제 고장 나도 고쳐 쓰지 않고 즉시 폐기 후 새로 띄우는 소모품(Ephemeral/Cattle)"으로 대해야 하는 클라우드 네이티브의 철학적 배경을 논증할 수 있는가?

Secondary

  • kubectl get pods 명령을 쳤을 때 보이지 않는 숨겨진 Pause 컨테이너가 파드 구동 시 가장 먼저 실행되어 네트워크 네임스페이스(IP)를 잡고 버텨주는 인프라적 흑마법을 뜯어볼 수 있는가?
  • 백엔드 서버(메인 컨테이너)의 비즈니스 로직 코드 안에 로그 전송 로직을 심는 대신, 공용 볼륨(emptyDir)을 공유하는 사이드카(Sidecar) 컨테이너를 붙여 관심사를 완벽히 분리(SoC)하는 구조를 설계할 수 있는가?

Industry

  • 파드가 죽거나 재시작되어 IP 주소가 10분마다 변경되는 혼란스러운 클러스터 환경에서, 단일하고 불변하는 가상 IP(VIP)를 제공하여 트래픽을 분산시키는 서비스(Service)의 추상화 계층을 구축할 수 있는가?
  • 수동으로 파드를 3개 띄우는 것과, 디플로이먼트(Deployment)를 통해 replicas: 3을 선언적(Declarative)으로 구성했을 때, 특정 워커 노드가 다운되는 장애 상황에서 벌어지는 K8s의 자가 치유(Self-healing) 역학을 시각화할 수 있는가?

CI/CD & Delivery Platform

4 / 4