Sidecar
Sidecar Pattern
메인 컨테이너 옆에 보조 컨테이너 배치. 서비스 메시의 기반.
Sidecar Pattern
메인 컨테이너 옆에 보조 컨테이너 배치. 서비스 메시의 기반.
Sidecar Pattern은 메인 애플리케이션 컨테이너 옆에 보조 컨테이너를 배치하여 공통 기능을 분리하는 마이크로서비스 디자인 패턴입니다. 오토바이 옆에 붙은 사이드카처럼 메인 컨테이너와 생명주기를 함께하며, 네트워크 네임스페이스와 볼륨을 공유합니다.
핵심 개념:
주요 활용 사례:
Service Mesh에서의 역할:
Istio, Linkerd 같은 Service Mesh는 모든 서비스 Pod에 사이드카 프록시(Envoy 등)를 자동 주입합니다. 이 프록시가 모든 인바운드/아웃바운드 트래픽을 가로채서 mTLS 암호화, 로드 밸런싱, 서킷 브레이커, 분산 트레이싱을 제공합니다. 애플리케이션 코드 수정 없이 네트워크 레벨 기능을 투명하게 적용할 수 있습니다.
Kubernetes 1.28+ Sidecar Container: 기존에는 사이드카도 일반 컨테이너로 취급되어 시작/종료 순서 제어가 어려웠습니다. 1.28부터 정식 지원되는 Sidecar Container(initContainers + restartPolicy: Always)는 메인 컨테이너보다 먼저 시작하고 나중에 종료되어 더 안정적인 라이프사이클 관리가 가능합니다.
# logging-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-logging
spec:
containers:
# 메인 애플리케이션
- name: app
image: my-app:latest
volumeMounts:
- name: logs
mountPath: /var/log/app
resources:
limits:
memory: "512Mi"
cpu: "500m"
# Sidecar: 로그 수집 (Fluentd)
- name: log-collector
image: fluent/fluentd:v1.16
volumeMounts:
- name: logs
mountPath: /var/log/app
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
resources:
limits:
memory: "128Mi"
cpu: "100m"
volumes:
- name: logs
emptyDir: {}
- name: fluentd-config
configMap:
name: fluentd-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluent.conf: |
<source>
@type tail
path /var/log/app/*.log
pos_file /var/log/app/fluentd.pos
tag app.logs
<parse>
@type json
</parse>
</source>
<match app.logs>
@type elasticsearch
host elasticsearch.logging.svc
port 9200
index_name app-logs
</match>
# vault-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-vault
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "my-app-role"
vault.hashicorp.com/agent-inject-secret-db: "secret/data/db/config"
vault.hashicorp.com/agent-inject-template-db: |
{{ with secret "secret/data/db/config" -}}
export DB_HOST="{{ .Data.data.host }}"
export DB_USER="{{ .Data.data.username }}"
export DB_PASS="{{ .Data.data.password }}"
{{- end }}
spec:
serviceAccountName: my-app-sa
containers:
- name: app
image: my-app:latest
command: ["/bin/sh", "-c"]
args:
- source /vault/secrets/db && ./start.sh
volumeMounts:
- name: vault-secrets
mountPath: /vault/secrets
# Vault Injector가 자동으로 Sidecar 추가
---
# Kubernetes 1.28+ Native Sidecar Container
apiVersion: v1
kind: Pod
metadata:
name: app-with-native-sidecar
spec:
initContainers:
# Native Sidecar: 메인보다 먼저 시작, 나중에 종료
- name: vault-agent
image: hashicorp/vault:1.15
restartPolicy: Always # 이게 핵심! Sidecar로 동작
args:
- agent
- -config=/etc/vault/agent.hcl
volumeMounts:
- name: secrets
mountPath: /vault/secrets
- name: vault-config
mountPath: /etc/vault
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: secrets
mountPath: /vault/secrets
readOnly: true
volumes:
- name: secrets
emptyDir:
medium: Memory # RAM에 저장 (보안)
- name: vault-config
configMap:
name: vault-agent-config
# Namespace에 Istio injection 활성화
kubectl label namespace my-app istio-injection=enabled
# Deployment 배포 시 Envoy Sidecar 자동 주입
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service
namespace: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-service
template:
metadata:
labels:
app: my-service
# 특정 Pod에서 Sidecar 비활성화
# annotations:
# sidecar.istio.io/inject: "false"
spec:
containers:
- name: app
image: my-service:latest
ports:
- containerPort: 8080
# 배포 후 Pod 확인 - Envoy Sidecar가 자동 추가됨
# kubectl get pods -n my-app
# NAME READY STATUS RESTARTS
# my-service-5d4f6c7b8-abc12 2/2 Running 0
# ^^^
# app + istio-proxy (Envoy)
# Istio VirtualService로 트래픽 제어
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-service
spec:
hosts:
- my-service
http:
- route:
- destination:
host: my-service
subset: v1
weight: 90
- destination:
host: my-service
subset: v2
weight: 10 # Canary: 10% 트래픽을 v2로
시니어: "서비스마다 로깅, 트레이싱 코드가 중복이네. 언어도 다르고..."
개발자: "Sidecar 패턴으로 분리하면 어떨까요? Fluentd Sidecar로 로그 수집하고, Jaeger Agent Sidecar로 트레이스 전송하면 앱 코드에서 인프라 로직을 뺄 수 있어요."
시니어: "리소스 오버헤드는?"
개발자: "Sidecar 하나당 메모리 50-100MB 정도요. 대신 각 앱에서 SDK 초기화 오버헤드가 사라지고, 버전 업그레이드도 Sidecar만 바꾸면 되니까 운영이 편해져요."
면접관: "Istio에서 Sidecar Proxy가 하는 일을 설명해주세요."
지원자: "Envoy Sidecar가 모든 인바운드/아웃바운드 트래픽을 가로챕니다. iptables 규칙으로 트래픽을 Envoy로 리다이렉트하고요. mTLS로 서비스 간 통신을 암호화하고, 로드밸런싱, 서킷브레이커, 재시도 정책을 적용합니다. 또한 모든 요청의 메트릭과 트레이스를 수집해서 관측성을 제공해요."
면접관: "Sidecar 없는 Service Mesh는요?"
지원자: "Cilium 같은 eBPF 기반 Service Mesh가 있어요. 커널 레벨에서 트래픽을 처리해서 Sidecar 오버헤드가 없죠. 다만 eBPF 지원 커널이 필요하고, L7 기능이 Envoy보다 제한적일 수 있어요."
운영팀: "Pod가 Ready인데 앱 컨테이너에서 외부 API 호출이 안 돼요."
개발자: "Istio Sidecar 때문일 수 있어요. Envoy가 아직 xDS 설정을 못 받아서 트래픽 라우팅을 못하는 거예요. holdApplicationUntilProxyStarts: true 설정하면 Envoy 준비될 때까지 앱 컨테이너 시작을 지연시킬 수 있어요."
운영팀: "아, Sidecar가 먼저 준비되어야 하는구나."