본문 바로가기
DevOps/Istio

istio traffic 관리 (1) [VirtualService & DestinationRule]

by 비어원 2025. 1. 12.
728x90

istio의 트래픽 라우팅 룰은 서비스 간 트래픽과 API 흐름을 쉽게 제어할 수 있게 한다. istio는 서킷 브레이커, 타임아웃, retry와 같은 서비스 레벨 수준의 기능 구성을 간단하게 하고, 비율 기반 트래픽 분할을 활용하여 A/B 테스팅, Canary rollout 등을 쉽게 할 수 있다. 또한, 종속 서비스나 네트워크의 오류에 대해 애플리케이션을 보다 강력하게 만드는 데 도움이 되는 out-of-box failure recovery 기능을 제공한다.

 

istio의 트래픽 관리 모델은 서비스와 함께 배포되는 envoy-proxy에 의존한다. 메쉬에서 주고받은 모든 트래픽은 envoy를 거치기 때문에 서비스를 변경하지 않고도 메쉬간 트래픽을 쉽게 전달하고 제어할 수 있다.

 

istio에서 제공하는 트래픽 관리 기능은 istio에서 제공하는 커스텀 리소스 (CR) 을 구성함으로써 트래픽 관리를 구성할 수 있다. istio에서 트래픽 관리를 위해 사용하는 커스텀 리소스는 다음과 같다.

 

  • VirtualService
  • Gateway
  • DestinationRule
  • ServiceEntry
  • Sidecar 등

 

istio에서 풍부한 트래픽 관리 기능을 제공하기 때문에 커스텀 리소스 종류가 꽤나 많다. 일단 트래픽 관리에 기본이되고 자주 사용하는 것 부터 차근차근 익혀나가다보면 istio를 잘 활용할 수 있을 것이다.

 

Prerequisites

일단 서비스 메쉬인 istio를 실습하기 위해서는 적당한 마이크로서비스가 배포되어 있어야 한다. 실습용으로 자주 사용되는 bookinfo를 먼저 쿠버네티스에 배포하자. bookinfo의 아키텍처는 다음과 같다.

 

 

배포는 다음과 같이 하면 된다.

$ kubectl create ns bookinfo
$ kubectl label ns bookinfo istio.io/rev=1-23-4
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo

 

배포를 완료하고 포트포워드 명령어를 사용하여 localhost:9080에 접속해보자.

$ kubectl port-forward svc/productpage 9080:9080

 

여기서 주목해볼 점은 여러번 접속하면 리뷰 화면이 랜덤으로 바뀐다. 이렇게 된 이유는 reviews 라는 이름의 서비스가 있는데, 이 서비스가 reviews-v1, reviews-v2, reviews-v3 파드를 모두 디스커버리하고 있기 떄문이다.

  • v1인 경우 별점이 없다.
  • v2인 경우 별점이 생긴다.
  • v3인 경우 별점 색이 추가되었다.

 

VirtualService

VirtualServiec는 istio 트래픽 라우팅 기능의 핵심 빌딩 블록이다. VirtualService를 사용하면 istio 서비스 메쉬 내에서 서비스로 요청을 라우팅하는 방법을 구성할 수 있다. 각 VirtualService는 순서대로 평가되는 일련의 라우팅 규칙으로 구성되어 istio가 VirtualService에 대한 각 요청을 메쉬 내의 특정 실제 대상과 일치시킬 수 있다.

 

VirtualService에서는 크게 요청 호스트와, 라우팅 룰라우팅 룰 적용 대상 을 설정하여 특정 대상에서 특정 호스트로 요청할 때 어떤 방식으로 트래픽을 라우팅할지 지정할 수 있다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - bookinfo.com
  gateways:
  - mesh
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    - destination:
        host: reviews # Kubernetes Service DNS
  - match:
    - uri:
        prefix: /ratings
    route:
    - destination:
        host: ratings # Kubernetes Service DNS

 

hosts : 요청 호스트

 

hosts 필드는 VirtualService의 서비스 호스트 목록이다. mesh에서 해당 호스트로 요청을 하면 VirtualService에 설정한 라우팅룰대로 트래픽이 제어가 된다.

 

