バーチャルホスト四つとマッチ五種を分ける
한국어 원문으로 표시합니다.
목표
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번 중 몇 번이었는지에서 나옵니다. 설명 줄에는 '가중치는 비율이지 보장이 아니다' 처럼 다음에 자기를 구해 줄 문장을 적으세요.