[쿠버네티스 패턴] 16장 sidecar 패턴

bocopile·2025년 11월 21일

쿠버네티스 패턴

목록 보기
14/28
post-thumbnail

1. Sidecar 패턴이란?

1) 한 줄 정의

Sidecar 컨테이너는 기존 컨테이너의 기능을 변경하지 않고 확장하고 향상시키는 패턴입니다.

2) 상세 설명

Sidecar 패턴은 하나의 Pod 내에서 메인 컨테이너와 헬퍼 컨테이너(Sidecar)가 협력하여 동작하는 기본적인 컨테이너 패턴입니다.

마치 오토바이에 부착된 사이드카처럼, Sidecar 컨테이너는 메인 컨테이너를 보조하면서도 독립적으로 동작합니다.

이를 통해

  • 단일 목적의 컨테이너를 재사용 가능하게 만듦
  • 컨테이너 간 느슨한 결합(Loose Coupling) 유지
  • 각 컨테이너의 독립적인 배포 및 업데이트 가능
  • 관심사의 분리(Separation of Concerns) 실현

2. Sidecar 패턴이 필요한 이유

1) 문제 상황

현대의 컨테이너 기반 애플리케이션은 다음과 같은 과제에 직면합니다

[단일 책임 원칙의 딜레마]

  • 컨테이너는 "하나의 문제를 잘 해결"해야 함 (Unix 철학)
  • 하지만 실제 운영에는 로깅, 모니터링, 프록시 등 부가 기능 필요
  • 메인 애플리케이션에 이런 기능을 모두 포함하면 컨테이너가 비대해짐

[재사용성 문제]

  • HTTP 서버 컨테이너를 만들 때마다 Git 동기화 코드를 작성?
  • 로깅 로직을 모든 애플리케이션에 중복 구현?
  • 각 팀이 같은 기능을 다르게 구현하여 유지보수 어려움

[기술 스택의 다양성]

  • 메인 앱은 Java, 로깅은 Python이 더 적합한 경우
  • 서로 다른 릴리스 주기를 가진 컴포넌트
  • 다른 팀이 소유한 컴포넌트 간 협업 필요

2) Sidecar 패턴의 해결책

Sidecar 패턴은 다음과 같은 방식으로 문제를 해결합니다.

  1. 기능의 모듈화: 로깅, 모니터링, 프록시 등을 독립적인 컨테이너로 분리
  2. 재사용 촉진: 검증된 Sidecar 컨테이너를 여러 애플리케이션에서 재사용
  3. 느슨한 결합: 메인 컨테이너 수정 없이 Sidecar 추가/제거 가능
  4. 독립적인 개발: 각 컨테이너를 다른 언어, 도구, 팀으로 개발 가능

3. Sidecar 패턴의 핵심 개념

1) Pod: 컨테이너 협력의 기초

Kubernetes의 Pod는 Sidecar 패턴을 구현하는 핵심 단위입니다.

[Pod의 특징]

  • 여러 컨테이너를 하나의 논리적 배포 단위로 묶음
  • 컨테이너들이 항상 같은 노드에 스케줄링
  • 동일한 생명주기 공유 (생성·재시작·삭제가 함께 동작)
  • 네트워크 네임스페이스 공유 → localhost 기반 통신 가능 & 동일 IP 사용
  • Pod 레벨에서 정의된 볼륨을 통해 파일 시스템 공유 가능
  • IPC / UTS / PID 네임스페이스 공유 가능 (기본적으로 IPC는 공유)

[Pod 내부 동작 원리]

Pod (pause 컨테이너)
├── 네트워크 네임스페이스 (공유)
├── IPC 네임스페이스 (공유)
└── 볼륨 마운트 (공유 가능)
    ├── 메인 컨테이너
    │   └── /var/www/html → emptyDir
    └── Sidecar 컨테이너
        └── /data → emptyDir (동일한 볼륨)

• Pause 컨테이너(Pod Sandbox)
→ Pod의 네임스페이스(Network / IPC / UTS / PID) 생성 및 유지
→ 나머지 컨테이너들은 생성된 네임스페이스에 Join

• Main & Sidecar 컨테이너
→ 동일한 IP, 포트 공간, localhost 공유
→ 동일 볼륨 사용 시 파일 시스템 공유 가능

