Ssoon

[3주차] 트래픽 제어(세밀한 트래픽 라우팅) : Istio로 라우팅 요청 본문

Istio Hands-on Study [1기]

[3주차] 트래픽 제어(세밀한 트래픽 라우팅) : Istio로 라우팅 요청

구구달스 2025. 4. 20. 21:08
CloudNet@ 가시다님이 진행하는 Istio Hands-on Study [1기]

🚀Istio로 Catalog Service 배포하기:
초보자 가이드 


🧹 작업 환경 정리하기

  • 기존에 남아 있는 리소스(deployment, service, gateway, virtualservice, destinationrule)를 모두 삭제합니다:
kubectl delete deployment,svc,gateway,virtualservice,destinationrule --all -n istioinaction

🚀 Catalog Service v1 배포하기

  • catalog service의 v1 버전을 배포합니다! 이 서비스는 Kubernetes 클러스터 안에서 동작하며, 외부에서 접근할 수 있도록 설정합니다.
  • 다음 명령어를 실행해 catalog service를 배포합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
serviceaccount/catalog created
service/catalog created
deployment.apps/catalog created
  • 다음과 같은 리소스를 생성합니다:
    • serviceaccount/catalog
    • service/catalog
    • deployment.extensions/catalog
  • 다음 명령어로 pod의 상태를 실시간으로 확인합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get pod -n istioinaction -owide
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE                  NOMINATED NODE   READINESS GATES
catalog-6cf4b97d-dpflk   2/2     Running   0          56s   10.10.0.12   myk8s-control-plane   <none>           <none>
  • 도메인 질의를 위한 임시 설정  
    'catalog.istioinaction.io' 도메인 이름을 로컬 컴퓨터(127.0.0.1)로 연결
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ echo "127.0.0.1       catalog.istioinaction.io" | sudo tee -a /etc/hosts
[sudo] password for ssoon:
127.0.0.1       catalog.istioinaction.io
  • 클러스터 내부에서 catalog service가 제대로 동작하는지 확인합니다.
    netshoot내부에서 catalog 접속 확인
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl exec -it netshoot -- curl -s http://catalog.istioinaction/items | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
  {
    "id": 2,
    "color": "cyan",
    "department": "Clothing",
    "name": "Atlas Shirt",
    "price": "127.00"
  },
  {
    "id": 3,
    "color": "teal",
    "department": "Clothing",
    "name": "Small Metal Shoes",
    "price": "232.00"
  },
  {
    "id": 4,
    "color": "red",
    "department": "Watches",
    "name": "Red Dragon Watch",
    "price": "232.00"
  }
]

 

catalog service v1을 배포한 후, pod 상태를 확인하고 클러스터 내부에서 서비스 접근을 테스트합니다.


🌐 Catalog Service를 외부에 공개하기: Istio Gateway 설정

  • 외부 클라이언트가 이 서비스를 사용할 수 있도록 Istio Gateway를 설정해볼게요. Gateway는 외부 트래픽을 클러스터 내부로 연결해주는 문지기 같은 역할을 합니다!
  • 다음은 Istio Gateway 리소스의 설정입니다.
    이 설정은 catalog.istioinaction.io 도메인을 통해 HTTP 포트 80번으로 들어오는 트래픽을 처리하도록 정의합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: catalog-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "catalog.istioinaction.io"
  • catalog-gateway라는 이름의 Gateway 리소스를 생성합니다. 이제 외부 트래픽을 받을 준비가 됐습니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-gateway.yaml -n istioinaction
gateway.networking.istio.io/catalog-gateway created

Istio Gateway를 설정해 외부 트래픽을 클러스터 내부로 연결합니다.
catalog.istioinaction.io 도메인을 통해 HTTP 요청을 받을 수 있습니다!


