Kubernetes v1.33:映象拉取策略如你所願!

映象拉取策略終於如你所願!

Kubernetes 中的有些事情令人驚訝,imagePullPolicy 的行為方式可能就是其中之一。鑑於 Kubernetes 的核心是執行 Pod,你可能會覺得奇怪,10 多年來,以 issue 18787 的形式存在的、限制 Pod 訪問需身份驗證的映象一直存在一個警告!當你能夠解決一個存在了十年的問題時,這真是一個激動人心的版本。

即使我不該擁有它,也要 IfNotPresent

問題的癥結在於 imagePullPolicy: IfNotPresent 策略只做了它所說的,僅此而已。讓我們設定一個場景。首先,位於 Namespace X 中的 Pod A 被排程到 Node 1,並需要來自私有倉庫的 image Foo。對於其映象拉取身份驗證材料,該 Pod 在其 imagePullSecrets 中引用了 Secret 1Secret 1 包含從私有倉庫拉取所需的憑據。Kubelet 將利用 Pod A 提供的 Secret 1 中的憑據,並從映象倉庫拉取 container image Foo。這是預期的(也是安全的)行為。

但現在事情變得奇怪了。如果位於 Namespace Y 中的 Pod B 恰好也被排程到 Node 1,就會發生意想不到的(並且可能不安全的)事情。Pod B 可能引用了相同的私有映象,指定了 IfNotPresent 映象拉取策略。Pod B 在其 imagePullSecrets 中沒有引用 Secret 1(或者在我們的例子中,任何 Secret)。當 Kubelet 嘗試執行該 Pod 時,它會遵循 IfNotPresent 策略。Kubelet 看到 image Foo 已經本地存在,就會將 image Foo 提供給 Pod BPod B 得以執行該映象,儘管它一開始並未提供授權其拉取該映象的憑據。

Illustration of the process of two pods trying to access a private image, the first one with a pull secret, the second one without it

使用由不同 Pod 拉取的私有映象

雖然 IfNotPresentimage Foo 已經存在於節點上時不應該拉取它,但允許排程到節點上的所有 Pod 訪問先前拉取的私有映象是一種不正確的安全態勢。這些 Pod 從未被授權拉取該映象。

IfNotPresent,但前提是我應該擁有它

在 Kubernetes v1.33 中,我們 —— SIG Auth 和 SIG Node —— 終於開始著手解決這個(非常古老)的問題,並確保驗證的正確性!基本的預期行為沒有改變。如果映象不存在,Kubelet 將嘗試拉取映象。每個 Pod 提供的憑據將用於此任務。這與 1.33 之前的行為一致。

如果映象存在,那麼 Kubelet 的行為會發生變化。Kubelet 現在將在允許 Pod 使用該映象之前驗證 Pod 的憑據。

在修訂此功能時,效能和服務穩定性一直是考慮的因素。使用相同憑據的 Pod 不需要重新進行身份驗證。當 Pod 從同一個 Kubernetes Secret 物件中獲取憑據時,即使憑據被輪換,情況也是如此。

永不拉取,但若已授權則使用

imagePullPolicy: Never 選項不會獲取映象。但是,如果容器映象已經存在於節點上,任何試圖使用私有映象的 Pod 都需要提供憑據,並且這些憑據需要驗證。

使用相同憑據的 Pod 不需要重新進行身份驗證。未提供先前用於成功拉取映象的憑據的 Pod 將不被允許使用私有映象。

如果已授權,則始終拉取

imagePullPolicy: Always 一直都按預期工作。每次請求映象時,請求都會發送到映象倉庫,映象倉庫將執行身份驗證檢查。

過去,透過 Pod 准入強制使用 Always 映象拉取策略是確保你的私有容器映象不會被已經拉取了這些映象的節點上的其他 Pod 重複使用的唯一方法。

幸運的是,這在某種程度上是高效的。只拉取映象清單,而不是映象本身。然而,仍然存在成本和風險。在新的釋出、擴容或 Pod 重啟期間,提供映象的映象倉庫必須可用以進行身份驗證檢查,這使得映象倉庫處於叢集內執行服務穩定性的關鍵路徑上。

它是如何工作的

該功能基於存在於每個節點上的永續性、基於檔案的快取。以下是該功能工作原理的簡化描述。有關完整版本,請參閱 KEP-2535

首次請求映象的過程如下

  1. 請求來自私有倉庫的映象的 Pod 被排程到一個節點上。
  2. 映象在節點上不存在。
  3. Kubelet 記錄下準備拉取映象的意圖。
  4. Kubelet 從 Pod 作為映象拉取 Secret 引用的 Kubernetes Secret 中提取憑據,並使用它們從私有倉庫中拉取映象。
  5. 映象成功拉取後,Kubelet 記錄成功的拉取。該記錄包括所用憑據的詳細資訊(以雜湊形式)以及它們來自的 Secret。
  6. Kubelet 刪除原始的意圖記錄。
  7. Kubelet 保留成功拉取的記錄以備後用。

當將來排程到同一節點的 Pod 請求先前拉取的私有映象時

  1. Kubelet 檢查新 Pod 為拉取提供的憑據。
  2. 如果這些憑據的雜湊值或憑據的源 Secret 與先前成功拉取記錄的雜湊值或源 Secret 匹配,則允許該 Pod 使用先前拉取的映象。
  3. 如果在該映象的成功拉取記錄中未找到憑據或其源 Secret,Kubelet 將嘗試使用這些新憑據向遠端倉庫請求拉取,從而觸發授權流程。

立即試用

在 Kubernetes v1.33 中,我們釋出了此功能的 Alpha 版本。要試用它,請為你的 1.33 Kubelet 啟用 KubeletEnsureSecretPulledImages 特性門控。

你可以在 Kubernetes 官方文件的“映象”概念頁面上了解有關該功能和其他可選配置的更多資訊。

接下來是什麼?

在未來的版本中,我們計劃:

  1. 使此功能與用於 Kubelet 映象憑據提供程式的投射服務賬號令牌協同工作,這將增加一個新的、特定於工作負載的映象拉取憑據來源。
  2. 編寫一個基準測試套件,以衡量此功能的效能並評估未來任何更改的影響。
  3. 實現一個記憶體快取層,這樣我們就不需要為每個映象拉取請求讀取檔案。
  4. 增加對憑據過期的支援,從而強制重新驗證先前已驗證的憑據。

如何參與

閱讀 KEP-2535 是深入瞭解這些變化的好方法。

如果你有興趣進一步參與,請在 Kubernetes Slack 的 #sig-auth-authenticators-dev 頻道上與我們聯絡(如需邀請,請訪問 https://slack.k8s.io/)。也歡迎你參加每兩週一次的 SIG Auth 會議,會議在每隔一個星期三舉行。