2) OOP와의 비교

[상속(Inheritance) vs 조합(Composition)]

개념컨테이너 확장 방식OOP 비유특징
상속Dockerfile FROMclass Child extends Parent- 빌드 타임 결합
- "is-a" 관계
- 강한 결합
조합Pod 내 다중 컨테이너class has SidecarService- 런타임 결합
- "has-a" 관계
- 느슨한 결합

[예시]

# 상속 방식 (Dockerfile)
FROM nginx:1.27
COPY git-sync.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/git-sync.sh
# 문제: nginx 업데이트 시 재빌드 필요, Git 동기화 로직이 컨테이너에 고정됨
# 조합 방식 (Pod)
spec:
  containers:
  - name: nginx
    image: nginx:1.27  # nginx만 업데이트 가능
  - name: git-sync
    image: git-sync:v4  # git-sync만 업데이트 가능
# 장점: 각 컨테이너 독립적으로 관리

3) Sidecar vs Init Container

특성Init ContainerSidecar Container
실행 시점Pod 시작 전Pod 실행 중
실행 방식순차적 실행 후 종료메인 컨테이너와 병렬 실행
생명주기작업 완료 후 종료Pod 종료까지 계속 실행
재시작실패 시 재시작실패 시 재시작 (정책에 따라)
사용 사례- DB 초기화
- 설정 파일 다운로드
- 의존성 대기
- 로깅
- 모니터링
- 프록시
- 데이터 동기화

4. Sidecar 패턴의 활용 사례

1) HTTP 서버 + Git 동기화

시나리오: 웹 서버가 Git 저장소의 정적 파일을 서빙

  • 메인 컨테이너: Nginx (파일 서빙만 담당)
  • Sidecar: Git-sync (저장소 동기화만 담당)
  • 공유 메커니즘: emptyDir 볼륨

2) 애플리케이션 + 로깅 에이전트

시나리오: 애플리케이션 로그를 중앙 로그 시스템으로 전송

  • 메인 컨테이너: 애플리케이션 (로그 파일 생성)
  • Sidecar: Fluentd/Filebeat (로그 수집 및 전송)
  • 장점: 애플리케이션은 로그 전송 로직 불필요

3) 서비스 메시 (Service Mesh)

시나리오: 마이크로서비스 간 통신 관리

  • 메인 컨테이너: 비즈니스 로직
  • Sidecar: Envoy Proxy (트래픽 관리, TLS, 로드밸런싱)
  • 특징: 애플리케이션 코드 수정 없이 서비스 메시 기능 추가

4) 설정 동기화

시나리오: 원격 설정 저장소의 변경사항 감지 및 반영

  • 메인 컨테이너: 애플리케이션
  • Sidecar: Consul Template (설정 변경 감지 및 업데이트)

5. Sidecar의 두 가지 유형

1) Transparent Sidecar (투명한 사이드카)

정의: 메인 애플리케이션이 Sidecar의 존재를 인지하지 못하는 방식

대표적인 예: Envoy Proxy

# Envoy가 모든 트래픽을 가로채는 방식
spec:
  containers:
  - name: app
    image: my-app:1.0
    # 애플리케이션은 Envoy를 모름
  - name: envoy
    image: envoyproxy/envoy:v1.31
    # iptables 규칙으로 트래픽 자동 리다이렉션

[제공 기능]

  • TLS 암호화/복호화
  • 로드 밸런싱
  • Circuit Breaking
  • Retry/Timeout 관리
  • L7 트래픽 관찰성
  • 분산 추적

[동작 방식]

외부 요청 → Envoy Sidecar → 메인 앱
         ↑ (iptables redirect)

[장점]

  • 애플리케이션 코드 변경 불필요
  • 모든 언어/프레임워크에 적용 가능
  • AOP(Aspect-Oriented Programming)와 유사한 횡단 관심사 처리

2) Explicit Sidecar (명시적 사이드카)

정의: 메인 애플리케이션이 명시적으로 Sidecar API를 호출하는 방식

[대표적인 예: Dapr]

spec:
  containers:
  - name: app
    image: my-app:1.0
    env:
    - name: DAPR_HTTP_PORT
      value: "3500"  # Dapr API 포트
  - name: daprd
    image: daprio/daprd:latest
    args: ["--app-port", "8080"]