🔗 트래픽 라우팅 설정: VirtualService 생성

  • 트래픽이 catalog service로 정확히 라우팅되도록 VirtualService 만들어야 합니다.
    VirtualService는 Gateway를 통해 들어온 요청을 특정 서비스로 연결해주는 역할을 해요.
  • 다음은 VirtualService 설정입니다:
    이 설정은 catalog.istioinaction.io로 들어오는 HTTP 요청을 catalog 서비스로 라우팅하도록 정의합니다. 
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog-vs-from-gw
spec:
  hosts:
  - "catalog.istioinaction.io"
  gateways:
  - catalog-gateway
  http:
  - route:
    - destination:
        host: catalog
  • VirtualService를 적용합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-vs.yaml -n istioinaction
virtualservice.networking.istio.io/catalog-vs-from-gw created
  • 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get gw,vs -n istioinaction
NAME                                          AGE
gateway.networking.istio.io/catalog-gateway   2m41s

NAME                                                    GATEWAYS              HOSTS                          AGE
virtualservice.networking.istio.io/catalog-vs-from-gw   ["catalog-gateway"]   ["catalog.istioinaction.io"]   43s
  • istio-ingressgateway Service(NodePort)에 포트 정보를  확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get svc -n istio-system istio-ingressgateway -o jsonpath="{.spec.ports}" | jq
[
  {
    "name": "status-port",
    "nodePort": 32568,
    "port": 15021,
    "protocol": "TCP",
    "targetPort": 15021
  },
  {
    "name": "http2",
    "nodePort": 30000,
    "port": 80,
    "protocol": "TCP",
    "targetPort": 8080
  },
  {
    "name": "https",
    "nodePort": 30005,
    "port": 443,
    "protocol": "TCP",
    "targetPort": 8443
  }
]
  • 이제 모든 설정이 완료됐습니다! Istio ingress gateway를 통해 외부에서 catalog service에 접근해볼게요.
    호스트에서 NodePort(Service)로 접속을 확인합니다.
    Gateway를 통해 catalog service의 /items 엔드포인트를 호출합니다.
C:\Users\ssoon>curl -v -H "Host: catalog.istioinaction.io" http://localhost:30000
* Host localhost:30000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:30000...
*   Trying 127.0.0.1:30000...
* Connected to localhost (127.0.0.1) port 30000
* using HTTP/1.x
> GET / HTTP/1.1
> Host: catalog.istioinaction.io
> User-Agent: curl/8.11.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
...
* Connection #0 to host localhost left intact

 

VirtualService를 설정해 Gateway로 들어온 트래픽을 catalog service로 라우팅합니다.
외부에서 curl 명령어로 테스트하여 서비스가 잘 동작하는지 확인합니다.


📌핵심 요약

  1. 작업 환경 정리: istioinaction namespace로 전환하고 기존 리소스를 삭제해 깨끗한 환경을 준비
  2. Catalog Service 배포: catalog service v1을 배포하고, pod 상태를 확인한 뒤 클러스터 내부에서 동작을 테스트
  3. Gateway 설정: Istio Gateway를 만들어 외부 트래픽을 catalog.istioinaction.io 도메인으로 받을 수 있게 설정.
  4. VirtualService 설정: VirtualService를 통해 Gateway로 들어온 트래픽을 catalog service로 라우팅
  5. 외부 접근 테스트: curl 명령어로 외부에서 서비스에 접근해 정상적으로 응답하는지 확인.

🚀Istio로 Catalog Service v2 배포하고
트래픽 확인하기


🛠️ Catalog Service v2 배포하기

  • Istio의 트래픽 제어 기능을 확인하기 위해, 먼저 catalog service의 v2 버전을 배포합니다. v2는 v1와 다른 응답을 반환해서 트래픽이 어떻게 분배되는지 확인할 수 있습니다.
  • 다음 명령어를 실행해 catalog service v2를 배포합니다: catalog-v2라는 이름의 새로운 deployment를 생성해요. 배포가 완료되면 클러스터에 v1과 v2가 모두 존재하게 됩니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f services/catalog/kubernetes/catalog-deployment-v2.yaml -n istioinaction
deployment.apps/catalog-v2 created

 

  • 클러스터에 어떤 pod이 있는지 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get deploy -n istioinaction --show-labels
