Envoy Gateway Listener 設計指南:多 Port、多 Hostname、多入口怎麼拆
很多人學 Gateway API 時,Listener 只停留在「喔,就是 port: 80 那個欄位」。
但實戰裡,Listener 根本不是小配角,它比較像你整個入口層的交通管制中心。
一個 listener 不只是開一個 port,它其實在定義:
- 接哪種協定
- 接哪個 hostname
- 要不要做 TLS
- 允許哪類 route 附掛
也就是說,listener 其實是一份入口合約。你合約切得清楚,後面的 route、團隊分工、除錯成本就會跟著一起變乾淨。
先建立正確觀念:一個 Listener = 一個入口插槽
例如這個 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這不是「一個 Gateway 開三個洞」而已,實際上更像:
httplistener:給明文 HTTPhttpslistener:給app.example.comgrpclistener:給 gRPC 服務專用入口
當你這樣想,很多設計判斷會瞬間清楚。
你不是在拼 YAML,而是在設計入口邊界。
三種最常見的拆法
拆法 1:按協定拆
這是最直覺的做法:
- HTTP 一個 listener
- HTTPS 一個 listener
- gRPC 一個 listener
- TCP/TLS passthrough 另外拆
優點是責任清楚。
尤其 gRPC 和一般 Web API 雖然都可能走 HTTP/2,但服務模型不同,拆開後 route 比較不會打架。
拆法 2:按 hostname 拆
如果你有多個網域,常見做法是每個主要 hostname 各自一個 listener:
listeners:
- name: app
hostname: app.example.com
protocol: HTTPS
port: 443
- name: admin
hostname: admin.example.com
protocol: HTTPS
port: 443這種方式很適合:
- 主站和後台要分開治理
- 不同 hostname 用不同憑證
- 想把 route 附掛範圍切乾淨
拆法 3:按團隊或環境責任拆
如果你是多人協作,listener 也可以當治理邊界:
public-api給外部產品流量internal-api給內部系統partner-api給合作夥伴
這時 listener 的價值就不只是技術設定,而是權限與責任邊界。
這種拆法在中大型團隊超有感,因為它可以減少「一個入口 everyone 都能亂掛」的災難。
sectionName 與 allowedRoutes:兩個超關鍵欄位
Route 要掛到哪個 listener,通常靠 parentRefs.sectionName:
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。
如果你不指定,系統會根據規則去找可附掛的 listener,但多 listener 場景下,明確指定通常比較不容易出事。
另一個很重要的是 allowedRoutes:
listeners:
- name: public
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: Same這代表只有跟 Gateway 同 namespace 的 route 才能附掛。
常見值有:
Same:只允許同 namespaceAll:所有 namespace 都能來掛Selector:只允許符合 label selector 的 namespace
如果你的平台邊界想清楚,這個欄位真的超香。
它等於在 listener 層就先決定「誰可以來接這個入口」。
實戰建議:怎麼拆比較不會後悔
先給你一句很實用的原則:
一個 listener 只承擔一種清楚責任。
例如:
- 一個 listener 只服務一組主要 hostname
- 一個 listener 只負責一種主要協定
- 一個 listener 只開放給一種 route 類型或一群固定 namespace
不要把所有流量都塞進一個萬能 listener,再期待後面 route 自己長出秩序。
那種設計一開始看起來省事,三個月後通常會像家裡抽屜裡那包不知道哪來的線材,什麼都在、什麼都亂。
幾個具體建議:
- listener 名稱要有語意,像
https-public、grpc-internal - 多 listener 場景盡量搭配
sectionName - 重要 hostname 不要全混在同一個 listener
- 預設先收斂
allowedRoutes,不要一開始就from: All
一句話總結
把 Listener 當成入口合約,不要當成單純 port 設定。
你把 listener 切得乾淨,route 才會掛得準,團隊分工才會自然,除錯時也比較不會像在迷宮裡追貓。
下一步
Listener 設計完,下一個問題通常就是:
不同 namespace、不同團隊,到底誰能掛 route、誰能引用誰?
下一篇來講跨 namespace 與權限分工: 👉 多 Namespace 與團隊分工