[애플리케이션 코드 예시]

import requests

# Dapr Sidecar에 명시적으로 요청
response = requests.post(
    "<http://localhost:3500/v1.0/state/statestore>",
    json={"key": "user123", "value": "John Doe"}
)

[제공 기능]

  • Service Invocation (서비스 간 호출)
  • State Management (상태 저장)
  • Pub/Sub Messaging
  • Bindings (외부 시스템 연동)
  • Secrets Management
  • Distributed Tracing

[장점]

  • 명확한 API 계약
  • 기능별 선택적 사용 가능
  • 디버깅 용이

3) 비교 정리

특성Transparent SidecarExplicit Sidecar
애플리케이션 인지불필요필요
트래픽 처리자동 가로채기명시적 호출
대표 예시Envoy, LinkerdDapr, AWS App Mesh
사용 사례- 서비스 메시
- 네트워크 정책
- 보안
- 상태 관리
- 이벤트 기반
- 외부 통합
학습 곡선낮음 (앱 변경 없음)중간 (API 학습 필요)

6. 기본 예제 코드

1) HTTP 서버 + Git 동기화 Sidecar

다음은 책에서 소개된 기본 예제를 개선한 버전입니다

# 01-basic-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-app-basic
  labels:
    app: web-app
    pattern: sidecar
spec:
  containers:
  # 메인 컨테이너: HTTP 서버
  - name: app
    image: nginx:1.27
    ports:
    - containerPort: 80
    volumeMounts:
    - mountPath: /usr/share/nginx/html  # Nginx 정적 파일 경로
      name: git-data
    resources:
      requests:
        memory: "64Mi"
        cpu: "100m"
      limits:
        memory: "128Mi"
        cpu: "200m"

  # Sidecar 컨테이너: Git 동기화
  - name: git-sync
    image: k8s.gcr.io/git-sync/git-sync:v4.2.4
    env:
    - name: GITSYNC_REPO
      value: "<https://github.com/kubernetes/website>"
    - name: GITSYNC_ROOT
      value: "/data"
    - name: GITSYNC_DEST
      value: "website"
    - name: GITSYNC_PERIOD
      value: "60s"  # 60초마다 동기화
    - name: GITSYNC_ONE_TIME
      value: "false"
    volumeMounts:
    - mountPath: /data
      name: git-data
    resources:
      requests:
        memory: "32Mi"
        cpu: "50m"
      limits:
        memory: "64Mi"
        cpu: "100m"

  volumes:
  - name: git-data
    emptyDir: {}  # Pod 재시작 시 초기화되는 임시 볼륨

[동작 흐름]

  1. Pod 시작 시 두 컨테이너가 동시에 실행
  2. git-sync가 Git 저장소를 /data에 clone
  3. nginx가 동일한 볼륨(/usr/share/nginx/html)에서 파일 읽기
  4. 60초마다 git-syncgit pull 실행
  5. Nginx는 자동으로 업데이트된 파일 서빙

[실행 및 검증]

# Pod 생성
kubectl apply -f 01-basic-sidecar.yaml

# Pod 상태 확인
kubectl get pod web-app-basic

# Nginx 로그 확인
kubectl logs web-app-basic -c app

# Git-sync 로그 확인
kubectl logs web-app-basic -c git-sync

# HTTP 응답 테스트
kubectl port-forward web-app-basic 8080:80
curl <http://localhost:8080>

7. Kubernetes 최신 기능 (v1.28~v1.34)

1) Kubernetes 1.28: Native Sidecar Containers

[배경]

기존에는 Sidecar를 구현하기 위해 두 가지 방법만 존재했습니다

  1. 일반 컨테이너로 추가: 시작 순서 보장 안 됨
  2. Init Container로 추가: 메인 앱 시작 전 종료됨

이 두 방법 모두 "메인 앱과 함께 실행되면서 시작 순서도 제어"하는 요구사항을 만족하지 못했습니다.

- 해결책: restartPolicy: Always

Kubernetes 1.28부터 Init Container에 restartPolicy 필드를 추가하여 Native Sidecar를 지원합니다.

