서비스 메시는 마이크로서비스 사이의 통신을 애플리케이션 코드 밖으로 빼내어, 트래픽 관리·보안·관측성을 인프라 계층에서 일관되게 처리하는 기술입니다. mTLS 자동 암호화, 재시도와 서킷 브레이커, 세밀한 트래픽 분할, 서비스 간 통신의 자동 계측 같은 기능을 코드 수정 없이 얻을 수 있다는 점이 매력적이죠. 하지만 서비스 메시는 공짜 기능이 아니라 운영 부담과의 교환입니다.
이 글은 “서비스 메시를 써야 하는가”라는 판단 자체에 초점을 맞춥니다. Istio와 Linkerd라는 대표적인 두 선택지를 비교하고, 도입을 정당화하는 조건과 오히려 후회하게 되는 상황을 솔직하게 정리합니다. 결론부터 말하면, 대부분의 초기 조직은 메시가 필요 없습니다.
서비스 메시가 실제로 해결하는 문제
서비스 메시의 핵심은 사이드카 프록시(또는 앰비언트 모드의 노드 프록시)입니다. 각 파드 옆에 프록시를 붙여 모든 인바운드/아웃바운드 트래픽이 이 프록시를 거치게 하고, 프록시들을 컨트롤 플레인이 중앙에서 설정합니다. 이 구조 덕분에 다음이 애플리케이션 코드와 무관하게 처리됩니다.
- mTLS: 서비스 간 통신을 자동으로 상호 인증·암호화
- 트래픽 관리: 카나리, 트래픽 미러링, 재시도, 타임아웃, 서킷 브레이커
- 관측성: 요청 단위 메트릭·트레이스를 언어와 무관하게 수집
- 인가 정책: “A 서비스만 B 서비스의 특정 경로 호출 가능” 같은 L7 정책
여기서 중요한 판단 기준이 나옵니다. 위 기능 중 여러 개가 동시에, 여러 서비스에 걸쳐, 코드로 해결하기엔 반복적으로 필요하다면 메시가 후보입니다. 하나만 필요하다면 대개 라이브러리나 인그레스로 충분합니다.
Istio: 강력하지만 무거운 선택
Istio는 기능 폭이 가장 넓습니다. Envoy 프록시를 사이드카로 쓰며, 세밀한 트래픽 라우팅과 정책을 CRD로 표현합니다. 아래는 카나리 배포에서 트래픽을 90/10으로 나누는 전형적인 설정입니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payments
spec:
hosts:
- payments
http:
- route:
- destination:
host: payments
subset: v1
weight: 90
- destination:
host: payments
subset: v2
weight: 10
retries:
attempts: 3
perTryTimeout: 2s
retryOn: 5xx,reset,connect-failure
Istio의 장점은 표현력입니다. L7 라우팅, 헤더 기반 분기, 트래픽 미러링, 외부 인가(ext-authz)까지 거의 모든 시나리오를 커버합니다. 앰비언트 모드가 성숙하면서 사이드카 없이 노드 단 프록시로 리소스 부담을 줄이는 방향도 생겼습니다. 대신 학습 곡선이 가파르고, CRD 종류가 많으며, 잘못 설정하면 디버깅이 매우 까다롭습니다.
Linkerd: 단순함을 무기로
Linkerd는 정반대 철학입니다. Rust로 작성된 전용 마이크로프록시(linkerd2-proxy)를 써서 메모리·CPU 사용량이 작고, 설정이 훨씬 단순합니다. mTLS는 기본으로 켜지고, 대부분의 기능이 “그냥 동작”하도록 설계되어 있습니다.
# 설치와 상태 점검이 명령 몇 개로 끝난다
linkerd install --crds | kubectl apply -f -
linkerd install | kubectl apply -f -
linkerd check
# 특정 네임스페이스에 프록시 주입
kubectl get deploy -n prod -o yaml \
| linkerd inject - \
| kubectl apply -f -
트래픽 분할도 표준 리소스로 간결하게 표현합니다.
apiVersion: policy.linkerd.io/v1beta3
kind: HTTPRoute
metadata:
name: payments-canary
namespace: prod
spec:
parentRefs:
- name: payments
kind: Service
group: core
rules:
- backendRefs:
- name: payments-v1
weight: 90
- name: payments-v2
weight: 10
Linkerd의 트레이드오프는 표현력의 상한입니다. Istio만큼 복잡한 L7 시나리오나 광범위한 확장 생태계는 없습니다. 하지만 “메시가 필요하지만 Istio는 과하다”는 조직에는 운영 부담 대비 만족도가 높습니다.
도입 전에 던져야 할 질문들
도구 비교보다 먼저 조직 상황을 점검해야 합니다. 아래 질문에 대부분 “아니오”라면 메시 도입을 미루는 편이 낫습니다.
- 서비스 수가 수십 개 이상이고 서로 활발히 통신하는가? (5~10개 서비스라면 대개 불필요)
- 서비스 간 mTLS 의무화 같은 규제·보안 요구가 있는가?
- 언어가 여러 개라서 재시도·서킷 브레이커를 각 언어 라이브러리로 통일하기 어려운가?
- 카나리·트래픽 미러링 같은 정교한 배포 전략이 반복적으로 필요한가?
- Kubernetes와 프록시를 운영·디버깅할 플랫폼 팀 역량이 있는가?
특히 마지막 항목이 결정적입니다. 메시는 장애의 새로운 층을 추가합니다. 사이드카가 트래픽을 가로채므로, 원인이 애플리케이션인지 프록시인지 컨트롤 플레인인지 구분하는 디버깅 능력이 없으면 오히려 신뢰성이 떨어집니다.
# 메시가 없어도 인그레스+표준 라이브러리로 커버되는 경우가 많다
# 예: 인그레스에서 TLS 종료 + 재시도, 앱에서는 gRPC 기본 재시도 정책
grpc.WithDefaultServiceConfig(`{
"methodConfig": [{
"name": [{"service": "payments.PaymentService"}],
"retryPolicy": {
"maxAttempts": 3,
"initialBackoff": "0.2s",
"retryableStatusCodes": ["UNAVAILABLE"]
}
}]
}`)
비용과 실패 모드를 정직하게 계산하기
메시 도입의 실제 비용은 다음과 같습니다. 리소스 오버헤드: 사이드카마다 CPU·메모리가 붙고, 요청마다 프록시 홉이 추가되어 지연시간이 소폭 늘어납니다. 업그레이드 부담: 컨트롤 플레인과 데이터 플레인(프록시)의 버전을 맞춰가며 정기적으로 업그레이드해야 하고, 이 과정 자체가 위험 작업입니다. 인지 부하: 새로운 CRD, 새로운 장애 유형, 새로운 관측 대상이 팀의 학습 대상이 됩니다.
# 메시 도입 후 반드시 갖춰야 할 검증 루틴 예시
linkerd viz stat deploy -n prod # 성공률/RPS/지연 실시간 확인
istioctl analyze -n prod # 설정 오류 정적 분석
istioctl proxy-config cluster payments-xxxx # 프록시가 본 실제 설정 덤프
권장 접근은 점진적 도입입니다. 전체 클러스터에 한 번에 주입하지 말고, 관측성처럼 위험이 낮은 기능부터 한 네임스페이스에 적용해 팀이 운영 감각을 익힌 뒤 mTLS, 트래픽 관리 순으로 확장합니다. 처음부터 Istio의 모든 기능을 켜는 것은 실패로 가는 지름길입니다.
마무리
서비스 메시는 “많은 서비스가 서로 활발히 통신하고, mTLS와 정교한 트래픽 제어가 반복적으로 필요하며, 이를 운영할 플랫폼 팀이 있는” 조직에서 빛을 발합니다. 그 조건에서 Istio는 표현력을, Linkerd는 단순함과 낮은 오버헤드를 제공합니다. 반대로 서비스가 몇 개뿐이거나 팀 역량이 부족하다면, 메시는 문제를 해결하기보다 새로운 장애 층을 추가할 뿐입니다. 도구를 고르기 전에 “정말 메시가 필요한가”부터 정직하게 답하는 것이, 이 기술을 다루는 가장 중요한 역량입니다.