L7 트래픽 비율 전환
L7 트래픽 비율 전환 (L7 Traffic Shifting)
Cilium Service Mesh는 CiliumEnvoyConfig CRD를 정의해서 Cilium 에이전트에 내장된 Envoy 컴포넌트의 구성을 설정할 수 있게 해줘요. 이 예제에서는 helloworld Service로 가는 요청 중 90%를 백엔드 helloworld-v1로, 나머지 10%를 백엔드 helloworld-v2로 보내는 Envoy 리스너를 구성해볼게요.
본문
테스트 애플리케이션 배포하기 (Deploy Test Applications)
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/client-helloworld.yaml
테스트 워크로드는 다음과 같이 구성돼요:
- client 디플로이먼트 하나,
client - server 디플로이먼트 두 개,
helloworld-v1과helloworld-v2
이 파드들과 helloworld Service에 대한 정보를 확인해볼게요:
$ kubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
client-64848f85dd-sjfmb 1/1 Running 0 2m23s 10.0.0.206 cilium-control-plane <none> <none> kind=client,name=client,pod-template-hash=64848f85dd
helloworld-v1-5845f97d6b-gkdtk 1/1 Running 0 2m23s 10.0.0.241 cilium-control-plane <none> <none> app=helloworld,pod-template-hash=5845f97d6b,version=v1
helloworld-v2-7d55d87964-ns9kh 1/1 Running 0 2m23s 10.0.0.251 cilium-control-plane <none> <none> app=helloworld,pod-template-hash=7d55d87964,version=v2
$ kubectl get svc --show-labels
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS
helloworld ClusterIP 10.96.194.77 <none> 5000/TCP 8m27s app=helloworld,service=helloworld
가중치 기반 라우팅 적용하기 (Apply weight-based routing)
client의 파드 이름으로 환경 변수를 만들어볼게요:
$ export CLIENT=$(kubectl get pods -l name=client -o jsonpath='{.items[0].metadata.name}')
helloworld Service에 여러 번 요청을 보내보세요.
$ for i in {1..10}; do kubectl exec -it $CLIENT -- curl helloworld:5000/hello; done
테스트 결과는 다음과 같아요:
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
테스트 결과는 예상대로였어요. helloworld service로 보낸 요청 중 50%가 백엔드 helloworld-v1로, 나머지 50%가 백엔드 helloworld-v2로 전달됐어요.
CiliumEnvoyConfig를 사용하면 하나의 Service로 향하는 트래픽을 백엔드 Service 그룹으로 로드 밸런싱할 수 있어요. helloworld Service로 가는 트래픽을 로드 밸런싱하려면 먼저 각 백엔드 디플로이먼트에 대한 개별 Service를 만들어야 해요.
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/helloworld-service-v1-v2.yaml
트래픽의 90%를 helloworld-v1 Service 백엔드로, 10%를 helloworld-v2 Service 백엔드로 보내는 CiliumEnvoyConfig를 정의하는 envoy-helloworld-v1-90-v2-10.yaml 파일을 적용해볼게요:
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/envoy-helloworld-v1-90-v2-10.yaml
이 파드들과 Service들에 대한 정보를 확인해볼게요:
$ kubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
client-64848f85dd-sjfmb 1/1 Running 0 2m23s 10.0.0.206 cilium-control-plane <none> <none> kind=client,name=client,pod-template-hash=64848f85dd
helloworld-v1-5845f97d6b-gkdtk 1/1 Running 0 2m23s 10.0.0.241 cilium-control-plane <none> <none> app=helloworld,pod-template-hash=5845f97d6b,version=v1
helloworld-v2-7d55d87964-ns9kh 1/1 Running 0 2m23s 10.0.0.251 cilium-control-plane <none> <none> app=helloworld,pod-template-hash=7d55d87964,version=v2
$ kubectl get svc --show-labels
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS
helloworld ClusterIP 10.96.194.77 <none> 5000/TCP 16m app=helloworld,service=helloworld
helloworld-v1 ClusterIP 10.96.0.240 <none> 5000/TCP 4s app=helloworld,service=helloworld,version=v1
helloworld-v2 ClusterIP 10.96.41.142 <none> 5000/TCP 4s app=helloworld,service=helloworld,version=v2
참고
이 Envoy 리소스들은 K8s에서 전혀 검증되지 않아요. 즉 Envoy 리소스에 오류가 있어도 그 오류는 이 CRD를 관찰하는 Cilium Agent에서만 보여요. 따라서
kubectl apply는 성공을 보고하지만, 노드 로컬 Envoy 인스턴스를 위한 리소스의 파싱/설치는 실패했을 수 있어요. 현재 이를 검증하는 유일한 방법은 오류와 경고에 대해 Cilium Agent 로그를 관찰하는 거예요. 또한 Cilium Agent는 클러스터 안의 충돌하는 Envoy 리소스에 대해 경고 로그를 출력해요.
참고
Cilium Ingress Controller는 내부적으로 필요한 Envoy 리소스를 구성해줘요. 충돌이 없는지 Envoy 리소스를 명시적으로 만들 때는 Cilium Agent 로그를 확인해주세요.
helloworld Service에 다시 여러 번 요청을 보내볼게요.
$ for i in {1..10}; do kubectl exec -it $CLIENT -- curl helloworld:5000/hello; done
테스트 결과는 다음과 같아요:
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v2, instance: helloworld-v2-7d55d87964-ns9kh
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
Hello version: v1, instance: helloworld-v1-5845f97d6b-gkdtk
테스트 결과는 예상대로였어요. helloworld service로 보낸 요청 중 90%가 백엔드 helloworld-v1로, 나머지 10%가 백엔드 helloworld-v2로 전달됐어요.
정리하기 (Cleaning up)
규칙을 제거해볼게요.
$ kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/envoy-helloworld-v1-90-v2-10.yaml
테스트 애플리케이션을 제거해볼게요.
$ kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/client-helloworld.yaml
$ kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/servicemesh/envoy/helloworld-service-v1-v2.yaml
더 알아보기 (Learn more)
- L7 Load Balancing and URL re-writing — Envoy 기반 로드 밸런싱과 URL 재작성
- L7-Aware Traffic Management — L7 트래픽 관리
- CiliumEnvoyConfig CRD — Cilium Service Mesh 개요