NAME         READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
catalog      1/1     1            1           20m   app=catalog,version=v1
catalog-v2   1/1     1            1           65s   app=catalog,version=v2

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get pod -n istioinaction -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP           NODE                  NOMINATED NODE   READINESS GATES
catalog-6cf4b97d-dpflk        2/2     Running   0          23m     10.10.0.12   myk8s-control-plane   <none>           <none>
catalog-v2-6df885b555-nw8w7   2/2     Running   0          3m16s   10.10.0.13   myk8s-control-plane   <none>           <none>

 

catalog service v2를 배포해 v1과 함께 클러스터에서 실행되도록 설정합니다.


🔍 Catalog Service v1과 v2의 응답 비교하기

  • 이제 catalog service에 여러 번 요청을 보내서 v1과 v2의 응답이 어떻게 다른지 확인해볼게요. Istio는 기본적으로 트래픽을 pod 간에 분배하기 때문에, v1과 v2 응답이 섞여 출력됩니다.
  • 다음 명령어를 실행해 catalog service의 /items 엔드포인트에 10번 요청을 보냅니다:
    • 응답을 보면 v2 응답에는 imageUrl 필드가 포함되어 있고, v1 응답에는 이 필드가 없습니다.
      여러 번 요청을 보내면 v1과 v2 응답이 무작위로 섞여 나오는 걸 볼 수 있습니다. 이는 Istio가 트래픽을 두 pod에 자동으로 분배하기 때문이에요.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for i in {1..10}; do curl -s http://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; done
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
...
]

[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00",
    "imageUrl": "http://lorempixel.com/640/480"
  },
 ...

catalog service에 여러 번 요청을 보내 v1과 v2의 응답을 비교합니다.
v2 응답에는 imageUrl 필드가 추가되어 있어 두 버전의 차이를 확인할 수 있습니다!


📌핵심 요약

  1. Catalog Service v2 배포: catalog-deployment-v2.yaml 파일을 적용해 v2 버전을 배포하고, kubectl get pod로 v1과 v2 pod이 정상 실행 중인지 확인
  2. 응답 비교: Istio ingress gateway를 통해 여러 번 요청을 보내 v1과 v2의 응답 차이를 확인. v2는 imageUrl 필드가 추가된 점이 특징
  3. 트래픽 분배 관찰: Istio가 트래픽을 v1과 v2 pod에 자동으로 분배해 응답이 섞여 나오는 걸 확인

🚀 Istio로 Catalog Service v1으로
모든 트래픽 라우팅하기 


🗂️ DestinationRule로 v1과 v2 구분하기

  • Istio가 catalog service의 v1과 v2를 구분할 수 있도록, 먼저 DestinationRule을 설정합니다.
    이 리소스는 서비스의 서로 다른 버전을 subset으로 정의해서 Istio가 트래픽을 올바르게 라우팅할 수 있게 도와줍니다.
  • catalog service의 v1과 v2는 Kubernetes Deployment에서 각각 app: catalog, version: v1app: catalog, version: v2라는 레이블로 구분돼 있습니다.. 이를 기반으로 DestinationRule을 아래와 같이 정의합니다:
    이 설정은 catalog 서비스의 두 버전을 version-v1과 version-v2라는 이름의 subset으로 나눠 정의해요. 
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-dest-rule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: catalog
spec:
  host: catalog.istioinaction.svc.cluster.local
  subsets:
  - name: version-v1
    labels:
      version: v1
  - name: version-v2
    labels:
      version: v2
  • DestinationRule을 적용합니다. 이로써 Istio는 v1과 v2를 명확히 구분할 준비가 되었습니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-dest-rule.yaml -n istioinaction
destinationrule.networking.istio.io/catalog created
  • Istio의 DestinationRule 리소스를 조회합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get destinationrule -n istioinaction
NAME      HOST                                      AGE
catalog   catalog.istioinaction.svc.cluster.local   68s
  • istio-ingressgateway의 Envoy 프록시가 인식하고 있는 catalog.istioinaction.svc.cluster.local 서비스에 대한 클러스터 설정 정보를 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local