gateways : 라우팅 룰 적용 대상

 

gateways는 VirtualService에 정의한 라우팅 룰을 실제로 적용할 대상을 설정할 수 있다. 라우팅 룰 적용할 대상은 Gateway 라는 커스텀 리소스로 설정할 수 있으며, 값이 주어지지 않는 경우에는 기본적으로 mesh 라는 값이 할당된다. mesh Gateway로 지정이 되면 모든 사이드카에 VirtualService 라우팅룰이 적용된다.

 

http (tcp, tls) : 라우팅 룰

 

http (tcp, tls) 필드는 라우팅 룰을 지정하는 필드이다. 위의 예시에서는 메쉬 내 모든 서비스에서 bookinfo.com 으로 요청할 때, /reviews 패스 하위로 요청하는 경우에는 reviews 서비스로, /ratings 패스 하위로 요청하는 경우에는 ratings 서비스로 요청하게 된다. 위의 VirtualService를 적용시키면 아래와 같은 형태로 라우팅 룰이 추가된다.

 

DestinationRule

 

VirtualService와 함께 DestinationRule은 istio 트래픽 라우팅 기능의 핵심 부분이다. VirtualService를 호스트로 요청할 때 목적지로 라우팅하는 방법을 작성하는 것이라면, DestinationRule은 목적지에 대한 세부 사항을 작성하는 것으로 생각하면 된다. DestinationRule은 VirtualService 라우팅 룰이 평가된 후에 적용이 되며, 트래픽의 실제 목적지에 적용된다.

 

특히, 서비스의 하위 집합 (subset)을 지정하기 위해 DestinationRule을 사용한다. 예를 들어, 버전별로 모든 지정된 서비스 인스턴스를 그룹화할 수 있다. DestinationRule으로 생성한 서브셋을 VirtualService의 라우팅 룰을 설정할 때 사용할 수 있다.

 

DestinationRule을 사용하면 서비스나 서비스의 서브셋을 호출할 떄 트래픽 정책(로드밸런싱 모델, TLS 모드, 서킷 브레이커 등) 을 커스터마이징 할 수 있다.

 

서브셋 지정 (A/B Test 예제)

예를 들어, 사용자 이름이 [a-m] 으로 시작하는 경우, reviews API는 v2으로, 나머지는 v1으로 라우팅하여 A/B 테스트를 하고싶다고 가정하자.

 

VirtualService와 DestinationRule을 사용하면 쉽게 A/B 테스트를 진행할 수 있다. 사용자 이름이 end-user 헤드로 전달된다고 가정하면 일단 VirtualService는 다음과 같이 선언하면 된다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          regex: "[a-n]+.*"
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1
  • end-user 헤더가 a-n으로 시작하는 경우, reviews 서비스의 v2 서브셋으로 전달한다.
  • match가 없는 라우팅룰 설정은 기본 라우트로, a-n으로 시작하지 않는 경우에는 reviews 서비스의 v1 서브셋으로 전달한다.

 

하지만 VirtualService를 생성하고나서 상품페이지로 접속하면 에러 화면이 나온다. VirtualService에서 설정한 서브셋을 아직 지정해주지 않아서 어디로 라우팅할지 모르기 때문에 에러가 발생한다.

 

 

VirtualService에서 설정한 서브셋을 지정해주기 위해 DestinationRule을 적용하자. (그래서 원래는 DestinationRule 부터 작성하는게 맞다.)

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews-ab-test
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
  • host: 서비스 레지스트리의 서비스 이름이다. 서비스 이름은 쿠버네티스 서비스 이름 (FQDN) 또는 ServiceEntry 에 선언된 호스트를 지정할 수 있다.
  • subset: 해당 호스트의 서브셋을 지정할 수 있다.
  • subset[].labels: 레이블을 기반으로 서브셋을 나눌 수 있다. 만약 host 가 쿠버네티스 서비스 이름 또는 FQDN이라면 여기서의 레이블은 서비스가 디스커버리하고 있는 파드들의 레이블을 사용하여 서브셋을 나눈다.

 

 

 

