본문 바로가기
클라우드/쿠버네티스

👯‍♀️ 파드, 혼자가 아닌 둘이서! 멀티 컨테이너 파드 패턴 완전 정복 (Sidecar & Init Container)

by gasbugs 2025. 9. 3.

안녕하세요, 쿠버네티스 전문가를 향해 나아가는 여러분! 🚀 우리는 보통 하나의 파드(Pod) 안에 하나의 컨테이너를 실행하는 것이 일반적이라고 생각합니다. 하지만 쿠버네티스의 파드는 사실 여러 개의 컨테이너를 함께 실행할 수 있는 "컨테이너의 집"입니다. 그리고 이 여러 컨테이너들이 서로 협력하여 하나의 목적을 달성하는 것이 바로 멀티 컨테이너 파드 패턴의 핵심입니다.

 

오늘은 이 강력한 멀티 컨테이너 패턴 중 가장 대표적인 두 가지, Sidecar(사이드카)와 Init Container(초기화 컨테이너)에 대해 자세히 알아보겠습니다. 이 패턴들을 이해하면 애플리케이션의 유연성과 안정성을 훨씬 높일 수 있을 겁니다!

 


1. Sidecar Pattern: 내 옆에서 나를 돕는 조수 🤝

Sidecar 컨테이너는 주 애플리케이션 컨테이너와 동일한 파드 안에서 함께 실행되면서, 주 컨테이너의 기능을 보조하거나 확장하는 역할을 합니다. 마치 주인이 운전하는 차 옆에 앉아 내비게이션을 보거나 서류를 정리해주는 조수처럼 말이죠. 🚗💨

  • 역할: 주 컨테이너의 핵심 로직을 건드리지 않고, 부가적인 기능(로깅, 모니터링, 설정 동기화, 프록시 등)을 독립적으로 수행합니다.
  • 핵심 동작:
    • 주 컨테이너와 함께 생성되고 함께 소멸됩니다.
    • 주 컨테이너와 네트워크 및 스토리지(볼륨)를 공유합니다. 이 점이 핵심입니다.
    • 주 컨테이너와 Sidecar 컨테이너는 서로 의존적이지만, 각각 독립적인 프로세스로 실행됩니다.
  • 주요 사용 사례:
    • 로그 수집/전송: 주 컨테이너가 발생시키는 로그를 Sidecar가 실시간으로 수집하여 중앙 로깅 시스템(Elasticsearch, Splunk 등)으로 전송합니다. 📝
    • 프록시: 주 컨테이너 앞에서 인증, 캐싱, 트래픽 라우팅 등의 역할을 수행하는 프록시 컨테이너를 Sidecar로 둡니다. (예: Envoy 프록시) 🛡️
    • 설정 동기화: 외부 설정 저장소(ConfigMap, Vault 등)에서 최신 설정을 주기적으로 가져와 주 컨테이너가 사용할 수 있도록 파일로 저장합니다. ⚙️
    • 데이터 동기화/백업: 주 컨테이너가 생성하는 데이터를 주기적으로 외부 스토리지로 백업하거나 동기화합니다.
  • 장점:
    • 관심사의 분리: 주 컨테이너는 핵심 비즈니스 로직에만 집중하고, 부가 기능은 Sidecar에게 위임하여 코드의 복잡성을 줄입니다.
    • 재사용성: 로그 수집 같은 공통 기능을 Sidecar 컨테이너로 만들어 여러 애플리케이션에 재사용할 수 있습니다.
    • 독립적인 배포: Sidecar 컨테이너만 독립적으로 업데이트하거나 확장할 수 있습니다.
  • 비유: 메인 엔진(주 컨테이너)은 자동차를 달리게 하는 역할만 하고, 내비게이션, 오디오, 에어컨(Sidecar 컨테이너)은 각각 독립적으로 작동하면서 운전 경험을 풍부하게 만드는 것과 같습니다. 🎶

YAML 예시:

Nginx가 생성하는 로그를 Sidecar 컨테이너가 계속 따라 읽는 예시 (공유 볼륨 사용)

apiVersion: v1
kind: Pod
metadata:
  name: sidecar-example
spec:
  containers:
  - name: main-nginx-container # 주 컨테이너
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: var-logs
      mountPath: /var/log/nginx # 로그를 이 볼륨에 저장
  - name: log-collector-sidecar # 사이드카 컨테이너
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"] # 주 컨테이너의 로그를 따라 읽음
    volumeMounts:
    - name: var-logs
      mountPath: /var/log/nginx # 주 컨테이너와 동일한 볼륨 마운트
  volumes:
  - name: var-logs
    emptyDir: {} # 파드 생명주기 동안만 존재하는 임시 공유 볼륨

 

 

 

잠깐! ✋ Sidecar와 Init Container는 어떻게 데이터를 공유할까요?

두 패턴의 예시에서 volumes와 emptyDir가 공통적으로 사용된 것을 눈치채셨나요? Sidecar와 Init Container가 메인 컨테이너와 협력하기 위한 가장 핵심적인 방법이 바로 파드 내 볼륨 공유입니다.

