개요
이 글은 Istio의 Data Plane, 그중에서도 사이드카에 집중한다. 사이드카가 어떤 원리로 앱 Pod에 주입되고, 어떻게 앱의 트래픽을 가로채 처리하는지를 실제 kind 로컬 클러스터(bobae-labs) 위에서 명령어 레벨로 확인한다.
Service Mesh와 Istio의 전체 구조는 이전 글에서 다뤘고, 이 글을 단독으로 읽어도 되도록 필요한 부분만 짧게 복습하고 시작해보자!
- Service Mesh: 모든 서비스 간 트래픽을 프록시로 한 번 통과시켜, 통신 제어(라우팅·재시도·mTLS·telemetry)를 앱 코드 밖으로 빼내는 구조. 정책을 선언하는 Control Plane과 실제 트래픽을 처리하는 Data Plane으로 나뉜다.
- Istio: Control Plane은 istiod, Data Plane은 Envoy 프록시로 구현한다. istiod가 xDS(gRPC 기반) 프로토콜로 각 Envoy에 설정을 push한다.
- 사이드카: Data Plane의 Envoy는 앱 Pod마다 사이드카 컨테이너(istio-proxy)로 주입된다. 이 컨테이너 안에는 트래픽을 처리하는 Envoy와, istiod와 연결해 Envoy를 부트스트랩·설정하는 pilot-agent 두 프로세스가 함께 돈다.
1. Sidecar Pattern
Istio의 (전통적인) Data Plane은 사이드카 패턴으로 동작한다. 즉, 앱 컨테이너 하나당 Envoy 컨테이너 하나가 같은 Pod 안에 나란히 배치된다. 같은 Pod = 같은 네트워크 네임스페이스이므로, iptables 규칙만 잘 걸어두면 앱의 모든 트래픽을 Envoy로 우회시킬 수 있다. 앱 입장에서는 코드 한 줄 안 바꿔도 mesh에 편입되는 셈이다.
2. Sidecar Injection
App Pod가 생성될 때, 사이드카가 주입되는 과정은 다음과 같다. [istio docs]
- 네임스페이스에
istio-injection=enabled라벨을 단다. - 그 네임스페이스에서 Pod가 생성되면, mutating webhook이 Pod spec을 가로채서 컨테이너와 볼륨을 추가한다.
- 추가되는 것은 init container(istio-init) + 사이드카 컨테이너(istio-proxy, 내부에 pilot-agent+envoy) 두 가지다.
# 1. 네임스페이스 생성
kubectl create namespace bobae-sidecar-lab
# 2. 그 네임스페이스에 사이드카 자동 주입 라벨 달기
kubectl label namespace bobae-sidecar-lab istio-injection=enabled
# 3. 확인
kubectl get namespace bobae-sidecar-lab -L istio-injection

이 istio-injection 라벨을 통해서, 앞으로 네임스페이스에 Pod를 만들면 → Mutating Webhook이 가로채서 → istio-proxy 사이드카와 istio-init init 컨테이너를 자동으로 붙여주는 과정을 겪는다. 라벨이 없으면 Pod를 생성해도 사이드카가 붙지 않는다.
2.1. istio-init & istio-proxy
injection이 허용된 네임스페이스에 주입되는 두 컨테이너의 역할은 다음과 같다.
- istio-init (init container): 앱보다 먼저 실행되어 iptables 규칙을 세팅하는 역할만 하고 종료된다. 이 규칙이 Pod로 들어오고 나가는 트래픽을 Envoy(15001/15006 등 포트)로 redirect한다. 즉, "앱의 트래픽이 강제로 Envoy를 거치게" 만드는 장치가 여기서 심어진다.
- istio-proxy (Envoy + pilot-agent): 실제 트래픽을 처리하는 사이드카 프록시 컨테이너. 앞서 개요에서 짚었듯 이 안에는 트래픽을 처리하는 Envoy와, istiod와 연결해 Envoy를 설정하는 pilot-agent가 함께 돈다. 앱이 살아있는 동안 계속 떠 있으면서 라우팅·mTLS·telemetry 등을 수행한다.
2.2. Sidecar 실제 주입 과정 확인!
사이드카 주입은 파드가 생성되는 시점에 발생한다. 간단한 앱을 배포하고 Pod를 띄워서 사이드카가 같이 띄워지는지 확인해보자.
2.2.1. 매니페스트 정의하고 앱 띄우기
가장 기본적인 매니페스트 예제로 앱을 띄운다. 각 의미는 주석으로!
apiVersion: apps/v1
kind: Deployment # 리소스 종류: Deployment
metadata:
name: httpbin # 이 Deployment 이름
spec: # 원하는 상태(desired state) 기술
replicas: 1 # Pod를 1개 띄움
selector:
matchLabels:
app: httpbin
version: v1 # "이 라벨 붙은 Pod가 내 관리 대상"
template: # 아래 설계도대로 Pod를 찍어내라
metadata:
labels:
app: httpbin
version: v1 # 찍어낼 Pod에 붙일 라벨
spec:
serviceAccountName: httpbin # 이 Pod는 httpbin 계정으로 실행
containers:
- image: docker.io/mccutchen/go-httpbin:v2.15.0 # 실행할 도커 이미지
name: httpbin
ports:
- containerPort: 8080 # 컨테이너가 8080 포트로 서비스함
2.2.2. injection 라벨이 붙은 namespace에 배포, Pod 상태 확인
정의된 yaml 매니페스트대로 앱을 클러스터에 올려보고, Pod 구성을 확인해보았다.
# 아까 라벨(istio-injection=enabled) 달아둔 네임스페이스에 배포
kubectl apply -f httpbin.yaml -n bobae-sidecar-lab

