Istio Traffic Management: 모범 사례 살펴보기
이 블로그 포스트는 Istio 를 사용하며 네트워킹 또는 트래픽 관리 문제를 방지하기 위한 특정 배포 또는 구성 지침을 제공합니다.
목차
1. 서비스의 기본 경로 설정
2. 네임스페이스 간 구성 공유 제어
3. 네임스페이스 간 Istio Destination Rule 적용 문제
4. Istio VirtualService 및 DestinationRule 분할 관리
5. Istio 503 오류 방지: 서브셋 설정 순서
1. 서비스의 기본 경로 설정
Istio의 기본 동작은 아무런 규칙을 설정하지 않아도 트래픽을 모든 버전의 대상 서비스로 보내도록 되어 있지만, 모든 서비스에 대해 기본 경로를 포함하는 VirtualService를 처음부터 정의하는 것이 일반적으로 모범 사례로 간주됩니다.
처음에는 서비스의 단일 버전만 존재하더라도, 두 번째 버전을 배포하려는 순간부터 해당 버전이 무작위로 트래픽을 받지 않도록 사전에 라우팅 규칙을 설정해야 합니다.
또한, Istio의 기본 라운드 로빈 방식의 라우팅을 그대로 사용할 경우 발생할 수 있는 미묘한 문제가 있습니다. 이는 Istio의 대상 규칙(Destination Rule) 평가 알고리즘과 관련이 있습니다.
요청을 라우팅할 때, Envoy는 먼저 VirtualService의 경로 규칙을 평가하여 특정 서브셋(subset)으로 라우팅할지를 결정합니다.
만약 서브셋이 선택되면, 그때서야 해당 서브셋에 해당하는 Destination Rule 정책이 활성화됩니다.
즉, 특정 서브셋에 대한 정책을 정의했더라도, 트래픽이 해당 서브셋으로 명시적으로 라우팅되지 않으면 해당 정책이 적용되지 않습니다.
예를 들어, 아래와 같이 reviews 서비스에 대한 Destination Rule이 정의되어 있고, 관련된 VirtualService가 없다고 가정해 봅니다.
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
Istio의 기본 라운드 로빈 방식에 의해 요청이 가끔 v1 인스턴스로 전달될 수도 있고, 유일한 실행 버전이 v1이라면 항상 해당 버전이 선택될 수도 있습니다.
그러나 위의 trafficPolicy는 절대 적용되지 않습니다.
이 문제를 해결하는 방법은 두 가지가 있습니다.
- trafficPolicy를 한 단계 위로 이동하여 모든 버전에 적용되도록 합니다.
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
subsets:
- name: v1
labels:
version: v1
2. VirtualService에서 명시적으로 서브셋을 대상으로 하는 경로 규칙을 정의합니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
2. 네임스페이스 간 구성 공유 제어
VirtualService, DestinationRule 또는 ServiceEntry를 특정 네임스페이스에서 정의한 후 다른 네임스페이스에서도 재사용할 수 있습니다.
Istio는 기본적으로 모든 트래픽 관리 리소스를 모든 네임스페이스에 자동으로 내보내지만(export), exportTo 필드를 사용하여 가시성을 조정할 수 있습니다.
예를 들어, 아래 VirtualService는 동일한 네임스페이스에서 생성된 워크로드의 요청에만 영향을 미칩니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myservice
spec:
hosts:
- myservice.com
exportTo:
- "."
http:
- route:
- destination:
host: myservice
Kubernetes 서비스의 가시성도 networking.istio.io/exportTo 애노테이션을 사용하여 제어할 수 있습니다.
3. 네임스페이스 간 Istio Destination Rule 적용 문제
Destination Rule을 특정 네임스페이스에서 다른 네임스페이스로 내보낸(export)다 해도 해당 네임스페이스에서 실제로 적용되는 것은 아닙니다.
Destination Rule이 적용되려면, Destination Rule 조회 경로(lookup path) 내에 해당 네임스페이스가 포함되어 있어야 합니다.
Destination Rule 조회 경로 순서
- 클라이언트 네임스페이스
- 서비스 네임스페이스
- MeshConfig의
rootNamespace(기본적으로istio-system)
예를 들어, 아래 Destination Rule을 ns1 네임스페이스에 생성했다고 가정해 봅니다.
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: myservice
spec:
host: myservice.default.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
- ns1에서 myservice로 요청 → Destination Rule이 적용됨 ✅
- ns2에서 myservice로 요청 → Destination Rule이 적용되지 않음 ❌
이 문제를 피하려면 Destination Rule을 서비스와 동일한 네임스페이스(예: default)에 배치하는 것이 좋습니다.
또는, istio-system 네임스페이스로 이동할 수도 있지만, 이는 모든 네임스페이스에 적용되는 글로벌 설정이므로 권장되지 않습니다.
4. Istio VirtualService 및 DestinationRule 분할 관리
모든 라우트 규칙을 하나의 VirtualService 또는 DestinationRule에서 관리하는 것이 불편할 경우, 이를 여러 개의 리소스로 나눌 수 있습니다.
Istio는 이러한 VirtualService 및 DestinationRule을 자동으로 병합하여 하나의 구성으로 만듭니다.
예를 들어, myapp.com 도메인에서 여러 서비스로 경로를 분기하는 경우, 아래와 같이 하나의 VirtualService에서 관리할 수 있습니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp.com
gateways:
- myapp-gateway
http:
- match:
- uri:
prefix: /service1
route:
- destination:
host: service1.default.svc.cluster.local
- match:
- uri:
prefix: /service2
route:
- destination:
host: service2.default.svc.cluster.local
그러나 이렇게 하면 각 서비스별 라우팅 규칙을 개별적으로 관리하기 어려워집니다.
이를 방지하려면 각 서비스에 대해 개별적인 VirtualService를 생성할 수 있습니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp-service1
spec:
hosts:
- myapp.com
gateways:
- myapp-gateway
http:
- match:
- uri:
prefix: /service1
route:
- destination:
host: service1.default.svc.cluster.local
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp-service2
spec:
hosts:
- myapp.com
gateways:
- myapp-gateway
http:
- match:
- uri:
prefix: /service2
route:
- destination:
host: service2.default.svc.cluster.local
이러한 방식은 Ingress Gateway에 연결된 VirtualService에서만 적용 가능하며, Sidecar에서는 지원되지 않습니다.
5. Istio 503 오류 방지: 서브셋 설정 순서
새로운 서브셋을 추가할 때:
- 먼저 Destination Rule을 업데이트하여 서브셋을 추가합니다.
- 몇 초간 대기하여 설정이 전파되도록 합니다.
- VirtualService를 업데이트하여 새 서브셋을 참조하도록 변경합니다.
서브셋을 제거할 때:
- VirtualService에서 서브셋 참조를 먼저 삭제합니다.
- 몇 초간 대기합니다.
- Destination Rule에서 불필요한 서브셋을 삭제합니다.
이러한 Make-before-break 방식을 사용하면 503 오류를 방지할 수 있습니다.