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)과 워커 노드의 하드웨어적 구성 09-05-01 IaC & Deployment 영역으로 위임.
- Helm과 GitOps 배포 파이프라인: 템플릿 엔진 및 ArgoCD 동기화 상위 모듈
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
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) 로그수집기(IP 172.17.0.3)로 데이터를 보낼 때 상대방 IP를 알아야 함.After (K8s Pod): 앱과 로그수집기가 1개의 파드에 묶임(공용 IP 10.1.1.5). 앱은 고민 없이localhost:9000으로 쏘면 옆에 있는 컨테이너가 받음. 복잡한 네트워크 매핑이 소멸하는 시각화.
Recommended
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를 꽉 잡고 버텨주므로 파드의 네트워크가 절대 붕괴하지 않는 극한의 설계술을 해부합니다.
- 1단계: 네트워크의 모순: 리눅스에서 컨테이너 A와 B가
- Implement: Pause 컨테이너 라이프사이클 모델링.
Event 1: 파드 스케줄링. K8s가Pause컨테이너 구동 IP 할당 완료 (10.5.2.1).Event 2:App컨테이너 구동 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 조합짜기.
- Concepts: Sidecar Pattern (사이드카 패턴), Ambassador, Adapter, Shared Volume (
- 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만 찌르면 되는 경이로운 추상화를 뜯어봅니다.
- 1단계: 맨몸 파드의 한계:
- Implement: Label Selector 기반의 동적 라우팅 역학 렌더링.
Service 룰: 라벨이tier=backend인 파드들에게 트래픽 분산.Event: 개발자가kubectl run으로 새 파드(IP 10.1.5.5)를 띄우고 라벨에tier=backend를 붙임.Action: Service가 이를 실시간으로 감지하여 로드밸런싱 풀(Endpoint)에 자동 편입. 사람의 개입 0%, 완벽한 자동 디스커버리 체계 시각화.
7. Terminology
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) 역학을 시각화할 수 있는가?