Istio를 어려운 방법으로 배우기: Canary, mTLS, 그리고 Tracing을 활용한 실제 Service Mesh 실습
Source: Dev.to
왜 문서만 읽지 않고 서비스 메시 실험실을 만들었는가
이 프로젝트는 서비스 메시가 버즈워드 너머에서 실제로 무엇을 하는지 진정으로 이해하기 위한 개인 실험실로 시작되었습니다. 샘플 앱을 사용하는 대신, 실제 3‑계층 앱(Next.js 프론트엔드, Go 백엔드, Flask ML 서비스)을 사용해 Istio가 트래픽, 보안, 가시성을 실제로 어떻게 바꾸는지 살펴보는 것이 목표였습니다.
아이디어는 간단했습니다: 이 설정이 언젠가 프로덕션에 배포될 수 있을 것처럼 느껴진다면 학습 효과가 오래가고, 이 레포는 앞으로의 작업을 위한 살아있는 레퍼런스가 됩니다.
3RVision 플랫폼: 실제 앱, 실제 트래픽
3RVision은 각각 자체 Kubernetes 네임스페이스에서 실행되는 세 개의 논리적 서비스로 구성됩니다:
- frontend → Next.js UI
- backend → Go API 서버
- ml → Flask ML 추론 서비스
프론트엔드는 백엔드와 통신하고, 백엔드는 모델 추론을 위해 ML 서비스에 호출합니다 – 바로 서비스 메시의 혜택을 받는 전형적인 홉‑바이‑홉 트래픽입니다.
각 서비스는 두 가지 배포 변형을 가집니다:
stable버전 (프로덕션)canary버전 (새 기능 테스트)
여기서 Istio의 트래픽 관리 기능이 활용됩니다.
환경 구성: Kind + Terraform + 네임스페이스
클라우드 계정 관리의 번거로움을 피하기 위해 Terraform이 로컬 Kind 클러스터를 프로비저닝합니다:
- 컨트롤‑플레인 노드 1개
- 워커 노드 2개
- HTTP(80)와 HTTPS(443) 포트 매핑
클러스터 설정 워크플로우
# Provision the cluster
terraform init
terraform apply
# Create namespaces
kubectl create namespace frontend
kubectl create namespace backend
kubectl create namespace ml
# Enable Istio sidecar injection
kubectl label namespace frontend istio-injection=enabled
kubectl label namespace backend istio-injection=enabled
kubectl label namespace ml istio-injection=enabled
이렇게 하면 명확히 구분됩니다:
Terraform → 클러스터 수명 주기
Kubernetes → 애플리케이션 리소스
Istio → 트래픽 shaping 및 보안
Istio가 들어가는 방식: 사이드카, 게이트웨이, 데이터 플레인
Istio는 각 애플리케이션 컨테이너 옆에 Envoy 사이드카 프록시를 주입함으로써 동작합니다. 모든 인바운드·아웃바운드 트래픽이 이 사이드카를 거치므로, 애플리케이션 코드를 변경하지 않고 라우팅, 재시도, mTLS, 텔레메트리를 추가할 수 있습니다.

아키텍처 개요
┌─────────────────────┐
│ User/Client │
└──────────┬──────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ KIND KUBERNETES CLUSTER │
│ (Terraform Provisioned) │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Control Plane │ │ Worker #1 │ │ Worker #2 │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│ ISTIO SERVICE MESH │
│ │
│ Gateway ──────► VirtualService ──────► DestinationRule │
│ (Ingress) (Routing) (mTLS + Load Balancing) │
├──────────────────────────────────────────────────────────────────────────┤
│ MICROSERVICES │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ FRONTEND │ │ BACKEND │ │ ML MODEL │ │
│ │ (Next.js) │───►│ (Go) │───►│ (Flask) │ │
│ │ Port: 3000 │ │ Port: 8080 │ │ Port: 5001 │ │
│ │ │ │ │ │ │ │
│ │ stable/canary│ │ stable/canary│ │ stable/canary│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│ OBSERVABILITY STACK │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Prometheus │ │ Jaeger │ │ Grafana │ │
│ │ (Metrics) │ │ (Tracing) │ │ (Dashboards) │ │
│ │ Port: 9090 │ │ Port: 16686 │ │ Port: 3000 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
가장자리에서는 Istio Ingress Gateway가 외부 요청을 받아 VirtualService에 정의된 라우팅 규칙을 적용하고 트래픽을 메시 내부로 전달합니다.
트래픽 관리 101: VirtualService, DestinationRule, Subset
이 프로젝트에서 사용된 주요 Istio 빌딩 블록은 다음과 같습니다:
| 리소스 | 목적 |
|---|---|
| Gateway | 특정 포트에서 외부 트래픽을 서비스에 노출 |
| VirtualService | 요청이 어떻게 라우팅되는지 정의 (헤더, 가중치, 경로 등) |
| DestinationRule | 트래픽에 대한 정책 정의 (Subset, 로드밸런싱, 연결 풀 등) |
예시: Frontend VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: frontend-vs
namespace: frontend
spec:
hosts:
- "frontend.local"
gateways:
- frontend-gateway
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: frontend-service
subset: canary
weight: 100
- route:
- destination:
host: frontend-service
subset: stable
weight: 100