Envoy Gateway Listener 設計ガイド: 複数 Port、複数 Hostname、複数 Ingress パターン
Gateway API を学び始めた人の多くは、Listener を「まあ port: 80 の field だよね」くらいに見がちです。
でも実運用では Listener は端役どころか、入口層全体の traffic control center に近い存在です。
listener は単に port を開けるだけではありません。次を定義します。
- どの protocol を受けるか
- どの hostname を受けるか
- TLS を行うか
- どの route type を attach 可能にするか
つまり listener は ingress 契約 です。契約をきれいに書けば、下流の route、チーム分担、デバッグ難易度まで連鎖的にきれいになります。
正しいメンタルモデルを作る: 1 Listener = 1 Ingress Slot
次の Gateway を見てください。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
hostname: app.example.com
tls:
mode: Terminate
certificateRefs:
- name: app-cert
- name: grpc
protocol: HTTPS
port: 8443
hostname: grpc.example.com
tls:
mode: Terminate
certificateRefs:
- name: grpc-certこれは「穴が 3 つある Gateway」ではありません。むしろ次のように考えます。
httplistener: 平文 HTTP 用httpslistener:app.example.com用grpclistener: gRPC service 専用の入口スロット
こう捉えると、多くの設計判断がすぐ明確になります。 YAML を組み立てているのではなく、入口の境界を設計しているのです。
よくある 3 つの分割パターン
Pattern 1: Protocol で分ける
最も直感的なやり方です。
- HTTP は 1 listener
- HTTPS は 1 listener
- gRPC は 1 listener
- TCP/TLS passthrough は別で分ける
責務がはっきりします。 gRPC と通常の web API はどちらも HTTP/2 上に乗ることがありますが、service モデルは異なります。分けておくことで route の干渉を防ぎやすくなります。
Pattern 2: Hostname で分ける
複数 domain があるなら、主要 hostname ごとに 1 listener というパターンがよく使われます。
listeners:
- name: app
hostname: app.example.com
protocol: HTTPS
port: 443
- name: admin
hostname: admin.example.com
protocol: HTTPS
port: 443これは次に向いています。
- 公開系と管理系のガバナンス分離
- hostname ごとに別証明書が必要
- route の attach 境界を明確に保つ
Pattern 3: Team または環境責務で分ける
複数 team 構成では、listener 自体を governance 境界として使えます。
public-apiは外部向け product trafficinternal-apiは内部システム向けpartner-apiは partner 連携向け
ここで listener の価値は技術設定を超え、権限と責任の境界になります。 中規模以上の team では特に効きます。誰でも何でも attach できる「1 つの巨大 ingress」の事故を減らせます。
sectionName と allowedRoutes: 重要な 2 field
route は parentRefs.sectionName で特定 listener に attach します。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
spec:
parentRefs:
- name: eg
sectionName: https
hostnames:
- "app.example.com"
rules:
- backendRefs:
- name: app-service
port: 8080この route は https listener だけを探します。
sectionName を指定しない場合は attach 可能な listener を探すためのルールが働きますが、複数 listener がある構成では明示したほうがほぼ安全です。
もう一つの重要 field が allowedRoutes です。
listeners:
- name: public
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: Sameこれは、Gateway と同じ namespace にある route だけが attach できることを意味します。
代表的な値:
Same: 同じ namespace のみAll: どの namespace でも可Selector: label selector に合う namespace のみ
platform 境界を意図的に作りたいなら、この field はかなり強力です。 「誰がこの ingress に attach できるか」を listener レベルで決められます。
実践アドバイス: 後悔しない Listener 構造
かなり役立つ原則が一つあります。
各 listener には、1 つの明確な責務だけを持たせる。
たとえば:
- 1 listener は 1 つの主要 hostname 群に対応する
- 1 listener は 1 つの主要 protocol type を扱う
- 1 listener は 1 つの route type、または固定された namespace 群に開く
すべての traffic を万能 listener 1 個に詰め込んで、下流で route が自動的に整理されることを期待しないでください。 最初は効率的に見えても、3 か月後にはどの家にもある謎ケーブル引き出しみたいになります。全部入っているのに、何も見つかりません。
具体的な提案:
- Listener 名は意味を持たせる:
https-public,grpc-internal - 複数 listener 構成では必ず
sectionNameとセットで使う - 重要な hostname を 1 listener に混ぜ込まない
allowedRoutesはまず制限寄りに始める。最初からfrom: Allにしない
一文まとめ
Listener は単なる port 設定ではなく ingress 契約として扱ってください。
listener 境界がきれいだと、route は正しく attach し、team は自然に担当範囲を持ち、デバッグも迷路で猫を追いかける感じがかなり減ります。
次の一歩
listener 設計が整理できたら、次によく出る疑問はこれです。 namespace が分かれた複数 team 環境で、誰が route を attach できて、誰が何を参照できるのか?
次の記事では cross-namespace パターンと ownership を扱います。 👉 複数 namespace とチーム分担