Split Four Virtual Hosts and Five Match Kinds
한국어 원문으로 표시합니다.
목표
Host 헤더로 가상 호스트가 먼저 정해지는 것을 확인하고, 매치의 종류와 목적지의 종류를 하나씩 붙여 가며 같은 요청이 어디로 가는지 본다.
왜 중요한가
라우팅 설정은 사람이 읽기에는 '규칙 목록' 처럼 보이지만 실제로는 두 단계의 선택이다. 그리고 두 단계가 서로 다른 규칙으로 돌아간다 — 앞은 구체성, 뒤는 순서. 이 차이를 모르면 규칙을 위아래로 옮기며 시간을 버리게 된다. 여기에 더해 weighted_clusters 가 보장이 아니라 확률이라는 것, direct_response 로 앱을 건드리지 않고 끝낼 수 있다는 것, 헤더가 세 층에서 각각 더해진다는 것까지 손으로 확인해 두면 남이 쓴 라우트 표도 몇 분이면 읽힌다.
단계
/root/envd-route/route.yaml에 가상 호스트 네 개를 두세요 —exact(shop.envd.test),suffix(*.envd.test),prefixw(shop.*),anyhost(*). 각각/에서vh=exact·vh=suffix·vh=prefixw·vh=any를 돌려줍니다(관리 9931, 리스너127.0.0.1:10031). 띄운 뒤 네 가지 Host 헤더로/zzz를 요청해/root/envd-route/01-vhosts.txt에exact=·suffix=·prefixw=·any=네 줄로 결과를 적으세요(요청한 Host 는 차례로shop.envd.test,www.envd.test,shop.other.test,nowhere.example입니다)./root/envd-route/route.yaml을/root/envd-route/route-dup.yaml로 복사한 뒤domains: ["*"]인 가상 호스트를 하나 더 만드세요(이름은 겹치지 않게).envoy --mode validate로 검사해 출력과 종료 코드를/root/envd-route/02-onestar.txt에 저장하세요(마지막 줄은rc=1).exact가상 호스트의/라우트 위에 두 라우트를 더하세요 —path: "/exact"는m=path를,safe_regex로^/id/[0-9]+$는m=regex를 돌려줍니다./root/envd-route/03-match.txt에path=(/exact요청),regex=(/id/42요청),regex_miss=(/id/abc요청) 세 줄을 적으세요. Host 는 모두shop.envd.test입니다./api로 가는 라우트를 두 개 더하세요(정규식 라우트 아래,/라우트 위). 하나는headers조건으로x-canary: yes일 때m=header를, 다른 하나는query_parameters조건으로debug=1일 때m=query를 돌려줍니다./root/envd-route/04-cond.txt에header=,query=,plain=(조건 없이/api만) 세 줄을 적으세요.- 업스트림 둘을 띄우고(
8082,8083) 클러스터blue·green을 만든 뒤,/split라우트가weighted_clusters로 75 대 25 로 나눠 보내게 하세요.--concurrency 1로 띄우고 40번 요청해/root/envd-route/05-weighted.txt에blue=·green=·total=세 줄(각 업스트림이 받은 횟수와 합)을 적으세요. - 두 라우트를 더하세요 —
path: "/healthz"는direct_response로 200 과alive를,prefix: "/old"는redirect로/new로 301 을 보냅니다./root/envd-route/06-direct.txt에health=(응답 본문),redirect_code=(HTTP 코드),redirect_url=(Location 헤더 값) 세 줄을 적으세요. - 응답 헤더
x-level을 세 층에 각각 더하세요 — 라우트에route, 가상 호스트에virtualhost, 라우트 표에routeconfig.shop.envd.test의/zzz로 요청해 돌아온x-level헤더를 모두/root/envd-route/07-headers.txt에levels=한 줄로 쉼표 없이 공백으로 이어 적고,count=줄에 개수를 적으세요. /root/envd-route/08-report.md에vhost_order=(가상 호스트 구체성 순서를exact,suffix,prefix,star형식으로),star_limit=(라우트 표 하나에 둘 수 있는*가상 호스트 수),blue_share=(5단계에서 blue 가 받은 비율, 백분율 정수),redirect_code=(6단계의 코드) 네 줄을 적고, 그 아래 배운 것을 네 줄 이상 적으세요.
참고
- Envoy 를 띄울 때는
setsid --fork nohup envoy -c <파일> --log-level warn --concurrency 1 > <로그> 2>&1 </dev/null를 쓰고, 다시 띄우기 전에는pkill -x envoy로 정리하세요. - 기동은 고정
sleep이 아니라/ready가 LIVE 를 돌려줄 때까지 도는 루프로 기다립니다. - 요청에 이름을 붙이려면
curl -H "Host: 이름"을 씁니다. 질의 문자열이 든 주소는 따옴표로 감싸야 셸이?를 삼키지 않습니다. - 업스트림 흉내용 서버는
python3 /opt/lab/envoy/upstream.py <포트> ok입니다. 응답 본문에 포트가 들어 있어 어느 쪽이 받았는지 셀 수 있습니다. - 흔한 실수 — 조건이 붙은 라우트를 넓은
prefix: "/"아래에 두면 영영 걸리지 않습니다. - 흔한 실수 —
--concurrency 1을 빼고 분배를 세면 숫자가 매번 달라집니다.
라우트 표보다 먼저 가상 호스트가 정해진다
/root/envd-route/route.yaml 에 가상 호스트 네 개를 두세요 — exact(shop.envd.test), suffix(*.envd.test), prefixw(shop.*), anyhost(*). 각각 / 에서 vh=exact·vh=suffix·vh=prefixw·vh=any 를 돌려줍니다(관리 9931, 리스너 127.0.0.1:10031). 띄운 뒤 네 가지 Host 헤더로 /zzz 를 요청해 /root/envd-route/01-vhosts.txt 에 exact=·suffix=·prefixw=·any= 네 줄로 결과를 적으세요(요청한 Host 는 차례로 shop.envd.test, www.envd.test, shop.other.test, nowhere.example 입니다).
라우트 표를 보기 전에 Host(또는 :authority) 헤더로 가상 호스트가 먼저 정해집니다. 그래서 '라우트를 분명히 썼는데 안 걸린다' 의 절반은 가상 호스트를 잘못 고른 것입니다. 와일드카드는 접미(*.foo.com)와 접두(foo.*) 두 가지가 있고, 어느 것도 빈 문자열에는 맞지 않습니다. 요청은 curl -H "Host: 이름" http://127.0.0.1:포트/zzz 로 보냅니다.
* 는 라우트 표 전체에 하나만 둘 수 있다
/root/envd-route/route.yaml 을 /root/envd-route/route-dup.yaml 로 복사한 뒤 domains: ["*"] 인 가상 호스트를 하나 더 만드세요(이름은 겹치지 않게). envoy --mode validate 로 검사해 출력과 종료 코드를 /root/envd-route/02-onestar.txt 에 저장하세요(마지막 줄은 rc=1).
가상 호스트 선택은 '가장 구체적인 것이 이긴다' 로 돌아가는데, * 가 두 개면 누가 더 구체적인지 정할 방법이 없습니다. 그래서 Envoy 는 이 상태를 실행 중에 헷갈리게 두지 않고 설정을 읽는 시점에 거절합니다. 거절 메시지에 라우트 표의 이름이 함께 나오니 그 줄을 그대로 옮겨 두세요.
정확한 경로와 정규식으로 맞힌다
exact 가상 호스트의 / 라우트 위에 두 라우트를 더하세요 — path: "/exact" 는 m=path 를, safe_regex 로 ^/id/[0-9]+$ 는 m=regex 를 돌려줍니다. /root/envd-route/03-match.txt 에 path=(/exact 요청), regex=(/id/42 요청), regex_miss=(/id/abc 요청) 세 줄을 적으세요. Host 는 모두 shop.envd.test 입니다.
매치의 종류는 셋입니다 — prefix(앞이 같으면), path(통째로 같아야), safe_regex(정규식). 앞의 둘이 빠르므로 정규식은 꼭 필요할 때만 씁니다. 정규식이 맞지 않으면 그 라우트를 건너뛰고 아래로 계속 내려갑니다 — 404 가 아니라 다음 라우트가 받는다는 점이 중요합니다. safe_regex 는 { regex: "..." } 형태로 씁니다.
같은 경로를 헤더와 질의 문자열로 가른다
/api 로 가는 라우트를 두 개 더하세요(정규식 라우트 아래, / 라우트 위). 하나는 headers 조건으로 x-canary: yes 일 때 m=header 를, 다른 하나는 query_parameters 조건으로 debug=1 일 때 m=query 를 돌려줍니다. /root/envd-route/04-cond.txt 에 header=, query=, plain=(조건 없이 /api 만) 세 줄을 적으세요.
경로만으로는 가를 수 없는 요구가 실무에는 많습니다 — 내부 테스터만 새 버전으로, 디버그 질의가 붙은 요청만 다른 백엔드로. 그래서 매치에는 경로 말고도 headers 와 query_parameters 조건을 함께 걸 수 있고, 한 매치 안의 조건은 모두 만족해야 합니다. 두 라우트가 같은 prefix 를 쓰면 위에 있는 것이 먼저 판정되니, 조건이 붙은 쪽을 위에 둡니다.
한 라우트가 두 클러스터로 나눠 보낸다
업스트림 둘을 띄우고(8082, 8083) 클러스터 blue·green 을 만든 뒤, /split 라우트가 weighted_clusters 로 75 대 25 로 나눠 보내게 하세요. --concurrency 1 로 띄우고 40번 요청해 /root/envd-route/05-weighted.txt 에 blue=·green=·total= 세 줄(각 업스트림이 받은 횟수와 합)을 적으세요.
가중치는 비율이지 보장이 아닙니다. 그리고 워커 스레드마다 상태가 따로 놀기 때문에 기본 concurrency(코어 수)로 세면 숫자가 매번 달라집니다 — 그래서 이 단계는 워커 하나로 띄워야 합니다. 업스트림은 python3 /opt/lab/envoy/upstream.py <포트> ok 로 띄우고, 응답 본문에 포트가 들어 있으니 sort | uniq -c 로 세면 됩니다.
업스트림 없이 응답하고, 옛 경로를 옮겨 준다
두 라우트를 더하세요 — path: "/healthz" 는 direct_response 로 200 과 alive 를, prefix: "/old" 는 redirect 로 /new 로 301 을 보냅니다. /root/envd-route/06-direct.txt 에 health=(응답 본문), redirect_code=(HTTP 코드), redirect_url=(Location 헤더 값) 세 줄을 적으세요.
direct_response 는 업스트림에 가지 않고 Envoy 가 직접 답합니다 — 헬스 체크 경로나 점검 안내 페이지를 앱에 넣지 않고 프록시에서 끝낼 수 있습니다. redirect 는 302 가 기본이라 영구 이전이면 response_code: MOVED_PERMANENTLY 를 적어야 합니다. curl -o /dev/null -w '%{http_code} %{redirect_url}' 로 두 값을 한 번에 받을 수 있습니다.
헤더를 붙이는 자리가 세 군데다
응답 헤더 x-level 을 세 층에 각각 더하세요 — 라우트에 route, 가상 호스트에 virtualhost, 라우트 표에 routeconfig. shop.envd.test 의 /zzz 로 요청해 돌아온 x-level 헤더를 모두 /root/envd-route/07-headers.txt 에 levels= 한 줄로 쉼표 없이 공백으로 이어 적고, count= 줄에 개수를 적으세요.
헤더 조작은 라우트 · 가상 호스트 · 라우트 표 세 곳에 쓸 수 있습니다. 덮어쓰는 것이 아니라 각각 더해집니다 — 그래서 같은 이름의 헤더가 여러 개 남을 수 있고, 클라이언트는 그걸 쉼표로 이은 하나로 보기도 합니다. 적용은 안쪽(라우트)부터 바깥쪽(라우트 표) 순입니다. curl -sI 로 헤더만 받아 grep -i x-level 하세요.
라우팅 표를 읽는 규칙으로 정리한다
/root/envd-route/08-report.md 에 vhost_order=(가상 호스트 구체성 순서를 exact,suffix,prefix,star 형식으로), star_limit=(라우트 표 하나에 둘 수 있는 * 가상 호스트 수), blue_share=(5단계에서 blue 가 받은 비율, 백분율 정수), redirect_code=(6단계의 코드) 네 줄을 적고, 그 아래 배운 것을 네 줄 이상 적으세요.
비율은 직접 계산하세요 — 40번 중 몇 번이었는지에서 나옵니다. 설명 줄에는 '가중치는 비율이지 보장이 아니다' 처럼 다음에 자기를 구해 줄 문장을 적으세요.