具代表性的面試主題

系統設計面試:如何用 Kubernetes Gateway API ListenerSet 支援多租戶入口?

系統設計困難
Offer.cc 編輯團隊發佈 更新

題幹

請設計一個共用 Kubernetes Gateway:平台團隊維護底層負載平衡,多個應用團隊獨立提交 hostname、連接埠、路由與 TLS 憑證。要求避免互相覆蓋、支援約 1000 個網域、保留狀態可觀測性,並說明 ListenerSet、授權、衝突、擴展與故障處理。

題幹與適用場景

請設計一個共用 Kubernetes Gateway。平台團隊負責 Gateway 與負載平衡基礎設施,應用團隊在各自命名空間維護入口 hostname、連接埠、HTTPRoute 與憑證。目標規模約 20 個團隊、每隊 50 個 listener,也就是約 1000 個網域;單一 Gateway 的基礎 listener 上限按 64 估算。

回答要解釋如何把 listener 從巨大的 Gateway 物件拆到多個 ListenerSet,如何授權跨命名空間附加,如何在衝突時保持流量穩定,以及控制器如何透過 status 讓團隊知道設定是否 Accepted、Programmed 或 Conflicted。

面試官考察點

資源邊界與委派

高品質回答會把共用基礎設施、租戶設定與路由繫結分開,說明為什麼應用團隊不能直接編輯平台 Gateway。

衝突與安全預設值

候選人應說清楚預設拒絕 ListenerSet、允許的命名空間來源、相同 hostname 的確定性優先級與憑證參照邊界。

控制器一致性

要涵蓋 watch、合併、驗證、狀態條件與重試,不能只寫一份 YAML 就假設資料面立即生效。

可擴展性與遷移

需要比較一個 Gateway、每租戶一個 Gateway、Ingress 註解等替代方案,並解釋何時 ListenerSet 的複雜度值得承擔。

回答前需要釐清的問題

  • 1000 個網域是否共用一個負載平衡位址,還是每個團隊需要獨立入口?
  • 應用團隊能否管理自己的 TLS Secret,平台是否保留憑證審批權?
  • 跨命名空間附加是允許全部命名空間、標籤選擇,還是只允許同命名空間?
  • 發生衝突時要求舊設定繼續服務,還是允許新設定搶占?
  • 控制器需要多快反映設定,是否要求跨叢集複製?
  • HTTPRoute、TLSRoute 與其他 Route 類型的授權邊界是否相同?

30 秒回答框架

「我讓平台團隊建立 Gateway,並預設禁止 ListenerSet;透過 allowedListeners 明確允許的命名空間範圍。每個應用團隊在自己的命名空間提交 ListenerSet 與 Route,控制器先驗證 ParentRef、hostname、連接埠、協定、憑證參照與 AllowedRoutes,再按 Gateway 優先、建立時間較早、namespace/name 字典序的規則合併。衝突物件標記 Accepted=False、Conflicted=True,不能取代已生效的 listener。資料面只由控制器從合併後的期望狀態編程,狀態條件與指標讓租戶能區分拒絕、衝突、未編程與已生效。」

分步驟深入解答

第一步:估算規模並選擇資源模型

20 個團隊乘以每隊 50 個 listener 約為 1000 個入口。把 1000 條設定塞進一個 Gateway 會造成單物件寫入競爭、權限過寬與控制器重算;ListenerSet 把每隊設定拆成獨立資源,Gateway 只保留平台級位址、類別與允許附加的策略。

第二步:建立授權握手

Gateway 的 allowedListeners 是安全門。預設 None 表示不接受任何 ListenerSet;平台可以選擇 Same、標籤 SelectorAll。ListenerSet 用 parentRef 指向 Gateway,控制器只有在兩端授權、參照有效且物件被允許時才進入合併集合。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
spec:
  allowedListeners:
    namespaces:
      from: Selector
      selector:
        matchLabels:
          gateway-access: shared
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
  name: team-a-listeners
  namespace: team-a
spec:
  parentRef:
    name: shared-gateway
    namespace: platform
  listeners:
  - name: app-a
    hostname: app-a.example.com
    protocol: HTTPS
    port: 443

第三步:定義合併與衝突規則

先把 Gateway 自帶 listeners 與獲授權的 ListenerSet 拼成候選集合,再按連接埠、協定與適用 hostname 判斷是否為同一 listener。衝突優先級固定為:父 Gateway 優先;然後 ListenerSet 建立時間較早者優先;仍相同則按 namespace/name 字典序。失敗者寫入 Conflicted,不能靜默覆蓋現有流量。

第四步:隔離路由與憑證

ListenerSet 的 allowedRoutes 限制哪些命名空間可以綁定 Route;Route 透過 parentRefs 指向 ListenerSet 的特定 section。TLS Secret 由平台策略限制參照範圍,憑證審批與應用發布權限分開。應用團隊只能修改自己的 ListenerSet 與 Secret,不能借 ParentRef 讀取其他租戶資源。

第五步:讓控制器可收斂

控制器 watch Gateway、ListenerSet、Route、Namespace 標籤與 Secret,產生按 Gateway 分組的期望模型。每次事件做去重與短暫防抖,驗證通過後再編程負載平衡。status 回傳 Accepted、Programmed、ResolvedRefs 與 Conflicted 條件;重試必須冪等,舊期望狀態保留到新設定成功編程。

第六步:比較替代方案與故障路徑