그중에서도 emptyDir는 멀티 컨테이너 패턴에서 가장 흔하게 사용되는 임시 공유 스토리지입니다.

 

emptyDir 볼륨의 핵심 특징:

  • 생명주기: 파드가 생성될 때 함께 만들어지고, 파드가 사라질 때 함께 삭제됩니다. 이름 그대로 처음에는 '텅 빈 디렉터리(Empty Directory)'로 시작합니다.
  • 데이터 공유: 파드 내의 모든 컨테이너가 이 볼륨을 각자의 파일 시스템에 마운트하여 파일을 읽고 쓸 수 있습니다. 마치 여러 사람이 함께 사용하는 '공용 화이트보드' 칠판과 같습니다. 칠판
  • 임시성: 파드가 사라지면 데이터도 영원히 사라지므로, 영구적으로 보존해야 할 데이터를 저장하는 용도로는 부적합합니다.

Sidecar 패턴에서는 메인 컨테이너가 쓴 로그 파일을 Sidecar가 읽기 위해, Init Container 패턴에서는 Init Container가 준비한 설정 파일을 메인 컨테이너가 읽기 위해 이 emptyDir라는 '공용 화이트보드'를 사용하는 것입니다.

 


2. Init Container: 메인 컨테이너를 위한 사전 준비 🏗️

Init Container는 주 애플리케이션 컨테이너가 시작하기 전에 먼저 실행되어 필요한 모든 사전 작업을 수행하는 컨테이너입니다. 주 컨테이너는 Init Container가 성공적으로 완료될 때까지 기다립니다.

  • 역할: 주 컨테이너의 시작에 필요한 전제 조건(Pre-requisites)을 충족시킵니다.
  • 핵심 동작:
    • 파드 내의 모든 Init Container는 순서대로 하나씩 실행됩니다.
    • 각 Init Container는 다음 Init Container가 시작되기 전에 성공적으로 완료(Exit Code 0)되어야만 합니다.
    • 모든 Init Container가 성공적으로 완료된 후에야 주 애플리케이션 컨테이너들이 병렬로 시작됩니다.
    • Init Container는 주 컨테이너와 네트워크 및 스토리지(볼륨)를 공유할 수 있습니다.
  • 주요 사용 사례:
    • 설정 파일 준비: 외부에서 설정 데이터를 가져와 주 컨테이너가 사용할 설정 파일을 생성합니다. 📋
    • 데이터베이스 마이그레이션 대기: 주 컨테이너가 데이터베이스에 연결하기 전에, 데이터베이스가 완전히 준비될 때까지 기다립니다. ⏳
    • 권한 설정: 특정 디렉토리의 권한을 변경하여 주 컨테이너가 접근할 수 있도록 합니다. 🔑
    • 초기 데이터 로딩: 주 컨테이너에 필요한 초기 데이터를 미리 다운로드하거나 생성합니다. ⬇️
  • 장점:
    • 강력한 의존성 관리: 주 컨테이너의 시작 조건을 명확하게 정의하고 강제할 수 있습니다.
    • 코드 분리: 복잡한 초기화 로직을 주 컨테이너에서 분리하여 컨테이너 이미지를 더 간결하게 유지할 수 있습니다.
    • 재시도 가능: Init Container가 실패하면 파드는 재시작되면서 Init Container부터 다시 시작합니다.
  • 비유: 연극이 시작되기 전에 무대 조명을 점검하고, 소품을 배치하고, 배우들이 대기하는 '막전 준비 과정' 🎭과 같습니다. 이 준비가 완벽하게 끝나야만 비로소 본 공연(주 컨테이너 실행)이 시작될 수 있죠.

YAML 예시:

Nginx가 시작하기 전에 index.html 파일을 생성하는 Init Container 예시입니다.

apiVersion: v1
kind: Pod
metadata:
  name: init-container-example
spec:
  initContainers: # Init Container 정의
  - name: init-myservice
    image: busybox
    command: ["sh", "-c", "echo 'Hello from Init Container!' > /usr/share/nginx/html/index.html"]
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html # 주 컨테이너와 공유할 볼륨 마운트
  containers:
  - name: main-nginx-container # 주 컨테이너
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html # Init Container가 생성한 파일을 읽음
  volumes:
  - name: workdir
    emptyDir: {}

🎉 결론: 멀티 컨테이너 파드로 더 유연하고 견고하게!

Sidecar와 Init Container 패턴은 단순한 단일 컨테이너 파드를 넘어서, 더 복잡하고 유연하며 견고한 애플리케이션 아키텍처를 구축할 수 있게 해줍니다.

  • 주 컨테이너 옆에서 보조 역할이 필요하다면 Sidecar를,
  • 주 컨테이너 시작 전 필수적인 사전 작업이 필요하다면 Init Container를 활용하세요.

이 두 가지 패턴을 적절히 사용한다면, 쿠버네티스 환경에서 애플리케이션의 운영 효율성과 안정성을 한 단계 더 끌어올릴 수 있을 것입니다.

 

 

Tags: 쿠버네티스, Kubernetes, Pod, 멀티컨테이너, Sidecar, InitContainer, DevOps, 컨테이너패턴, MSA, 아키텍처