如何用 Kubernetes PartialObjectMetadata 降低控制器讀取成本?
題目與背景
一個控制器只需要物件名稱、標籤、命名空間和 resourceVersion,卻要讀取大量 Pod 的完整 spec 與 status。請使用 Kubernetes 的 metadata-only 內容協商設計列表請求,並說明不支援部分回應的聚合 API、406 錯誤和後續 watch 如何處理。
面試官考察什麼
- 能否正確構造
Accept參數並區分單一物件與列表表示。 - 能否理解部分回應不是欄位過濾補丁,而是另一種 API 表示。
- 能否設計 406、版本相容和完整物件回退,避免控制器啟動失敗。
- 能否保持 list/watch 的
resourceVersion和快取一致性。
先問清楚的澄清問題
資源與伺服器邊界
目標資源是內建 API、CRD 還是聚合 API?所有 apiserver 和代理是否支援 metadata-only 表示?
使用模式
用戶端只做存在性和標籤索引,還是之後仍要讀取物件 spec?需要 list 後立即 watch 嗎?
失敗策略
部分回應不可用時允許讀取完整物件,還是必須明確失敗以保護頻寬和記憶體預算?
30 秒回答框架
我會為列表請求使用 application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,只接收 metadata 和列表的 resourceVersion。在 Accept 中加入較低品質的 application/json 作為回退,客戶端根據回應 kind 判斷實際表示;若沒有回退則把 406 視為能力不支援,而非重試風暴。list 成功後用回傳的 resourceVersion 建立 watch,並為快取記錄表示類型。
深入解答步驟
1. 區分兩種表示
單物件請求使用 as=PartialObjectMetadata,集合請求使用 as=PartialObjectMetadataList。回傳物件的 spec 和 status 被省略,只保留 metadata;這減少序列化、網路和用戶端解碼成本,但不能滿足需要業務欄位的呼叫方。
2. 構造帶回退的請求
GET /api/v1/pods
Accept: application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1, application/json;q=0.9首選表示不可用時,伺服器可以選擇一般 JSON。用戶端必須檢查回應的 kind、apiVersion 和 Content-Type,不能因為 HTTP 200 就假設拿到部分物件。
3. 處理嚴格模式與 406
若 Accept 只宣告部分表示,而目標 API 不支援,Kubernetes 回傳 406。控制器應把 406 記錄為能力探測結果,按策略切換完整物件、跳過該資源或提示設定錯誤;不能無限重試相同 Accept,也不能把 406 當作暫時網路故障。
4. 處理聚合 API 和 CRD
內建 API 通常支援 metadata-only,但聚合層後的 API 可能不支援。CRD 或第三方 API 的實作也可能只提供完整物件。啟動時可按資源和伺服器分組探測能力,快取結果並設定過期時間;不要把一個資源的成功能力推廣到所有資源。
5. 保持 list/watch 一致
列表回應中的 resourceVersion 仍是後續 watch 的起點。用戶端要保存它,並處理 watch 過期、斷開和重新 list。metadata-only 只改變物件表示,不改變資源版本語義;回退到完整物件時也要用同一版本建立快取,避免混入舊資料。
6. 設計快取與升級
快取項目應標記表示類型和欄位可用性。需要 spec 的路徑不能讀取 metadata-only 項目後假設欄位存在,而應按名稱發起完整 GET。升級伺服器或代理後重新探測 Accept 能力,避免長期保留不必要的完整物件路徑。
7. 衡量成本和安全性
比較請求位元組數、解碼 CPU、堆峰值、list 延遲、watch 重連率和完整 GET 比例。標籤、註解和 ownerReferences 仍可能包含敏感資訊,權限檢查不會因只回傳 metadata 而消失;日誌和指標也不應直接輸出全部註解。
高品質示例回答
我會為列表首選 PartialObjectMetadataList,並以較低品質的一般 JSON 作為回退。用戶端根據回應 kind 驗證實際表示,406 只觸發一次能力切換。保存返回的 resourceVersion 建立 watch,快取記錄欄位能力;聚合 API、CRD 和需要 spec 的路徑分別探測與讀取,最後用位元組、CPU、記憶體和重連指標證明收益。
常見錯誤
- 對列表使用單物件的
PartialObjectMetadata參數。 - 以為 metadata-only 是伺服器任意欄位過濾,忽略回傳 kind。
- 沒有回退就把 406 當成可重試的 5xx。
- 將內建資源的能力假設推廣到聚合 API 或所有 CRD。
- 丟棄 list 的
resourceVersion,重新 watch 時從錯誤位置開始。 - 只測回應大小,不測解碼 CPU、堆峰值和重連成本。
追問與回答
為什麼列表要使用 PartialObjectMetadataList?
集合請求返回的是列表表示,PartialObjectMetadataList 明確表示每個項目只有 metadata。單物件表示用於單一 GET;兩者不能混用後再靠用戶端猜測。
伺服器不支援部分回應時怎麼辦?
Accept 同時宣告一般 JSON 回退時,檢查回應 kind 後使用完整物件;嚴格模式則把 406 記錄為能力缺失並按資源策略跳過或報錯。不要無限重試同一請求。
metadata-only 會改變 resourceVersion 嗎?
不會。它改變物件表示,不改變資源版本語義。list 返回的版本仍用於後續 watch 和快取一致性。
CRD 都支援這種請求嗎?
不能假設。聚合 API 和 CRD 可能不支援部分表示,啟動時應按資源探測並快取能力。
什麼時候必須讀完整物件?
需要 spec、status 或業務欄位進行決策時,metadata-only 不足。此時先用 metadata 建立索引,再按名稱或事件觸發受控的完整 GET。