apiVersion: v1
kind: Pod
metadata:
  name: native-sidecar-example
spec:
  initContainers:
  # 일반 Init Container
  - name: init-setup
    image: busybox:1.36
    command: ['sh', '-c', 'echo "Setup complete"']

  # Native Sidecar Container
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.31-latest
    restartPolicy: Always  # ← 이 필드가 핵심!
    ports:
    - containerPort: 8080
      name: proxy

  containers:
  - name: main-app
    image: my-app:1.0

[주요 특징]

특성일반 Init ContainerNative Sidecar일반 Container
restartPolicy-Always-
시작 순서순차적순차적 시작순서 보장 안 됨
종료 시점작업 완료 후Pod 종료 시Pod 종료 시
재시작실패 시만항상정책에 따라
Startup Probe지원지원지원

[실행 순서]

1. init-setup 실행 → 완료 후 종료
2. envoy-proxy 시작 → Startup Probe 성공 대기
3. envoy-proxy Startup Probe 성공
4. main-app 시작
5. envoy-proxy와 main-app이 함께 실행
6. envoy-proxy 종료 시 자동 재시작

[사용 사례]

  1. 네트워크 프록시: 메인 앱 시작 전 프록시 준비 필요
  2. 배치/AI 워크로드: Job에서 로깅 Sidecar 사용 (Job 완료를 차단하지 않음)
  3. 보안 에이전트: 앱 시작 전 보안 정책 적용

[특이사항 Feature Gate 활성화]

# kube-apiserver, kubelet에 플래그 추가
--feature-gates=SidecarContainers=true

2) Kubernetes 1.34: Per-Container Restart Policies

[배경]

기존 Kubernetes는 Pod 레벨에서만 재시작 정책을 설정할 수 있었습니다

spec:
  restartPolicy: Always  # Pod의 모든 컨테이너에 적용

[문제점]

  • 메인 앱은 항상 재시작해야 하지만, 로그 전송 Sidecar는 실패 시에만 재시작하고 싶을 때
  • 특정 exit code(예: OOM)에서만 재시작하고 싶을 때
  • 컨테이너별로 다른 재시작 전략이 필요할 때

해결책: restartPolicyRules

Kubernetes 1.34는 컨테이너별 재시작 정책과 Exit Code 기반 규칙을 도입했습니다.

apiVersion: v1
kind: Pod
metadata:
  name: restart-policy-example
spec:
  restartPolicy: Never  # Pod 레벨 기본 정책

  containers:
  # Exit code 42(임시 오류)에만 재시작하는 앱
  - name: retriable-app
    image: my-app:1.0
    restartPolicy: Never
    restartPolicyRules:
    # Exit code 42일 때만 재시작
    - action: Restart
      onExitCodes:
        operator: In
        values: [42]  # OOM 또는 일시적 오류
    # Exit code 1일 때는 재시작하지 않음
    - action: DoNotRestart
      onExitCodes:
        operator: In
        values: [1]  # 설정 오류 (영구적)

  # 항상 재시작하는 모니터링 Sidecar
  - name: monitoring-sidecar
    image: monitoring:1.0
    restartPolicy: Always  # 어떤 exit code든 항상 재시작

  # 실패 시에만 재시작하는 로깅 Sidecar
  - name: log-forwarder
    image: fluentd:latest
    restartPolicy: OnFailure

[주요 개념]

  1. 컨테이너별 restartPolicy
    • Always: 항상 재시작
    • OnFailure: exit code가 0이 아닐 때만 재시작
    • Never: 재시작하지 않음
  2. restartPolicyRules: Exit code 기반 세밀한 제어
    • action: Restart 또는 DoNotRestart
    • onExitCodes.operator: In 또는 NotIn
    • onExitCodes.values: Exit code 리스트

[실용 예제: ML 학습 워크로드]

# GPU를 사용하는 ML 학습 작업
spec:
  restartPolicy: Never
  containers:
  - name: ml-trainer
    image: tensorflow:latest
    restartPolicy: Never
    restartPolicyRules:
    # Exit 42: GPU OOM → 재시작 (학습 재개 가능)
    - action: Restart
      onExitCodes:
        operator: In
        values: [42]
    # Exit 1: 데이터셋 오류 → 재시작하지 않음 (수정 필요)
    - action: DoNotRestart
      onExitCodes:
        operator: In
        values: [1]
    resources:
      limits:
        nvidia.com/gpu: 1