SERVICE FQDN                                PORT     SUBSET         DIRECTION     TYPE     DESTINATION RULE
catalog.istioinaction.svc.cluster.local     80       -              outbound      EDS      catalog.istioinaction
catalog.istioinaction.svc.cluster.local     80       version-v1     outbound      EDS      catalog.istioinaction
catalog.istioinaction.svc.cluster.local     80       version-v2     outbound      EDS      catalog.istioinaction

 

DestinationRule을 사용해 catalog service의 v1과 v2를 각각 version-v1과 version-v2 subset으로 정의합니다.
이렇게 하면 Istio가 버전을 구분해 트래픽을 라우팅할 수 있습니다!


🔄 VirtualService로 모든 트래픽을 v1으로 라우팅하기

  • 이제 Istio가 v1과 v2를 구분할 수 있으니, 모든 트래픽을 catalog service의 v1으로 라우팅하도록 VirtualService를 업데이트합니다. 이를 통해 v2로 가는 트래픽을 차단하고 v1만 응답하도록 설정할 수 있습니다.
  • 아래는 업데이트된 VirtualService 설정입니다:
    catalog.istioinaction.io로 들어오는 모든 HTTP 요청을 catalog 서비스의 version-v1 subset(즉, v1)으로 라우팅하도록 지정합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-vs-v1.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog-vs-from-gw
spec:
  hosts:
  - "catalog.istioinaction.io" #VirtualService는 'catalog.istioinaction.io' 도메인으로 들어오는 트래픽에 적용
  gateways:
  - catalog-gateway
  http:
  - route: #라우팅 동작을 정의
    - destination: #트래픽이 전달될 목적지를 지정
        host: catalog #목적지 서비스의 이름이 'catalog'임
        subset: version-v1 #해당 서비스의 특정 서브셋(subset)인 'version-v1'으로 트래픽을 보냅니다.
  • 이제 이 VirtualService를 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-vs-v1.yaml -n istioinaction
virtualservice.networking.istio.io/catalog-vs-from-gw configured
  • 모든 트래픽이 v1으로 라우팅되도록 설정되었습니다.

VirtualService를 업데이트해 모든 트래픽을 version-v1 subset으로 라우팅합니다.
이렇게 하면 catalog service의 v1만 응답하게 됩니다!