DestinationRule을 적용한 후 Sign in 버튼을 눌러서 아무 유저이름과 비밀번호를 입력하면 로그인이 되는데 두가지 경우 모두 로그인하여 비교해보면 하나는 v1, 나머지 하나는 별점이 보이는 v2로만 보일 것이다.

 

서브셋 지정 (Blue-Green)

 

VirtualService와 DestinationRule을 적절히 잘 사용하면 블루그린 배포도 가능하다.

Blue-Green 배포를 간단히 말하자면 다음 과정을 거친다.

  1. 두 가지 버전 (기존 버전, 신규 버전)을 각각 blue, green (순서는 무관) 으로 하고,두 버전을 모두 일단 배포를 한다. (기존 버전 남긴 채 신규 버전 배포)
  2. 기존 버전에만 트래픽을 100% 주입한 다음 신규 버전이 모두 준비상태가 될 때까지 기다린다.
  3. 신규 버전이 모두 준비 상태가 되면 신규 버전으로 모두 트래픽을 향하게 한다. (특정 비율로 점진적으로 트래픽을 옮겨가도 상관 없음.)
  4. 신규 버전으로 모두 트래픽이 향하고 아무 문제가 없다면 기존 버전을 내리고, 신규 버전에 버그가 발생하면 재빠르게 기존 버전에만 트래픽이 향하도록 한다.

 

블루그린의 장점은 롤백이 빠르며, 특정비율로 라우팅을 분배하여 점진적으로 트래픽을 옮길 수 있어서 신규 버전의 버그가 있어도 롤링업데이트보다 덜 취약하다. 대신 기존버전의 레플리카가 사라지지 않고 신규 버전을 추가로 배포하기 때문에, 배포 시점에 사용되는 리소스가 커진다는 단점이 있다.

 

위와 같은 그림처럼 블루그린 배포를 한다면 일단 VirtualService와 DestinationRule을 아래와 같이 추가한다. (기존에 설정해둔 것은 일단 지운다.)

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - weight: 100 # weight를 조절
      destination:
        host: reviews
        subset: blue
    - weight: 0 # weight를 조절
      destination:
        host: reviews
        subset: green
  • Subset 별로 destination을 다르게 가져가고 있다.
  • 한 라우팅 룰에 destination을 여러개 등록할 수 있으며, 각 destination마다 비중을 가져갈 수 있다. weight는 0이상의 정수로 설정 가능하며 실제 비중은 destination.weight / (모든 destination의 weight 합) 으로 계산된다.

 

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: blue
    labels:
      version: v1
  - name: green
    labels:
      version: v2

 

서브셋 지정 (Canary)

Canary 배포는 블루그린과 유사한데, 블루그린과 차이점은 블루그린은 기존 버전과 신규 버전을 같은 (비슷한) 리소스 양만큼 사용하여 미리 띄워놓는 반면, Canary는 Canary 레플리카와 일반 레플리카를 분리한 다음, Canary 레플리카를 매우 작게 준 다음 Canary 레플리카에 트래픽을 적은 비율로 줘서 신규 버전에 이상이 없는지 검증한 다음, 일반 레플리카 버전을 롤링 업데이트하고 Canary 레플리카를 지우는 방식으로 배포가 진행된다.

 

Canary 배포는 다음과 같이 진행된다.

  1. 기존 버전의 레플리카를 남겨둔 채 Canary 레플리카를 적은 개수로 생성한다. (임시)
  2. Canary 레플리카가 준비상태가 되면 적은 비율의 트래픽을 Canary 레플리카로 전달한다.
  3. Canary 버전으로 트래픽이 향한 후 아무 문제가 없다면 기존 버전을 롤링 업그레이드 하고 Canary를 지운다. 문제가 발생한다면 Canary만 지우거나 트래픽을 보내지 않도록 하면 된다.

 