[장점]

  • 리소스 효율성: 실패한 컨테이너만 in-place 재시작 (Pod 재스케줄링 불필요)
  • 빠른 복구: 노드 간 이동 없이 즉시 재시작
  • 정밀한 제어: Exit code별로 다른 전략 적용

3) 버전별 기능 요약

버전기능상태핵심 키워드
1.28Native SidecarBetarestartPolicy: Always on initContainers
1.29Native Sidecar GA 준비Beta → Stable 진행 중-
1.34Per-Container RestartAlpharestartPolicyRules, onExitCodes

8. 실습 예제

0) 실습코드

1) 실습 1: 기본 Sidecar 패턴

  • 코드 작성 (01-basic-sidecar.yaml)

    # 기본 Sidecar 패턴 예제
    # HTTP 서버와 Git 동기화 사이드카를 사용하는 Pod
    apiVersion: v1
    kind: Pod
    metadata:
      name: web-app-basic
      labels:
        app: web-server
        pattern: sidecar
    spec:
      containers:
      # 메인 애플리케이션 컨테이너
      - name: app
        image: nginx:1.27
        ports:
        - containerPort: 80
          name: http
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: git-content
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"
    
      # Sidecar 컨테이너: Git 동기화
      - name: git-sync
        image: registry.k8s.io/git-sync/git-sync:v4.3.0
        volumeMounts:
        - mountPath: /tmp/git
          name: git-content
        env:
        - name: GITSYNC_REPO
          value: "https://github.com/kubernetes/website"
        - name: GITSYNC_ROOT
          value: "/tmp/git"
        - name: GITSYNC_LINK
          value: "current"
        - name: GITSYNC_PERIOD
          value: "60s"  # 60초마다 동기화
        - name: GITSYNC_ONE_TIME
          value: "false"
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "100m"
    
      volumes:
      - name: git-content
        emptyDir: {}
    
    ---
    # Service를 통해 웹 서버 노출
    apiVersion: v1
    kind: Service
    metadata:
      name: web-app-service
    spec:
      selector:
        app: web-server
      ports:
      - protocol: TCP
        port: 80
        targetPort: 80
      type: ClusterIP
    
  • 파드 생성

    kubectl apply -f ./01-basic-sidecar.yaml
  • 파드 상태 확인

    kubectl get pod web-app-basic -w

  • 컨테이너 별 로그 확인

    kubectl logs web-app-basic -c app        # Nginx 로그
    kubectl logs web-app-basic -c git-sync   # Git 동기화 로그

  • HTTP 응답 테스트

    kubectl port-forward web-app-basic 8080:80
    curl http://localhost:8080

  • 공유 볼륨 확인

    kubectl exec web-app-basic -c app -- ls -la /usr/share/nginx/html
    kubectl exec web-app-basic -c git-sync -- ls -la /data
    
    • 마운트 성공 (/usr/share/nginx/html)
    • 마운트 실패 (/data)
  • 코드 정리

    kubectl delete pod web-app-basic

2) 실습 2: Native Sidecar (Kubernetes 1.28+)

[사전 요구사항]

# 버전확인
kubectl version  # 1.28 이상 확인

