트래픽 미러링
트래픽 미러링 (Mirroring)
이 태스크는 Istio의 트래픽 미러링(shadowing) 기능을 보여줘요. 미러링은 실시간 트래픽의 사본을 미러링된 서비스로 보내서, 프로덕션 변경을 최대한 위험을 줄여 도입할 수 있게 해주는 강력한 개념이에요.
출처: Istio 문서
본문
참고: Istio 웹사이트 코드의 템플릿 버그 때문에 이 페이지의 예제는 제대로 렌더링되지 않아요. 올바른 매니페스트(manifest)는 페이지 소스에서 확인할 수 있어요.
이 태스크는 Istio의 트래픽 미러링(shadowing) 기능을 보여줘요.
트래픽 미러링은 섀도잉(shadowing)이라고도 불리는데, 피처 팀이 최대한 위험을 줄이면서 프로덕션에 변경 사항을 도입할 수 있게 해주는 강력한 개념이에요. 미러링은 실시간 트래픽의 사본을 미러링된 서비스로 보내요. 미러링된 트래픽은 primary 서비스의 중요 요청 경로(critical request path) 밖에서(out of band) 발생해요.
이 태스크에서는 먼저 모든 트래픽을 테스트 서비스의 v1로 보내도록 강제할 거예요. 그런 다음, 트래픽의 일부를 v2로 미러링하는 규칙을 적용할 거예요.
Istio는 Kubernetes Gateway API를 지원하며, 향후 트래픽 관리의 기본 API로 만들려고 하고 있어요. 아래 지침을 통해 메시에서 트래픽 관리를 설정할 때 Gateway API를 쓸지 Istio 설정 API를 쓸지 선택할 수 있어요. 선호에 따라 Gateway API 탭이나 Istio APIs 탭 중 하나의 지침을 따르면 돼요.
참고로 Kubernetes Gateway API CRD는 대부분의 Kubernetes 클러스터에 기본으로 설치되지 않으므로, Gateway API를 사용하기 전에 해당 CRD가 설치되어 있는지 확인해야 해요:
$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.0/experimental-install.yaml
시작하기 전에
-
설치 가이드를 따라 Istio를 설정해요.
-
액세스 로깅(access logging)을 활성화한 두 가지 버전의 httpbin 서비스를 배포하는 것으로 시작해요:
-
httpbin-v1을 배포해요:$ kubectl create -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: httpbin-v1 spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "[::]:80", "httpbin:app"] ports: - containerPort: 80 EOF -
httpbin-v2를 배포해요:$ kubectl create -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: httpbin-v2 spec: replicas: 1 selector: matchLabels: app: httpbin version: v2 template: metadata: labels: app: httpbin version: v2 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "[::]:80", "httpbin:app"] ports: - containerPort: 80 EOF -
httpbinKubernetes 서비스를 배포해요:$ kubectl create -f - <<EOF apiVersion: v1 kind: Service metadata: name: httpbin labels: app: httpbin spec: ports: - name: http port: 8000 targetPort: 80 selector: app: httpbin EOF
-
-
httpbin서비스로 요청을 보내는 데 사용할curl워크로드를 배포해요:$ cat <<EOF | kubectl create -f - apiVersion: apps/v1 kind: Deployment metadata: name: curl spec: replicas: 1 selector: matchLabels: app: curl template: metadata: labels: app: curl spec: containers: - name: curl image: curlimages/curl command: ["/bin/sleep","3650d"] imagePullPolicy: IfNotPresent EOF
기본 라우팅 정책 만들기
기본적으로 Kubernetes는 httpbin 서비스의 두 버전에 걸쳐 로드 밸런싱을 해요. 이 단계에서는 모든 트래픽이 v1로 가도록 그 동작을 바꿀 거예요.
-
모든 트래픽을 서비스의
v1로 라우팅하는 기본 라우트 규칙을 만들어요:Istio APIs
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: httpbin spec: hosts: - httpbin http: - route: - destination: host: httpbin subset: v1 weight: 100 --- apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: httpbin spec: host: httpbin subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 EOFGateway API
$ kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: httpbin-v1 spec: ports: - port: 80 name: http selector: app: httpbin version: v1 --- apiVersion: v1 kind: Service metadata: name: httpbin-v2 spec: ports: - port: 80 name: http selector: app: httpbin version: v2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin spec: parentRefs: - group: "" kind: Service name: httpbin port: 8000 rules: - backendRefs: - name: httpbin-v1 port: 80 EOF -
이제 모든 트래픽이
httpbin:v1로 향하게 됐으니, 서비스에 요청을 보내 볼게요:$ kubectl exec deploy/curl -c curl -- curl -sS http://httpbin:8000/headers { "headers": { "Accept": "*/*", "Content-Length": "0", "Host": "httpbin:8000", "User-Agent": "curl/7.35.0", "X-B3-Parentspanid": "57784f8bff90ae0b", "X-B3-Sampled": "1", "X-B3-Spanid": "3289ae7257c3f159", "X-B3-Traceid": "b56eebd279a76f0b57784f8bff90ae0b", "X-Envoy-Attempt-Count": "1", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=20afebed6da091c850264cc751b8c9306abac02993f80bdb76282237422bd098;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default" } } -
httpbin-v1와httpbin-v2pod의 로그를 확인해요.v1에 대한 액세스 로그 항목이 보이고v2에는 아무것도 없어야 해요:$ kubectl logs deploy/httpbin-v1 -c httpbin 127.0.0.1 - - [07/Mar/2018:19:02:43 +0000] "GET /headers HTTP/1.1" 200 321 "-" "curl/7.35.0"$ kubectl logs deploy/httpbin-v2 -c httpbin <none>
httpbin-v2로 트래픽 미러링
-
httpbin-v2로 트래픽을 미러링하도록 라우트 규칙을 변경해요:Istio APIs
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: httpbin spec: hosts: - httpbin http: - route: - destination: host: httpbin subset: v1 weight: 100 mirror: host: httpbin subset: v2 mirrorPercentage: value: 100.0 EOF이 라우트 규칙은 트래픽의 100%를
v1로 보내요. 마지막 부분(stanza)은 같은 트래픽의 100%를httpbin:v2서비스로 미러링(즉, 동시에 전송)하고 싶다는 것을 지정해요. 트래픽이 미러링되면, 요청은 Host/Authority 헤더에-shadow가 붙어서 미러링된 서비스로 전송돼요. 예를 들어cluster-1은cluster-1-shadow가 돼요.또한, 이 요청들은 "fire and forget" 방식으로 미러링된다는 점이 중요해요. 즉 응답은 버려져요.
mirrorPercentage필드 아래의value필드를 사용하면 모든 요청을 미러링하는 대신 트래픽의 일부만 미러링할 수 있어요. 이 필드가 없으면 모든 트래픽이 미러링돼요.Gateway API
$ kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin spec: parentRefs: - group: "" kind: Service name: httpbin port: 8000 rules: - filters: - type: RequestMirror requestMirror: backendRef: name: httpbin-v2 port: 80 backendRefs: - name: httpbin-v1 port: 80 EOF이 라우트 규칙은 트래픽의 100%를
v1로 보내요.RequestMirror필터는 같은 트래픽의 100%를httpbin:v2서비스로 미러링(즉, 동시에 전송)하고 싶다는 것을 지정해요. 트래픽이 미러링되면, 요청은 Host/Authority 헤더에-shadow가 붙어서 미러링된 서비스로 전송돼요. 예를 들어cluster-1은cluster-1-shadow가 돼요.또한, 이 요청들은 "fire and forget" 방식으로 미러링된다는 점이 중요해요. 즉 응답은 버려져요.
-
트래픽을 보내요:
$ kubectl exec deploy/curl -c curl -- curl -sS http://httpbin:8000/headers이제
v1과v2양쪽 모두에서 액세스 로깅이 보여야 해요.v2에 생성된 액세스 로그는 실제로v1로 향하는 미러링된 요청들이에요.$ kubectl logs deploy/httpbin-v1 -c httpbin 127.0.0.1 - - [07/Mar/2018:19:02:43 +0000] "GET /headers HTTP/1.1" 200 321 "-" "curl/7.35.0" 127.0.0.1 - - [07/Mar/2018:19:26:44 +0000] "GET /headers HTTP/1.1" 200 321 "-" "curl/7.35.0"$ kubectl logs deploy/httpbin-v2 -c httpbin 127.0.0.1 - - [07/Mar/2018:19:26:44 +0000] "GET /headers HTTP/1.1" 200 361 "-" "curl/7.35.0"
정리하기
-
규칙을 제거해요:
Istio APIs
$ kubectl delete virtualservice httpbin $ kubectl delete destinationrule httpbinGateway API
$ kubectl delete httproute httpbin $ kubectl delete svc httpbin-v1 httpbin-v2 -
httpbin과curl배포 및httpbin서비스를 삭제해요:$ kubectl delete deploy httpbin-v1 httpbin-v2 curl $ kubectl delete svc httpbin