前提
GEP-1294: xRoutes Mesh Binding を実装している Istio 等の Service Mesh を利用してください。
はじめに
Shadow Serviceを使わなくても、 Gateway API の標準機能だけ で 既存HTTPRouteのyamlを1行も触らずに拡張 できます。ポイントは「HTTPRoute の parentRefs に Kubernetes Service を指定できる(GEP-1294)」仕様です。
GEP-1294 の Route presence により、Service を parentRef にした xRoute を作成すると、その Service に対する暗黙の送達(通常の Service→Endpoints ルーティング)は “追加” ではなく Route によって置換されうる と整理されています。さらに Namespace boundaries では、同一 Namespace の Service を parentRef にした producer route は、その Service へのすべての受信リクエストに適用されるべき(SHOULD)とされます。
なにが嬉しいか
- 既存ツールがHTTPRouteの細かいカスタマイズを提供していない場合でもカスタムできる
- Gateway APIの仕様だけで実現可能
図解
Mermaidを表示
flowchart LR
classDef parent stroke-dasharray: 4 2;
classDef note fill:#FFF9C4,stroke:#FBC02D,color:#5D4037,stroke-width:1px;
subgraph Ingress
GW[Gateway]
end
subgraph app-ns
HR_a[HTTPRoute a(既存)]
SVC_a[(Service a)]
DEP_a[Deployment a]
end
subgraph ext-ns
HR_b[HTTPRoute b(新設)]
SVC_b[(Service b)]
DEP_b[Deployment b]
end
GW e1@--> HR_a
HR_a -.parent ref: 登録.-> GW
HR_a e2@--> SVC_a
SVC_a -."selector: 注1".-x DEP_a
SVC_a e4@--> HR_b
HR_b -."parentRef: 上書き".-> SVC_a
HR_b e5@--> SVC_b
SVC_b e6@--> DEP_b
subgraph Notes
direction TB
N1>"注1: Service を parentRef にした Route は、その Service の暗黙ルーティングを **置換** します(GEP-1294『Route presence』)。このため Service 側の selector は最終的な宛先決定に影響しません。"
:::note
end
e1@{ animate: true }
e2@{ animate: true }
e4@{ animate: true }
e5@{ animate: true }
e6@{ animate: true }
使いどころ
- Controller 等が管理している HTTPRoute を変更せずに、
Serviceを親にした別の HTTPRoute で宛先の Service を切り替えたり、必要な L7 制御(マッチ/ヘッダ操作/リトライ/スプリット等)を上乗せできる - “その Service への受信全体を制御したい” → producer route
- “自分の Namespace からの発信だけ差し替えたい” → consumer route
追加説明
GEP-1294 では、parentRef が指す Service の Namespace と Route の Namespace の関係で意味合いが変わります。APIに明示フィールドがあるわけではなく、あくまで 振る舞い上 の区別です。
これにより、以下のような事が可能になります:
- 受け口全体を制御したい場合に、対象 Service 側で producer route を定義
- 自分の Namespace からの発信だけを制御したい場合に、別 Namespace 側で consumer route を作成
いずれの場合も既存の HTTPRoute を触らずに追加で置くことで実現できます。
producer route(受信側を制御)
適用条件:
parentRef が 同一 Namespace の Service を指す場合
振る舞い:
- その Service へのすべての受信リクエスト(他 Namespace からの呼び出しを含む)に適用されるべき(SHOULD)
- Service 側の既定ルーティングより Route の規則が優先
- 注: 一部実装ではクライアント側プロキシで適用されるため、メッシュ外クライアントには効かない場合があります
先程の図解は、このproducer routeです。
consumer route(送信側を制御)
適用条件:
parentRef が 別 Namespace の Service を指す場合
振る舞い:
- その Route が存在する Namespace 内からの発信にのみ適用(スコープが限定)
- 異なる Namespace 間のトラフィックを、無関係な第三の Namespace から勝手に変更できないようにするための境界づけ
① とある ns は HTTPRoute a の内容が適用される(consumer route/通常経路)
flowchart LR
classDef note fill:#FFF9C4,stroke:#FBC02D,color:#5D4037,stroke-width:1px;
subgraph app-ns
SVC_a[(Service a)]
DEP_a[Deployment a]
end
subgraph other-ns["other-ns(例:とある ns)"]
CALL_other[Pod/Sidecar(caller)]
HR_a[HTTPRoute a(consumer)]
end
CALL_other e1@--> HR_a
HR_a -."parentRef: app-ns / Service a(別NS ↔ consumer)".-> SVC_a
HR_a e2@--> SVC_a
SVC_a e3@--> DEP_a
e1@{ animate: true }
e2@{ animate: true }
e3@{ animate: true }
② 特定の ns は HTTPRoute b の内容が適用される(consumer route/宛先差し替え)
flowchart LR
classDef note fill:#FFF9C4,stroke:#FBC02D,color:#5D4037,stroke-width:1px;
subgraph app-ns
SVC_a[(Service a)]
end
subgraph ext-ns
SVC_b[(Service b)]
DEP_b[Deployment b]
end
subgraph dev-ns["dev-ns(特定の ns)"]
CALL_dev[Pod/Sidecar(caller)]
HR_b[HTTPRoute b(consumer)]
end
CALL_dev e1@--> HR_b
HR_b -."parentRef: app-ns / Service a(別NS ↔ consumer)".-> SVC_a
HR_b e2@--> SVC_b
SVC_b e3@--> DEP_b
e1@{ animate: true }
e2@{ animate: true }
e3@{ animate: true }
例
- Gateway API で普通に HTTPRoute を設定する
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gw
namespace: app-ns
spec:
gatewayClassName: istio
listeners:
- name: http
protocol: HTTP
port: 80
hostname: example.local
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: route-a
namespace: app-ns
spec:
hostnames:
- example.local
parentRefs:
- name: gw
namespace: app-ns
rules:
- backendRefs:
- kind: Service
name: svc-a
port: 80
weight: 100
---
apiVersion: v1
kind: Service
metadata:
name: svc-a
namespace: app-ns
spec:
selector:
app: a
ports:
- name: http
port: 80
targetPort: 5678
- 上記の HTTPRoute や Service を変更せずに、受け口全体を上書きする producer route(
route-bをapp-nsに配置)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: route-b
namespace: app-ns # 同一NS のため、 producer route です
spec:
parentRefs:
- group: ""
kind: Service
name: svc-a
namespace: app-ns
port: 80
rules:
- backendRefs:
- kind: Service
name: svc-b
namespace: ext-ns # 別NSの宛先へ切替
port: 80
weight: 100
---
apiVersion: v1
kind: Service
metadata:
name: svc-b
namespace: ext-ns
spec:
selector:
app: b
ports:
- name: http
port: 80
targetPort: 5678
上記は producer route(同一 NS を親参照)なので、
svc-aへのすべての受信リクエストに対してroute-bのルールが適用され、宛先がsvc-bに差し替わります(メッシュ実装に依存して適用点はクライアント側になる場合あり)。
ReferenceGrant について補足
GEP-1294 は Mesh(East/West)文脈で、Service を parentRef にした Route から 別 Namespace の backendRefs を参照でき、ReferenceGrant なしで許可される と明記しています:
Routes of either type can send traffic to backendRefs in any namespace. Unlike Gateway bound routes, this is allowed without a ReferenceGrant. In Gateway-bound routes (North-South), routes are opt-in; by default, no Services are exposed (often to the public internet), and a service producer must explicitly opt-in by creating a route themselves, or allowing another namespace to via ReferenceGrant. For mesh, routes augment existing Services, rather than exposing them to a broader scope.
また、アクセス制御については NetworkPolicy 等の仕組みで行うと補足されています:
As a result, a ReferenceGrant is not required in most mesh implementations. Access control, if desired, is handled by other mechanism such as NetworkPolicy
そのため app-ns の producer route から ext-ns の svc-b へ振り分ける本記事の構成は、 ReferenceGrant は不要 です。
まとめ
他のコントローラーが生成したHTTPRouteをカスタマイズできない際に、そのHTTPRouteの参照先をGEP-1294を使う事で変更し、まるでHTTPRouteへ追加の設定を記述した際と同じ結果を得る方法を紹介しました。
これが何かの参考になればと思います。
参考リンク
- Route presence: https://gateway-api.sigs.k8s.io/geps/gep-1294/#route-presence
- Namespace boundaries(producer / consumer の境界): https://gateway-api.sigs.k8s.io/geps/gep-1294/#namespace-boundaries