✅ v1 응답 확인하기

  • catalog service에 요청을 보내 실제로 v1 응답만 오는지 확인합니다.
    다음 명령어를 실행해 10번 요청을 보냅니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for i in {1..10}; do curl -s http://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; done
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
  {
...
  • 이제 모든 응답이 v1에서 오기 때문에, 이전에 v2 응답에서 보였던 imageUrl 필드가 없는 결과만 나타납니다.
    이는 Istio가 트래픽을 version-v1 subset으로 정확히 라우팅하고 있다는 뜻입니다. 

VirtualService 적용 후 요청을 보내 v1 응답만 오는지 확인합니다.
모든 트래픽이 v1으로 라우팅되면 imageUrl 필드가 없는 응답만 나타납니다!


📌핵심 요약

  • DestinationRule 설정: DestinationRule을 만들어 catalog service의 v1과 v2를 version-v1과 version-v2 subset으로 정의
  • VirtualService 업데이트: VirtualService를 수정해 catalog.istioinaction.io로 들어오는 모든 트래픽을 version-v1 subset으로 라우팅하도록 설정
  • 응답 테스트: 여러 번 요청을 보내 모든 응답이 v1에서 오는지 확인 > imageUrl 필드가 없는 응답만 나타나 성공적으로 v1 라우팅 완료

🚀Istio로 특정 요청을
Catalog Service v2로 라우팅하기 


🔧 VirtualService로 특정 요청 라우팅 설정하기

  • Istio를 사용하면 HTTP 헤더 같은 조건을 기반으로 트래픽을 원하는 서비스 버전으로 보낼 수 있습니다.
    x-istio-cohort: internal 헤더가 포함된 요청을 catalog service의 v2 버전으로 라우팅하도록 설정합니다. 나머지 요청은 v1으로 가도록 유지합니다.
    아래는 이를 구현한 VirtualService 설정입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-vs-v2-request.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog-vs-from-gw
spec:
  hosts:
  - "catalog.istioinaction.io"
  gateways:
  - catalog-gateway
  http: #HTTP 트래픽에 대한 라우팅 규칙을 정의
  - match: #첫 번째 라우팅 규칙이 적용될 조건을 정의
    - headers: #HTTP 헤더에 기반한 매칭 조건을 지정
        x-istio-cohort: #매칭할 HTTP 헤더의 이름이 'x-istio-cohort'임을 나타냄
          exact: "internal" #'x-istio-cohort' 헤더의 값이 정확히 "internal"일 때 이 규칙이 적용됨
    route:
    - destination:
        host: catalog
        subset: version-v2
  - route:
    - destination:
        host: catalog
        subset: version-v1
  • 이 설정을 살펴보면:
    • match 블록에서 x-istio-cohort 헤더 값이 정확히 internal인 요청을 찾습니다.
    • 일치하는 요청은 version-v2 subset(즉, v2)으로 라우팅됩니다.
    • 그 외의 모든 요청은 version-v1 subset(즉, v1)으로 라우팅됩니다.
  • VirtualService를 적용합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-vs-v2-request.yaml -n istioinaction
virtualservice.networking.istio.io/catalog-vs-from-gw configured
  • 특정 헤더가 있는 요청만 v2로 가도록 설정됐습니다!

VirtualService를 업데이트해 x-istio-cohort: internal 헤더가 있는 요청을 v2로,
나머지 요청을 v1으로 라우팅하도록 설정합니다.
이를 통해 트래픽을 세밀하게 제어할 수 있습니다!


🕵️‍♂️ 특정 요청의 v2 응답 확인하기

  • catalog service에 요청을 보내 실제로 트래픽이 올바르게 라우팅되는지 확인합니다.
    먼저 일반 요청(헤더 없이)을 보내서 v1 응답을 확인합니다:
    • 이 요청은 x-istio-cohort 헤더가 없으므로 v1으로 라우팅됩니다. 응답은 imageUrl 필드가 없는 v1의 결과 입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for i in {1..5}; do curl -s htt
p://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; done
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
  • 이제 x-istio-cohort: internal 헤더를 포함한 요청을 보내 v2 응답을 확인합니다.
    • 이 요청은 v2로 라우팅되며, imageUrl 필드가 포함된 응답이 나옵니다,
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl http://catalog.istioinaction.io:30000/items -H "x-istio-cohort: internal"
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00",
    "imageUrl": "http://lorempixel.com/640/480"
  },

x-istio-cohort: internal 헤더가 있는 요청은 v2로, 없는 요청은 v1으로 라우팅됩니다.
curl로 테스트해 v2 응답에 imageUrl 필드가 포함된 걸 확인합니다!


📌핵심 요약

  • VirtualService 설정: VirtualService를 업데이트해 x-istio-cohort: internal 헤더가 있는 요청을 version-v2 subset으로, 나머지를 version-v1 subset으로 라우팅하도록 설정
  • 라우팅 테스트: 헤더 없이 요청하면 v1 응답(imageUrl 필드 없음)이, x-istio-cohort: internal 헤더를 포함하면 v2 응답(imageUrl 필드 포함)이 나오는 걸 확인

🌐 Istio로 Call Graph 내 특정 요청 라우팅하기 

  • Istio의 트래픽 관리 기능을 활용해 서비스 간 호출이 이루어지는 call graph 내부에서 특정 요청세밀하게 라우팅하는 방법
  • 지금까지는 Gateway에서 트래픽을 제어했지만, 이번에는 서비스 간 호출에서도 동일한 라우팅 규칙을 적용

🧹 기존 Istio 리소스 정리하기

  • 새로운 실습을 시작하기 전에 istioinaction namespace에 있는 기존 Istio 리소스를 모두 삭제 합니다. 이렇게 하면 이전 설정이 남아 있어 발생할 수 있는 혼란을 방지할 수 있죠.
  • 다음 명령어를 실행해 모든 Gateway, VirtualService, DestinationRule 리소스를 삭제합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl delete gateway,virtualservice,destinationrule --all -n istioinaction
