동적 요청 라우팅 구성
동적 요청 라우팅 구성 (Configuring Dynamic Request Routing)
Gateway API의 HTTPRoute를 활용해 헤더 기반으로 HTTP 트래픽을 동적 라우팅하는 방법을 실제 예제(podinfo)로 배우는 문서예요.
본문
사전 요구사항 (Prerequisites)
이 가이드를 사용하려면 클러스터에 Linkerd가 설치되어 있고, Helm CLI가 설치되어 있어야 해요.
동적 요청 라우팅 (Dynamic request routing)
동적 요청 라우팅을 사용하면 요청 헤더의 내용을 기반으로 HTTP 트래픽을 라우팅할 수 있어요. 이는 A/B 테스트나 트래픽 관리 전략 같은 작업에 유용합니다.
핵심 구성 메커니즘은 Gateway API 타입인 HTTPRoute와 GRPCRoute입니다. 이 예제에서는 HTTPRoute 타입을 사용하는 일반적인 사용 사례를 살펴볼게요.
이 튜토리얼에서는 podinfo 프로젝트를 사용해 동적 요청 라우팅을 보여줍니다. 클러스터에 backend 두 개와 frontend 한 개의 podinfo 파드를 배포할 거예요. 트래픽은 처음에 한 backend로만 흐르고, 이후 frontend 요청에 헤더를 추가하는 것만으로 다른 backend로 트래픽을 전환해 볼게요.
설치 (Setup)
먼저 test 네임스페이스를 만들고 linkerd로 annotation을 달아, 그곳에 생성되는 모든 파드에 linkerd 프록시가 주입되도록 합니다:
`kubectl create ns test --dry-run=client -o yaml \
| linkerd inject - \
| kubectl apply -f -
`
그 다음 podinfo의 Helm repo를 추가하고, 두 개의 인스턴스를 설치합니다. 첫 번째는 "A backend"라는 메시지로 응답하고, 두 번째는 "B backend"로 응답할 거예요.
`helm repo add podinfo https://stefanprodan.github.io/podinfo
helm install backend-a -n test \
--set ui.message='A backend' podinfo/podinfo
helm install backend-b -n test \
--set ui.message='B backend' podinfo/podinfo
`
첫 번째 backend 인스턴스 backend-a로만 요청을 보내는 podinfo 인스턴스를 하나 더 추가합니다:
`helm install frontend -n test \
--set backend=http://backend-a-podinfo:9898/env podinfo/podinfo
`
세 파드가 모두 실행되면, 로컬 머신에서 frontend로 요청을 port-forward할 수 있어요:
`kubectl -n test port-forward svc/frontend-podinfo 9898 &
`
요청 보내기 (Sending Requests)
frontend 파드의 9898 포트 /echo로 보내는 요청은 Service backend-a-podinfo가 가리키는 파드로 전달됩니다:
`$ curl -sX POST localhost:9898/echo \
| grep -o 'PODINFO_UI_MESSAGE=. backend'
PODINFO_UI_MESSAGE=A backend
`
HTTPRoute 소개 (Introducing HTTPRoute)
헤더 기반 라우팅을 활성화하기 위해 다음 HTTPRoute 리소스를 적용해 볼게요:
`cat
apiVersion: policy.linkerd.io/v1beta2
kind: HTTPRoute
metadata:
name: backend-router
namespace: test
spec:
parentRefs:
- name: backend-a-podinfo
kind: Service
group: core
port: 9898
rules:
- matches:
- headers:
- name: "x-request-id"
value: "alternative"
backendRefs:
- name: "backend-b-podinfo"
port: 9898
- backendRefs:
- name: "backend-a-podinfo"
port: 9898
EOF
`
parentRefs에는 이 HTTPRoute 인스턴스가 작용할 리소스를 지정합니다. 여기서는 HTTPRoute의 네임스페이스(test)에 있는 backend-a-podinfo Service를 가리키고, Service의 포트 번호(Service의 target port가 아니라)를 지정했어요.
다음으로, 해당 Service로 들어오는 트래픽에 작용할 규칙 리스트를 제공합니다.
첫 번째 규칙에는 matches와 backendRefs 두 항목이 들어 있어요.
matches에는 이 특정 규칙이 매칭해야 할 조건을 나열합니다. 하나의 matches만 충족되면 규칙이 발동합니다(조건은 OR로 결합됩니다). 그 안에서 headers를 사용해 특정 헤더 키와 값에 대한 매칭을 지정할 수 있어요. 여러 헤더를 지정하면 모두 매칭되어야 합니다(matcher는 AND로 결합). 값에 대한 정규식 매칭을 원한다면 type: RegularExpression 필드를 추가할 수도 있습니다. 여기서처럼 type을 지정하지 않으면 Exact 타입으로 매칭합니다.
backendRefs에는 현재 규칙에 매칭되는 요청의 최종 목적지를 Service의 name과 port로 지정합니다.
여기서는 x-request-id: alternative 헤더를 가진 모든 요청을 backend-b-podinfo로 라우팅하도록 지정했어요. 헤더가 없으면 엔진은 matches 항목이 없고 backend-a-podinfo Service를 가리키는 마지막 규칙으로 폴백합니다.
앞선 요청들은 여전히 backend-a-podinfo로만 도달해야 해요:
`$ curl -sX POST localhost:9898/echo \
| grep -o 'PODINFO_UI_MESSAGE=. backend'
PODINFO_UI_MESSAGE=A backend
`
하지만 x-request-id: alternative 헤더를 추가하면 backend-b-podinfo로 라우팅됩니다:
`$ curl -sX POST \
-H 'x-request-id: alternative' \
localhost:9898/echo \
| grep -o 'PODINFO_UI_MESSAGE=. backend'
PODINFO_UI_MESSAGE=B backend
`
구현 참고사항 (Implementation notes)
위 예제에서 우리는 podinfo가 전달하는 일반적인 헤더인 x-request-id를 사용했어요. 하지만 애플리케이션이 헤더를 전달하기만 하면, 같은 기법이 임의의 헤더에서도 동작합니다.
또한 동적 요청 라우팅은 클라이언트 측 동작이라는 점에 주의하세요. 그래서 트래픽 소스(여기서는 frontend 파드)는 메시에 포함되어야 하지만, 엄밀히 말하면 목적지는 메시에 포함될 필요가 없습니다.
더 알아보기 (Learn more)
- Linkerd의 동적 요청 라우팅 기능 개요
- 라우팅 정책 구성 가이드