每租戶一個 Gateway 能簡化權限,卻增加位址、負載平衡與憑證成本;單 Gateway 加註解便宜,但缺少統一 schema、衝突語意與跨實作互通性。ListenerSet 控制面不可用時保留最後一次 Programmed 設定,拒絕未知新 listener;平台 Gateway 刪除或 ParentRef 失效時把子資源標記為未接受,恢復後重新收斂。

高品質示範回答

「我會把 Gateway 當作平台擁有的共用邊界,把 ListenerSet 當作租戶擁有的宣告。平台先設定 GatewayClass、位址與 allowedListeners,預設不允許任何附加;只有帶有 gateway-access=shared 標籤的命名空間可以引用它。每隊提交自己的 ListenerSet、HTTPRoute 與憑證參照。

控制器收到事件後,先驗證 ParentRef、命名空間授權、連接埠/協定/hostname、AllowedRoutes 與 Secret 參照,再把 listener 合併。父 Gateway 優先,之後按 ListenerSet 建立時間與 namespace/name 解決衝突;輸家標記 Accepted=False、Conflicted=True,不奪走已運行的設定。合併成功後才更新負載平衡,Programmed 狀態表示資料面已生效。

按 20 隊乘 50 條約 1000 個 listener,拆分資源可避免單物件寫入競爭與權限集中。控制器不可用時繼續服務最後的穩定快照,新的衝突設定不進入資料面。若租戶需要完全獨立的位址、合規域或故障域,我會改用多個 Gateway,接受較高基礎設施成本。」

常見錯誤

  • 讓所有團隊直接編輯 Gateway → 設定互相覆蓋且權限過大 → Gateway 歸平台,ListenerSet 按命名空間委派。
  • 預設允許全部命名空間 → 任意租戶可申請共用入口 → 預設 None,再用 Same 或 Selector 收窄範圍。
  • 讓新 listener 最後寫入即生效 → 新設定可能劫持舊網域 → 使用確定性優先級並將輸家標記衝突。
  • 只檢查 hostname 不檢查連接埠與協定 → 不同協定仍可能撞在同一入口 → 以連接埠、協定與適用 hostname 共同判定。
  • 直接把 Secret 名稱交給資料面 → 跨命名空間越權或憑證洩露 → 通過參照授權和控制器驗證後再編程。
  • 收到事件就立即改負載平衡 → 短暫非法狀態造成抖動 → 防抖、冪等合併、成功後切換並保留舊快照。
  • status 只寫 Ready → 租戶無法區分拒絕、衝突與未編程 → 使用 Accepted、Programmed、ResolvedRefs、Conflicted 條件。
  • 把 ListenerSet 當作無限擴展 → 控制器和負載平衡仍有容量瓶頸 → 按 Gateway 分片、限制每租戶配額並監測收斂延遲。

追問及應對

追問一:兩個團隊提交相同 hostname 和連接埠,誰贏?

父 Gateway 優先;兩個 ListenerSet 衝突時建立時間較早者優先,仍相同按 namespace/name 字典序。輸家保持可見但標記 Conflicted,不能用重試時間改變結果。

追問二:平台想暫時凍結一個租戶,怎麼做?

移除其命名空間標籤或縮小 allowedListeners 選擇器,控制器會讓該 ListenerSet 變為未接受並保留最後快照。凍結動作寫入稽核記錄,恢復時重新驗證而不是直接信任舊物件。

追問三:一個 ListenerSet 有 64 條 listener,還能繼續擴展嗎?

單個 ListenerSet 自身仍要遵守實作限制,不能把總量當成無限。把租戶拆成多個 ListenerSet、按 Gateway 分片,並為每個分片設定配額;如果位址或憑證隔離更重要,則改用多個 Gateway。

追問四:憑證 Secret 更新時如何避免中斷?

監聽 Secret 版本並先驗證憑證鏈、hostname 與有效期;在資料面確認新憑證已編程後再更新 Programmed。舊憑證在寬限視窗內保留,失敗則繼續使用已知良好版本並告警。

追問五:控制器重啟期間新 Route 會不會覆蓋舊流量?

不會。控制器持久化或重建期望狀態,資料面繼續使用最後成功快照;重啟後先完整重算、驗證衝突與參照,再以一次可觀察的版本切換。

來源一:Gateway API ListenerSet 使用指南

使用指南定義 ListenerSet 的多租戶委派用途、64 條 listener 限制、allowedListeners、parentRef 與衝突優先級。本文的資源模型、授權握手、衝突處理與狀態設計據此展開。

來源二:GEP-1713

GEP-1713 說明 ListenerSet 解決共用 Gateway 的資源爭用、跨命名空間管理與大規模網域場景,並給出父 Gateway、建立時間與字典序的合併規則。本文的容量估算與替代方案比較以此為約束。

來源三:Kubernetes Gateway API v1.5 發布說明

發布說明記錄 ListenerSet 進入 Standard,並說明它針對多租戶、委派 listener 與超過 64 條 listener 的場景。本文把這些公開變更轉化為面試中的遷移與治理問題。

來源四:系統設計面試公開指南

公開面試指南強調先釐清需求、討論擴展和故障、解釋取捨。本文的釐清問題、估算、衝突追問與替代方案用於訓練這些可觀察的答題訊號。

公開來源

同類題目

相關面試工具

用 Solve 整理系統設計回答

從澄清需求開始,展開規模、架構、元件選擇和取捨。

查看工具