Envoy Gateway HTTP ルーティング実践: Host、Path、Header、Traffic Splitting
最初の 2 本で「これは何か」の土台はできました。ここからは日々実際に触るもの、つまり HTTPRoute に入ります。
HTTPRoute は、入ってくるトラフィックに対する routing script だと考えるとわかりやすいです。Nginx ルールを書いたり controller の annotation を暗記したりする代わりに、Kubernetes-native なリソースで表現します。
先に一つだけ整理しておくと、この記事が扱うのは HTTPRoute のみです。HTTP/HTTPS の意味を扱うからです。gRPC なら GRPCRoute、生の TCP なら TCPRoute、TLS passthrough なら TLSRoute が向いています。何でも HTTPRoute に押し込まないことです。YAML から「なんとか間に合わせてる感」が出てきます。
最もよくあるルーティング: Host と Path
典型例はこれです。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
spec:
parentRefs:
- name: eg
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080意味はこうです。
Host: app.example.comのときだけこの route にマッチする- path は
/apiで始まる必要がある - トラフィックは
api-service:8080へ転送される
hostnames を外すと、「domain は問わず path だけで判定する route」になります。
matches で何を見られるか
matches は HTTPRoute の中心的な概念の一つです。
「どんな条件でこのルールを発火させるか」と考えるとわかりやすいです。
代表的な match 条件:
pathheadersqueryParamsmethod
例:
matches:
- method: GET
path:
type: PathPrefix
value: /api
headers:
- name: version
value: v2意味:
GETリクエストのみ- path は
/apiで始まる - request に
version: v2header が必要
このパターンは API version の試験運用や、特定ユーザーへの段階的 rollout に向いています。
1 つの Route に複数ルールを持たせる
1 つの HTTPRoute で、異なる path を別 service へ振り分けることもできます。
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /admin
backendRefs:
- name: admin-service
port: 8080これは 1 domain 配下のサブパス分割にとても便利です。たとえば:
/apiは API service へ/adminは admin backend へ
ルーティングロジックがそのまま見えます。途中まで読んだら自分の存在意義まで疑い始めるような古い設定ファイルより、ずっと健全です。
Header、Method、Query を条件にする
HTTPRoute は path だけではなく、request header、method、query param でもマッチできます。
たとえば version: v2 が付いた request だけ新 service へ送るなら:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: versioned-route
spec:
parentRefs:
- name: eg
rules:
- matches:
- path:
type: PathPrefix
value: /api
headers:
- name: version
value: v2
backendRefs:
- name: api-v2
port: 8080
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-v1
port: 8080このパターンは次に向いています。
- Canary release
- 特定顧客だけ新 version を先に試す
- 新機能の手動検証
新しい domain を丸ごと切るより、header ベース routing のほうが粒度が細かく、実験もしやすいです。
filters: 転送前に request を加工する
HTTPRoute は単に「match して forward する」だけではありません。転送前後に変換もできます。それが filters です。
よくある用途は header の追加です。
rules:
- filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: x-env
value: prod
backendRefs:
- name: api-service
port: 8080これは次に便利です。
- backend に渡す前に tracing metadata を差し込む
- 入口層で固定 header を付与する
- request/response の変換
ただし、filters は強力でも、入口層を巨大 middleware の塊にしてよい免罪符ではありません。route にロジックを盛りすぎると、デバッグがそれ専用のカウンセリングを必要とする感じになります。
Weighted Traffic Splitting: 最もよくある Canary パターン
旧 version に 90%、新 version に 10% 流したいなら weight を使います。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
spec:
parentRefs:
- name: eg
hostnames:
- "app.example.com"
rules:
- backendRefs:
- name: api-v1
port: 8080
weight: 90
- name: api-v2
port: 8080
weight: 10これは基本的な canary / traffic splitting です。
トラフィック実験をするたびに完全な service mesh が必要なわけではありません。多くの API service では、これで十分以上ですし、設定もかなりきれいです。
💡
weightは相対値です。合計が 100 である必要はありません。9と1でも90と10と同じ比率を表します。
timeouts: request を永遠にぶら下げない
HTTPRoute は rule 単位で timeout を設定できます。これは重要です。入口層に制限がないと、悪い request が永遠に居座る迷惑客みたいになります。
rules:
- matches:
- path:
type: PathPrefix
value: /reports
timeouts:
request: 10s
backendRequest: 2s
backendRefs:
- name: report-service
port: 80802 つの field の意味:
request: クライアント request 全体の最大待機時間backendRequest: backend への 1 回の request に対する最大待機時間
backendRequest は request を超えるべきではありません。全行程 10 分なのに、途中のバス待ちが 20 分まで可、みたいな話になって宇宙が混乱します。
よくある 2 つの注意点
1. parentRefs は特定 listener を指定できる
Gateway に複数 listener がある場合、1 つだけに bind できます。
parentRefs:
- name: eg
sectionName: httpこれは route が http listener にだけ attach されることを意味します。
複数 listener がある構成では、全部にぶら下げるよりずっと予測しやすいです。
2. matches がない = 全部にマッチする
rule に matches がない場合、デフォルトでは / にマッチする、つまり catch-all です。
便利ではありますが、自分ではより具体的な rule があるつもりでも、静かに飲み込んでしまうことがあります。面倒だから省略して、1 時間後に「なぜ精密な rule が動かないんだ」と悩まないようにしてください。
ルーティングが効いていることを確認する
route を設定したら curl で検証します。
curl -H "Host: app.example.com" http://$GATEWAY_HOST/api/users
curl -H "Host: app.example.com" -H "version: v2" http://$GATEWAY_HOST/api/usersHTTPRoute status を見るには:
kubectl get httproute app-route -o yaml特に注目するのは:
status.parentsAcceptedcondition
YAML が正しそうでも、Gateway 側が reject していることがあります。応募しただけで採用されたと思い込むのと同じです。
一文まとめ
HTTPRoute の核心は「まず match し、その後で forward する」です。host、path、header、weight を押さえれば、日常的な HTTP 入口要件の 8 割くらいは処理できます。
次の一歩
次の記事では、本番で必ず出てくるテーマに進みます。HTTPS、証明書、TLS termination、そしてセキュリティです。 👉 TLS とセキュリティ