Canary의 장점은 블루그린과 마찬가지로 롤링 업데이트에 비해 신규 버전의 버그에 덜 취약하며 블루그린 보다는 리소스를 아낄 수 있다는 장점이 있다. 하지만 점진적으로 트래픽을 조절하기에는 Canary의 리소스가 조금 부족하다. 물론 점진적 트래픽을 조절하기 위해서 Canary의 레플리카를 올리는 방법이 있긴 하지만 블루그린과 약간 유사하다.

 

그래서 istio를 사용하여 Canary 배포를 구성하는 방식이 블루그린과 아주 유사하다. 대신 신규 버전의 비중과 신규 버전의 레플리카 수와 비율 조정에 대한 시나리오가 조금씩 다르다. 그렇기 때문에 블루그린과 Canary 배포의 개념만 알면 상황에 맞게 적절히 블루그린과 Canary를 같이 사용할 수도 있을 것이다.

 

Canary 는 다음과 같이 구성하면 된다.

 

Canary 배포 전

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: main
    labels:
      group: main
  - name: canary
    labels:
      group: canary

 

  • 블루그린과 다르게, main, canary라는 서브셋을 사용하고 있으며, 각각의 Deployment에 의해 배포되는 파드는 group 레이블로 구분된다. (main | canary)
  • 이 값은 Canary 배포 시에는 변하지 않으며, Canary 검증이 완료된 후 main 그룹의 레플리카를 신규 버전으로 롤링업데이트 하는 형식으로 배포를 하면 된다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - weight: 1000 # main
      destination:
        host: reviews
        subset: main
    - weight: 0 # canary
      destination:
        host: reviews
        subset: canary
  • Canary 배포 전이기 때문에 canary 서브셋은 weight가 0이다.

 

Canary 배포 후

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - weight: 1000 # main
      destination:
        host: reviews
        subset: main
    - weight: 1 # canary
      destination:
        host: reviews
        subset: canary
  • Canary 레플리카가 모두 준비 상태라면 canary 서브셋의 weight를 0이 아닌 값으로 수정하자.

 

신규 버전으로 완전 배포

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - weight: 1000 # main
      destination:
        host: reviews
        subset: main
    - weight: 0 # canary
      destination:
        host: reviews
        subset: canary
  • main 서브셋 모두 신규 버전으로 배포되고 준비가 되었다면 canary의 비중을 전부 없애고 canary 레플리카를 모두 제거하면 canary 배포 완료

 

 

로드밸런싱 옵션

기본적으로 istio는 최소 요청 부하 분산 정책을 사용하며 요청 수가 가장 적은 인스턴스에 분산된다. istio는 특정 서비스나 서브셋 단위로 여러가지 로드밸런싱 옵션을 지정할 수 있다. 지원하는 로드밸런싱 옵션은 다음과 같다.

  • Random: 무작위로 인스턴스를 선택
  • Weighted: 특정 비율에 따라 요청이 풀의 인스턴스로 전달된다.
  • Round-robin: 요청이 순차적으로 인스턴스에 전달된다.
  • Consistent hash: HTTP 헤더, 쿠키 및 다른 프로퍼티 기반의 soft session affinity를 제공한다.
  • Ring hash: Ketama 알고리즘을 사용하여 업스트림 호스트에 대한 일관된 해싱을 구현한다.
  • Maglev: Maglev 논문에 설명한 대로 업스트림 호스트에 대한 일관된 해싱을 구현한다.

 

로드밸런싱 옵션을 지정하는 방식은 다음과 같다.

 

 

Round-robin

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: ratings
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN

 

 

 

Cookie 기반의 consistent hash

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: bookinfo-ratings
spec:
  host: ratings.prod.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpCookie:
          name: user
          ttl: 0s

 

 

마무리

이번장에서는 VirtualService와 DestinationRule을 사용하여 mesh 내의 트래픽 라우팅 규칙을 정의하는 방법을 알아보았다. 다음 장에는 외부에서 mesh로 들어오는 트래픽을 관리하는 방식에 대해 알아볼 것이다. (Gateway)

728x90

'DevOps > Istio' 카테고리의 다른 글

istio traffic 관리 (2) [Gateway]  (0) 2025.01.13
istio 소개 및 설치  (0) 2025.01.12

댓글