本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.31:基於 OCI 製品的只讀卷(Alpha)

Kubernetes 社群正在朝著未來滿足更多人工智慧(AI)和機器學習(ML)用例的方向發展。雖然該專案過去一直被設計用於滿足微服務架構,但現在是時候傾聽終端使用者的聲音,並引入更專注於 AI/ML 的特性了。

其中一項需求是直接將相容開放容器倡議(OCI)的映象和製品(稱為 OCI 物件)作為原生捲來源來支援。這允許使用者專注於 OCI 標準,並使他們能夠使用 OCI 映象庫來儲存和分發任何內容。這樣的功能為 Kubernetes 專案提供了機會,使其能夠發展到超越執行特定映象的用例中。

鑑於此,Kubernetes 社群自豪地推出在 v1.31 中引入的一個新的 Alpha 特性:映象捲來源(Image Volume Source)(KEP-4639)。該特性允許使用者在 Pod 中將映象引用指定為卷,同時在容器內將其作為卷掛載來重用。


kind: Pod
spec:
  containers:
    - …
      volumeMounts:
        - name: my-volume
          mountPath: /path/to/directory
  volumes:
    - name: my-volume
      image:
        reference: my-image:tag

上面的示例將導致把 my-image:tag 掛載到 Pod 容器中的 /path/to/directory

使用場景

此增強功能的目標是儘可能地貼近 kubelet 內現有的容器映象實現,同時引入新的 API 介面以支援更廣泛的用例。

例如,使用者可以在 Pod 中的多個容器之間共享一個配置檔案,而無需將該檔案包含在主映象中,這樣他們就可以最大限度地降低安全風險並減小整體映象大小。他們還可以使用 OCI 映象打包和分發二進位制製品,並將其直接掛載到 Kubernetes Pod 中,以此來簡化他們的 CI/CD 流水線。

資料科學家、MLOps 工程師或 AI 開發者可以在 Pod 中將大語言模型權重或機器學習模型權重與模型伺服器一起掛載,從而可以高效地提供服務,而無需將它們包含在模型伺服器的容器映象中。他們可以將這些權重打包成 OCI 物件,以利用 OCI 的分發能力,確保高效的模型部署。這使他們能夠將模型規約/內容與處理它們的可執行檔案分離開來。

另一個用例是,安全工程師可以使用一個公開的惡意軟體掃描器映象,並掛載一個包含私有(商業)惡意軟體簽名的卷,這樣他們就可以載入這些簽名,而無需構建自己的組合映象(這可能不被公開映象的版權所允許)。這些檔案無論掃描軟體的作業系統或版本如何都能正常工作。

但從長遠來看,將由作為這個專案的終端使用者來勾勒出這個新功能的更多重要用例。SIG Node 很高興收到任何反饋或建議,以進行進一步增強,從而支援更高階的使用場景。歡迎透過 Kubernetes Slack(#sig-node) 頻道或 SIG Node 郵件列表提供反饋。

詳細示例

要使其功能正常,需要在 API Server 以及 kubelet 上啟用 Kubernetes Alpha 特性門控 ImageVolume。如果已啟用,並且容器執行時支援該特性(例如 CRI-O ≥ v1.31),那麼可以建立一個像這樣的示例 pod.yaml 檔案:

apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: test
      image: registry.k8s.io/e2e-test-images/echoserver:2.3
      volumeMounts:
        - name: volume
          mountPath: /volume
  volumes:
    - name: volume
      image:
        reference: quay.io/crio/artifact:v1
        pullPolicy: IfNotPresent

該 Pod 使用 image.referencequay.io/crio/artifact:v1 聲明瞭一個新卷,該引用指向一個包含兩個檔案的 OCI 物件。pullPolicy 的行為與容器映象相同,並允許以下值:

  • Always:kubelet 總是嘗試拉取該引用,如果拉取失敗,容器建立將失敗。
  • Never:kubelet 從不拉取該引用,只使用本地映象或製品。如果該引用不存在,容器建立將失敗。
  • IfNotPresent:如果該引用在磁碟上尚不存在,kubelet 就會拉取。如果該引用不存在且拉取失敗,容器建立將失敗。

volumeMounts 欄位指示名為 test 的容器應將該卷掛載到路徑 /volume 下。

現在,如果你建立這個 Pod:

kubectl apply -f pod.yaml

然後進入它的 shell:

kubectl exec -it pod -- sh

你就可以檢視已掛載的內容:

/ # ls /volume
dir   file
/ # cat /volume/file
2
/ # ls /volume/dir
file
/ # cat /volume/dir/file
1

你已成功使用 Kubernetes 消費了一個 OCI 製品!

容器執行時會拉取映象(或製品),將其掛載到容器中,並最終使其可供直接使用。實現中有許多細節,與 kubelet 現有的映象拉取行為緊密對齊。例如:

  • 如果提供了 :latest 標籤作為 reference,那麼 pullPolicy 將預設為 Always,而在任何其他情況下,如果未設定,則預設為 IfNotPresent
  • 如果 Pod 被刪除並重新建立,卷將被重新解析,這意味著新的遠端內容將在 Pod 重新建立時變得可用。在 Pod 啟動期間解析或拉取映象失敗將阻止容器啟動,並可能增加顯著的延遲。失敗將使用正常的捲回退機制進行重試,並將在 Pod 的 reason 和 message 中報告。
  • 拉取 Secret 將以與容器映象相同的方式組裝,即查詢節點憑據、服務賬號的 image pull secret 以及 Pod 規約中的 image pull secret。
  • OCI 物件透過合併清單層的方式掛載到單個目錄中,這與容器映象的處理方式相同。
  • 卷以只讀(ro)和非可執行檔案(noexec)的方式掛載。
  • 不支援容器的子路徑掛載(spec.containers[*].volumeMounts.subpath)。
  • 欄位 spec.securityContext.fsGroupChangePolicy 對此卷型別沒有影響。
  • 如果啟用,該功能也將與 AlwaysPullImages 准入外掛一起工作。

感謝你閱讀完這篇部落格文章!SIG Node 很自豪也很高興能將此功能作為 Kubernetes v1.31 的一部分交付。

作為這篇部落格文章的作者,我想特別感謝所有參與其中的個人!你們都太棒了,讓我們繼續努力!

進一步閱讀