[실습 순서]

  • 코드 작성

    # Kubernetes v1.33+ Native Sidecar 패턴
    # restartPolicy: Always를 사용한 Init Container 기반 Sidecar
    apiVersion: v1
    kind: Pod
    metadata:
      name: web-app-native-sidecar
      labels:
        app: web-server-native
        pattern: native-sidecar
    spec:
      initContainers:
      # Native Sidecar: restartPolicy Always를 사용
      - name: log-collector
        image: busybox:1.36
        restartPolicy: Always  # v1.29+에서 지원, v1.33에서 stable
        command:
        - sh
        - -c
        - |
          echo "Log collector sidecar started"
          while true; do
            if [ -f /var/log/app/app.log ]; then
              tail -f /var/log/app/app.log | while read line; do
                echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line"
              done
            fi
            sleep 1
          done
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/app
        resources:
          requests:
            memory: "32Mi"
            cpu: "50m"
          limits:
            memory: "64Mi"
            cpu: "100m"
    
      # Startup probe를 사용하는 Sidecar
      - name: metrics-exporter
        image: prom/node-exporter:v1.8.2
        restartPolicy: Always
        ports:
        - containerPort: 9100
          name: metrics
        startupProbe:
          httpGet:
            path: /metrics
            port: 9100
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3
        livenessProbe:
          httpGet:
            path: /metrics
            port: 9100
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /metrics
            port: 9100
          periodSeconds: 5
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "100m"
    
      containers:
      # 메인 애플리케이션
      - name: app
        image: nginx:1.27
        ports:
        - containerPort: 80
        volumeMounts:
        - name: log-volume
          mountPath: /var/log/app
        lifecycle:
          postStart:
            exec:
              command:
              - sh
              - -c
              - |
                # 로그 디렉토리 설정
                mkdir -p /var/log/app
                # Access 로그를 파일로 리다이렉트
                ln -sf /dev/stdout /var/log/nginx/access.log
                ln -sf /dev/stderr /var/log/nginx/error.log
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"
    
      volumes:
      - name: log-volume
        emptyDir: {}
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: web-app-native-service
    spec:
      selector:
        app: web-server-native
      ports:
      - name: http
        protocol: TCP
        port: 80
        targetPort: 80
      - name: metrics
        protocol: TCP
        port: 9100
        targetPort: 9100
      type: ClusterIP
    
  • 배포 진행

    kubectl apply -f ./02-native-sidecar-v1.33.yaml
  • Init Container(Native Sidecar) 구성 확인

    kubectl describe pod web-app-native-sidecar

  • 컨테이너 시작 순서 및 상태 확인 (Native Sidecar -> main Container)

    kubectl get pod web-app-native-sidecar -w

  • 메인 앱 테스트 확인

    kubectl port-forward svc/web-app-native-service 8080:80
    curl http://localhost:8080

  • Metrics Sidecar(Native Sidecar) 동작 테스트

    kubectl port-forward svc/web-app-native-service 9100:9100
    curl http://localhost:9100/metrics | head

  • Native Sidecar 재시작 동작 확인

    kubectl exec web-app-native-sidecar -c log-collector -- kill 1
  • 파드 상태 모니터링

    kubectl get pod web-app-native-sidecar \
    -o jsonpath='{range .status.initContainerStatuses[*]}{.name} {.restartCount} {.state}{"\n"}{end}'
    • 응답값
    log-collector 1 {"running":{"startedAt":"2025-11-22T08:51:14Z"}}
    metrics-exporter 0 {"running":{"startedAt":"2025-11-22T08:51:15Z"}}
  • 실습 코드 정리

    kubectl delete -f ./02-native-sidecar-v1.33.yaml

9. 설계 모범 사례

1) 언제 Sidecar를 사용할까?

[사용하기 좋은 경우]

  1. 횡단 관심사(Cross-Cutting Concerns)

    • 로깅, 모니터링, 보안, 네트워킹 등
    • 여러 애플리케이션에 공통으로 필요한 기능
  2. 관심사 분리

    • 메인 앱과 다른 프로그래밍 언어/기술 스택 사용
    • 다른 팀이 소유하는 컴포넌트
    • 다른 릴리스 주기
  3. 재사용성

    • 검증된 Sidecar 이미지를 여러 애플리케이션에서 재사용
    • 예: Envoy, Fluentd, Telegraf

[사용하지 말아야 할 경우]

  1. 긴밀하게 결합된 기능
    • 메인 앱의 핵심 비즈니스 로직
  2. 단일 컨테이너로 충분한 경우
    • 과도한 엔지니어링 방지
    • 리소스 오버헤드 고려
  3. 데이터 일관성이 중요한 경우
    • 데이터베이스 트랜잭션 등은 단일 프로세스로 처리

