이번 시간은 본격적인 App 배포에 앞서 Istio의 Gateway와 VirtualService에 대해서 설명하고자 한다.
Gateway
Public Cloud 환경의 K8s에서 Web Application 배포 경험이 있다면, 외부에서 접근할 수 있도록 Ingress Controller를 사용해봤을 것이다. 여러 개의 서비스를 노출해야 하는 상황에서, 모든 Service를 Loadbalancer 타입으로 생성하기엔 비용과 흩어진 Entrypoint 등의 문제가 발생한다. 이런 문제를 해결하기 위해 Ingress Controller를 최전선에 두고 Ingress Rule을 추가하여 Hostname과 Path에 따라 지정된 서비스로 Routing할 수 있었다. 다만 K8s에서 기본적으로 제공하지 않고 Third-party App(ex: ALB, Nginx, Traefik)을 통해 이러한 기능이 제공된다. Istio는 여기서 한층 더 발전해 Service Mesh의 경계에서 Inbound/Outbound 트래픽을 처리할 수 있는 Loadbalancer를 제공하며, 이를 'Gateway'라는 Istio Resource로 설정할 수 있다.
이전 시간에 'demo' profile로 istio를 설치했을 때, istio-ingressgateway와 istio-egressgateway가 생성된 것을 확인하였다. 해당 workload는 다음과 같이 Envoy 단일 컨테이너로 구성되어 있으며, L4와 L7 모두 지원한다. 이 때의 Envoy는 Sidecar Proxy가 아닌 Standalone으로 존재하며 아래와 같이 Container 갯수가 1/1로 조회되는 것을 알 수 있다.
실제로 해당 Pod 내부에는 다음과 같이 istio에서 작업한 envoy proxy 이미지(docker.io/istio/proxyv2:1.9.2)가 정의된 상태다.
Gateway를 통해 설정할 수 있는 항목은 다음과 같다.
- 외부에 공개할 Port 번호
- 사용할 프로토콜(HTTP, HTTPS, GRPC 등)
- SNI 설정
- TLS
다음은 이해를 돕기위한 Ingress Gateway의 Manifest 예시다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- kr.bookinfo.com
- "istio: ingressgateway" label을 통해 istio-ingressgateway에 설정 적용
- host
- gateway 설정이 적용될 host를 의미하며, Namespace 또는 Prefix를 포함한 DNS Name으로 정의
- host와 매칭하는 VirtualService가 반드시 존재해야 함
- port
- number: 외부에 공개할 포트 번호
- protocol
- HTTP, HTTPS, GRPC, HTTP2, MONGO, TCP, TLS 중 하나를 선택
- name: port에 배정할 이름
다만 Gateway를 정의하는 것만으로는 동작하지 않으며, 후술할 VirtualService를 따로 정의하여 L7 Path 및 Host와 프로토콜 등을 지정해야 한다.
Virtual Service
VirtualService를 간단하게 설명하자면, Envoy 프록시에게 어떤 destination으로 어떻게 트래픽을 전달할지 알려주는 역할을 수행하는 Istio 리소스다. 이를 통해 Routing 동작을 사용자가 원하는대로 customize하여 Native Kubernetes에서는 할 수 없었던 기능들을 제공한다. 대표적인 사례는 다음과 같다.
- Call 중 10%는 신규 버전으로 전달 => Canary
- 특정 User의 Call은 테스트 버전으로 route => HTTP 헤더값 기반 Routing Rule
- Request 중 5%는 HTTP 400 에러 발생 => Fault Inejction
이제 VirtualService의 Manifest는 어떻게 정의되어 있는지 확인해볼 시간이다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jackson
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v3
- host
- 일반적으로 K8s의 Service 이름 또는 FQDN을 사용하며, 그밖에 IP 주소, DNS Name, "*" prefix 역시 가능하다.
- http
- match
- Request가 정의한 조건에 맞는지 확인하고 True인 경우, Routing Rule을 적용
- 해당 예시에선 Header 속성 중 'end-user' 값이 'jackson'과 일치하는 경우를 예로 들었다
- route
- destination
- 트래픽이 전달될 Host를 명시하며, 이때의 Host는 VirtualService의 Host(ex: DNS Name) 와는 달리, Service Registry에 존재하는 실제 Destination를 의미한다.
- Service Registry는 Service Mesh 안에 존재하는 K8s Service와 Endpoint 데이터를 따로 갖고 있는 저장소이며, Istio가 관리한다.
- Service 이름만 명시하는 경우, 해당 VirtualService가 위치한 Namespace에서 해당 Service를 찾으므로 필요한 경우, FQDN 형식을 사용
- 트래픽이 전달될 Host를 명시하며, 이때의 Host는 VirtualService의 Host(ex: DNS Name) 와는 달리, Service Registry에 존재하는 실제 Destination를 의미한다.
- destination
- match
VitrualService의 Routing Rule은 위에서 아래로 각 Rule이 차례대로 적용되며, 가장 마지막에 위치한 Rule이 Default Backend로 동작한다.
App 배포
이론 설명이 너무 길었다. 이번엔 Istio에서 제공하는 Sample App인 'bookinfo'를 배포하고, Gateway와 VirtualService를 적용하여 외부에서 접근해볼 시간이다.
bookinfo App은 책에 대한 정보(Summary, Detail, Review)를 화면에 표시하는 Application으로 4개의 Microservice로 구성된다.
- productpage: Request를 받으면 details와 reviews 서비스를 호출 후 결과를 렌더링하는 Frontend
- details: 책 정보(Type, 페이지 수, ISBN 등) 서비스
- reviews: 책에 대한 리뷰 서비스를 수행하며, ratings 서비스를 호출
- ratings: 책 평점 서비스
'reviews' Microservice는 3개의 버전을 포함한다.
- v1: ratings 서비스를 호출하지 않음
- v2: ratings를 호출하며, 점수를 1부터 5개의 검정 별(star)로 표시
- v3: ratings를 호출하며, 점수를 1부터 5개의 빨강 별(star)로 표시
bookinfo App의 전체 Architecture는 다음과 같다.
다음 명령어로 'bookinfo' App을 default namespace에 배포한다. App의 모든 Deployment와 Service는 bookinfo.yaml 파일에 정의된 상태이다.
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
default namespace에 이미 Sidecar Injection 설정이 완료된 상태이며, Envoy Proxy가 Pod에 포함되었음을 확인할 수 있다.
다음과 같은 Gateway와 VirtualService 파일을 작성하고, Kubernetes에 추가(kubectl apply)한다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
<bookinfo-gateway.yaml>
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
<bookinfo-virtualservice.yaml>
아래 명령어로 외부에서 Application에 접근 가능한 URL을 가져올 수 있다.
echo $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/productpage
이 주소를 웹 브라우저에 붙여넣기하여 접속하면 다음과 같은 화면이 나온다.
여러번 새로고침할 때마다 'Book Reviews' 메뉴의 화면이 계속해서 바뀌는 것을 알 수 있다. 3개 버전의 reviews가 배포된 상태이기 때문에 Round-robin 방식으로 Loadbalancing되기 때문이다. 일단 트래픽을 충분히 발생시키기 위해 10번 정도 새로고침을 해주자.
Kiali Dashboard
Kiali는 Istio에서 수집한 Telemetry 데이터를 바탕으로 Observability를 제공하는 Dashboard다. 'bookinfo' App에 충분한 트래픽이 발생하였으므로 Kiali에서 이를 확인할 수 있다. 다음 명령어로 Local 환경에서 Kiali Dashboard에 접근할 수 있다.
istioctl dashboard kiali
Versioned App Graph을 선택하면 reviews는 v1/v2/v3 3개 버전으로 구성되었으며, 그래프의 내용이 위에서 설명한 'bookinfo' App의 Architecture와 동일한 것을 알 수 있다.
Display 항목 중 'Request Distribution'을 선택하면 reviews는 서로 대등한 확률로 Request에 대한 Loadbalancing이 이루어지는 것도 확인할 수 있다.
Workloads 메뉴에선 현재 배포한 Workload(ex: Deployment, StatefulSet)의 상태를 쉽게 파악할 수 있다.
특히 유용한 기능 중 하나는 workload를 선택했을 때, Log를 확인이 가능하다는 것이다. 굳이 터미널에서 'kubectl logs' 명령어를 사용하지 않아도 되는 점에서 매우 편리하다.
Kiali에 대해서 더욱 깊이있게 공부하고 싶은 분이라면 Istio에서 제공하는 Document를 참고하기 바란다.
What comes next?
다음 시간엔 Istio의 가장 강력한 기능 중 하나인 Traffic Management에 대해서 다뤄볼 예정이다.
참고
'Service Mesh' 카테고리의 다른 글
Istio - (5) Destination Rule 응용 (0) | 2021.04.06 |
---|---|
Istio - (4) Traffic Management (0) | 2021.04.05 |
Istio - (2) Istio 설치(EKS) (0) | 2021.03.27 |
Istio - (1) Introduction (0) | 2021.03.27 |