해당 Pod의 READY 컬럼을 보면, 우리가 매니페스트에 정의한 컨테이너는 httpbin 하나 뿐이지만 결과는 2/2(앱 + 사이트카)다. istio-injection=enabled 라벨이 붙은 네임스페이스에서 기존 컨테이너에 사이드카가 같이 배포되었다는 의미다.
# 해당 Pod의 상태를 좀 더 구체적으로 확인
kubectl describe pod -n bobae-sidecar-lab httpbin-545d7f5848-vfdn7


Init Container에서 istio-init, istio-proxy 두 가지 컨테이너를 확인할 수 있다. 두 컨테이너의 상태가 대조적인게 포인트인데,
- istio-init : Terminated / Completed. init 컨테이너로, iptables 규칙을 심는 역할을 다 하고 빠졌다. 그래서 2/2를 셀 때도 이 친구는 안 센다(이미 종료됐으니까).
- istio-proxy : Running. agent와 envoy가 있는 컨테이너다.
3. native sidecar와 ambient mode
지금까지 본 방식이 Istio의 전통적 사이드카다. 우리 회사도 여전히 이 방식을 쓰고 있다. 최근에는 사이드카의 구조적 아쉬움을 해소하기 위해 새로운 방식의 사이드카들이 나왔는데, 이를 살펴보자.
3.1. 기존 Sidecar 패턴의 문제점
- 사이드카 수명이 Pod 수명보다 짧은 경우(대표적으로 istio-init, initContainers에 Spec 작성)
- init container는 완료 후 종료되는 컨테이너라, 명확한 시작 순서를 제공한다.
- 문제점: 사이드카가 종료되어야 그 다음 init container와 메인 컨테이너들이 시작될 수 있다.
- 사이드카 수명이 Pod 수명과 같은 경우(Envoy, containers에 Spec 작성)
- 워크로드 컨테이너와 함께 도는 일반 메인 컨테이너로 구현한다.
- 문제점 1: 시작 순서를 제어할 수 없다. (앱이 프록시보다 먼저 떠서, Envoy가 없는 상태에서 요청이 갈 곳을 잃게 된다.)
- 문제점 2: 워크로드 컨테이너가 종료된 뒤에도 사이드카가 Pod 종료를 막을 수 있다. 대표적으로 Job/CronJob에서 메인 컨테이너가 끝나고
istio-proxy가 계속 떠 있어 Pod가Completed로 넘어가지 못하고 무기한으로 실행 상태가 유지된다.
- 이 문제 때문에 메시를 태우지 않고 사용하면서, 트래픽 가시성이 떨어진다.
3.2. Native Sidecar
Kubernetes에서 SidecarContainers feature gate를 활성화하면 사용할 수 있는 기능으로, 사이드카를 restartPolicy: Always를 가진 init container로 띄우는 기능이다. (Always 옵션만 설정 가능하다.) init container이므로 앱 컨테이너보다 먼저 기동을 끝내고, 앱이 종료된 뒤에 종료되도록 순서가 보장된다. 위의 startup race와 Job 종료 문제가 여기서 해소된다.
(작성중)
'DevOps > DevOps' 카테고리의 다른 글
| [K8S] Service Mesh와 Istio (0) | 2026.07.05 |
|---|---|
| [K8S] Mac Mini(Ubuntu)에 kind 기반 로컬 K8S Cluster 환경 구축하기 (0) | 2026.06.21 |
| [DevOps] SSH 없이 안전하게 EC2 운영하기: SSM 기반 접근 제어와 전역 정책 설계 (0) | 2025.12.07 |
| [K8S] 자주 사용하는 Kubernetes CLI 정리 (1) | 2025.09.28 |
| [DevOps] 멀티모듈 프로젝트 CI/CD 적용 - 설계 구상 편 (3) | 2024.07.22 |