2) Sidecar 컨테이너 설계 원칙

  1. 단일 책임 원칙

    # 나쁜 예: 너무 많은 책임
    - name: swiss-army-knife
      image: all-in-one:latest
      # 로깅 + 모니터링 + 프록시 + 백업
    
    # 좋은 예: 하나의 책임
    - name: log-forwarder
      image: fluentd:latest
    - name: metrics-collector
      image: telegraf:latest
  1. 리소스 제한 설정

    # 항상 requests와 limits 설정
    resources:
      requests:
        memory: "64Mi"
        cpu: "100m"
      limits:
        memory: "128Mi"
        cpu: "200m"
  1. 헬스 체크 구현

    # Sidecar에도 적절한 Probe 설정
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 30
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
  1. 우아한 종료 처리

    # PreStop hook으로 우아한 종료
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh", "-c", "sleep 5"]
    

3) 보안 고려사항

  1. 최소 권한 원칙

    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
    
  1. 네트워크 정책

    # Sidecar만 외부 통신 허용
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: sidecar-network-policy
    spec:
      podSelector:
        matchLabels:
          app: my-app
      policyTypes:
      - Egress
      egress:
      - to:
        - podSelector:
            matchLabels:
              role: log-server
        ports:
        - protocol: TCP
          port: 24224
    
  1. 시크릿 관리

    # 환경 변수 대신 볼륨 마운트 사용
    volumeMounts:
    - name: secrets
      mountPath: /etc/secrets
      readOnly: true
    volumes:
    - name: secrets
      secret:
        secretName: app-secrets
    

4) 성능 최적화

  1. 볼륨 타입 선택

    볼륨 타입사용 사례특징
    emptyDir임시 데이터 공유- Pod 재시작 시 초기화
    - 노드의 디스크 사용
    emptyDir.medium: Memory빠른 I/O 필요- 메모리 사용 (빠름)
    - 크기 제한 주의
    configMap설정 파일- 읽기 전용
    - 크기 제한 (1MB)
    persistentVolumeClaim영구 데이터- Pod 재시작 후에도 유지
    # 고성능 I/O가 필요한 경우
    volumes:
    - name: cache
      emptyDir:
        medium: Memory
        sizeLimit: 1Gi
    
  1. Sidecar 시작 순서 제어

    # Native Sidecar 사용 (1.28+)
    initContainers:
    - name: envoy
      restartPolicy: Always
      startupProbe:
        httpGet:
          path: /ready
          port: 15021
        failureThreshold: 30
        periodSeconds: 1
    
  1. CPU/메모리 공유 최적화

    # QoS Class: Guaranteed (예측 가능한 성능)
    containers:
    - name: app
      resources:
        requests:
          memory: "256Mi"
          cpu: "500m"
        limits:
          memory: "256Mi"  # requests와 동일
          cpu: "500m"      # requests와 동일
    

5) 운영 및 모니터링

  1. 레이블링 전략

    metadata:
      labels:
        app: my-app
        component: sidecar
        sidecar-type: logging
        version: v1.2.3
    
  2. 로그 구조화

    // Sidecar 로그는 JSON 형식으로
    {
      "timestamp": "2025-01-15T10:30:00Z",
      "level": "INFO",
      "component": "git-sync",
      "message": "Synced successfully",
      "repo": "<https://github.com/example/repo>"
    }
    
  3. 메트릭 수집

    # Prometheus annotations
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9090"
        prometheus.io/path: "/metrics"
    

6) 상속 vs 조합 결정 가이드

기능을 추가하고 싶다면?
│
├─ 기능이 여러 앱에서 재사용되는가?
│  ├─ YES → Sidecar (조합)
│  └─ NO  → 다음 질문으로
│
├─ 기능이 메인 앱과 다른 릴리스 주기를 가지는가?
│  ├─ YES → Sidecar (조합)
│  └─ NO  → 다음 질문으로
│
├─ 기능이 다른 팀/언어로 개발되는가?
│  ├─ YES → Sidecar (조합)
│  └─ NO  → 다음 질문으로
│
└─ 런타임에 기능을 교체할 가능성이 있는가?
   ├─ YES → Sidecar (조합)
   └─ NO  → Dockerfile (상속)

10. 참고자료

공식 문서

디자인 패턴

실무 사례

  • "Kubernetes Patterns" by Bilgin Ibryam and Roland Huß (O'Reilly)
  • "Production Kubernetes" by Josh Rosso, Rich Lander, Alex Brand, John Harris (O'Reilly)

GitHub 예제

profile
DevOps Engineer

0개의 댓글