gateway.networking.istio.io "catalog-gateway" deleted
virtualservice.networking.istio.io "catalog-vs-from-gw" deleted
destinationrule.networking.istio.io "catalog" deleted

실습 전 kubectl delete 명령어로 기존 Istio 리소스를 삭제합니다.


🏗️ Webapp과 Catalog Service 아키텍처 복원하기

  • 이제 2장에서 다뤘던 아키텍처를 복원합니.
    이 아키텍처는 webapp 서비스가 catalog 서비스를 호출하는 구조로, Istio Gateway를 통해 외부 트래픽이 webapp으로 들어오게 설정할게요.
  • 먼저 webapp 서비스와 관련 리소스를 배포합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f services/webapp/kubernetes/webapp.yaml
serviceaccount/webapp created
service/webapp created
deployment.apps/webapp created
  • 이 명령어는 다음 리소스를 생성합니다:
    • serviceaccount/webapp
    • service/webapp
    • deployment.extensions/webapp
  • 다음으로, Istio GatewayVirtualService를 설정해 외부 트래픽이 webapp 서비스로 라우팅되도록 합니다:
    • coolstore-gateway와 webapp-virtualservice를 생성합니다.
      이제 트래픽이 Gateway를 통해 webapp으로 들어올 준비가 됐습니다!
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat services/webapp/istio/webapp-catalog-gw-vs.yaml
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: webapp-virtualservice
spec:
  hosts:
  - "webapp.istioinaction.io"
  gateways:
  - coolstore-gateway
  http:
  - route:
    - destination:
        host: webapp
        port:
          number: 80

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction
gateway.networking.istio.io/coolstore-gateway created
virtualservice.networking.istio.io/webapp-virtualservice created
  • 정상적으로 실행되는지 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get gw,vs -n istioinaction
NAME                                            AGE
gateway.networking.istio.io/coolstore-gateway   39s

NAME                                                       GATEWAYS                HOSTS                         AGE
virtualservice.networking.istio.io/webapp-virtualservice   ["coolstore-gateway"]   ["webapp.istioinaction.io"]   39s
  • 도메인 질의를 위한 임시 설정
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ echo "127.0.0.1       webapp.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 3
[sudo] password for ssoon:
127.0.0.1       webapp.istioinaction.io
ff02::2 ip6-allrouters
127.0.0.1       catalog.istioinaction.io
127.0.0.1       webapp.istioinaction.io
  • 이제 webapp 서비스의 /api/catalog 엔드포인트를 호출catalog 서비스의 응답을 확인합니다.
    • 이 요청은 webapp을 통해 catalog 서비스로 전달되며, catalog의 v1과 v2 응답이 섞여 나타납니다. 이는 Istio가 기본적으로 트래픽을 두 버전의 pod에 분배하기 때문입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00",
    "imageUrl": "http://lorempixel.com/640/480"
  },
 ...
 (⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },

webapp과 catalog 서비스를 배포하고 Istio Gateway를 설정해 트래픽이 webapp으로 라우팅합니다.
curl로 테스트하면 v1과 v2 응답이 섞여 나옵니다!


🔄 모든 트래픽을 Catalog v1으로 라우팅하기

  • 이제 webapp이 호출하는 catalog 서비스의 트래픽을 모두 v1으로 라우팅하도록 설정해볼게요. 이를 위해 DestinationRuleVirtualService를 만들어 catalog 서비스의 버전을 관리합니다.
  • 먼저 DestinationRule을 적용해 catalog 서비스의 v1과 v2를 subset으로 정의합니다: destinationrule.networking.istio.io/catalog를 생성해 v1과 v2를 version-v1과 version-v2 subset으로 구분
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-dest-rule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: catalog
spec:
  host: catalog.istioinaction.svc.cluster.local
  subsets:
  - name: version-v1
    labels:
      version: v1
  - name: version-v2
    labels:
      version: v2
      
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-dest-rule.yaml -n istioinaction
destinationrule.networking.istio.io/catalog created
  • 다음으로, VirtualService를 만들어 모든 트래픽을 catalog의 v1으로 라우팅하도록 설정합니다:  virtualservice.networking.istio.io/catalog를 생성하며, catalog 서비스로 가는 모든 내부 요청을 version-v1 subset으로 보냅니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-vs-v1-mesh.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog
spec:
  hosts:
  - catalog
  gateways:
    - mesh
  http:
  - route:
    - destination:
        host: catalog
        subset: version-v1

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-vs-v1-mesh.yaml -n istioinaction
virtualservice.networking.istio.io/catalog created
  • 이제 다시 webapp 엔드포인트를 호출합니다.
    • 이제 catalog의 v1 응답만 나타납니다(예: imageUrl 필드가 없는 응답). 이는 트래픽이 모두 v1으로 라우팅되고 있음을 보여줍니다!
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
  ...
  (⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },

DestinationRule과 VirtualService를 설정해 catalog 서비스의 모든 내부 트래픽을 v1으로 라우팅합니다.
webapp 호출로 v1 응답만 나오는지 확인합니다!


🎯 특정 요청을 Catalog v2로 라우팅하기

  • 마지막으로, x-istio-cohort: internal 헤더가 포함된 요청만 catalog 서비스의 v2로 라우팅하도록 설정합니다.
    이는 call graph 내부에서도 세밀한 트래픽 제어가 가능하다는 걸 보여줍니다.
  • 아래는 이를 구현한 VirtualService 설정입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch5/catalog-vs-v2-request-mesh.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog
spec:
  hosts:
  - catalog
  gateways: #VirtualService가 연결될 게이트웨이를 지정
    - mesh #서비스 메시 내부의 모든 트래픽에 이 규칙을 적용
           #외부에서 들어오는 트래픽이 아니라 메시 내부 서비스 간 통신에 적용
  http:
  - match:
    - headers:
        x-istio-cohort:
          exact: "internal"
    route:
    - destination:
        host: catalog
        subset: version-v2
  - route:
    - destination:
        host: catalog
        subset: version-v1
  • 이 설정은:
    • gateways: mesh를 사용해 클러스터 내부의 서비스 간 호출에 적용됩니다.
    • x-istio-cohort: internal 헤더가 있는 요청은 version-v2로, 나머지는 version-v1으로 라우팅합니다.
  • 이 VirtualService를 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/catalog-vs-v2-request-mesh.yaml -n istioinaction
virtualservice.networking.istio.io/catalog configured
  • 이제 x-istio-cohort: internal 헤더를 포함webapp 엔드포인트를 호출해봅시다:
    • 이 요청은 catalog의 v2 응답을 반환하며, imageUrl 필드가 포함된 결과를 볼 수 있습니다. 
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog -H "Host: webapp.istioinaction.io" -H "x-istio-cohort: internal" | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00",
    "imageUrl": "http://lorempixel.com/640/480"
  },
 ...
  • 헤더 없이 호출하면 v1 응답이 나옵니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/catalog \
-H "Host: webapp.istioinaction.io" | jq
[
  {
    "id": 1,
    "color": "amber",
    "department": "Eyewear",
    "name": "Elinor Glasses",
    "price": "282.00"
  },
 ...

VirtualService를 설정해 x-istio-cohort: internal 헤더가 있는 내부 요청을 catalog v2로 라우팅합니다.
curl로 테스트해 v2 응답에 imageUrl 필드가 포함된 걸 확인합니다!


📌핵심 요약

  1. 리소스 정리: 기존 Istio 리소스를 삭제해 깨끗한 환경을 준비
  2. 아키텍처 복원: webapp과 catalog 서비스를 배포하고 Istio Gateway를 설정해 트래픽이 webapp으로 라우팅 => 초기 테스트에서 v1과 v2 응답이 섞여 나왔습니다.
  3. v1 라우팅: DestinationRule과 VirtualService를 설정해 catalog 서비스의 모든 내부 트래픽을 v1으로 라우팅 => v1 응답만 나오는 걸 확인
  4. 특정 요청 v2 라우팅: x-istio-cohort: internal 헤더가 있는 요청을 v2로 라우팅하도록 VirtualService를 업데이트했고, 헤더 포함 여부에 따라 v1/v2 응답이 구분됨을 테스트

 

Comments