映像檔
容器映像檔代表封裝應用程式及其所有軟體依賴項的二進位資料。容器映像檔是可以獨立執行的可執行軟體套件,並且對其執行期環境做出非常明確的假設。
您通常會建立應用程式的容器映像檔,並將其推送至登錄檔,然後在 Pod 中參考它。
本頁概述容器映像檔概念。
注意
如果您正在尋找 Kubernetes 發行版本(例如 v1.32,最新的次要版本)的容器映像檔,請造訪下載 Kubernetes。映像檔名稱
容器映像檔通常會給定一個名稱,例如 pause
、example/mycontainer
或 kube-apiserver
。映像檔也可以包含登錄檔主機名稱;例如:fictional.registry.example/imagename
,以及可能的連接埠號碼;例如:fictional.registry.example:10443/imagename
。
如果您未指定登錄檔主機名稱,Kubernetes 會假設您指的是 Docker 公用登錄檔。您可以透過在容器執行期組態中設定預設映像檔登錄檔來變更此行為。
在映像檔名稱部分之後,您可以新增標籤或摘要(與您在使用 docker
或 podman
等指令時的方式相同)。標籤可讓您識別同一系列映像檔的不同版本。摘要是映像檔特定版本的唯一識別碼。摘要是映像檔內容的雜湊值,並且是不可變的。標籤可以移動以指向不同的映像檔,但摘要是固定的。
映像檔標籤包含小寫與大寫字母、數字、底線 (_
)、句點 (.
) 與破折號 (-
)。長度最多可達 128 個字元。並且必須遵循下一個 regex 模式:[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}
您可以在 OCI Distribution Specification 中閱讀更多相關資訊並找到驗證 regex。如果您未指定標籤,Kubernetes 會假設您指的是標籤 latest
。
映像摘要包含雜湊演算法(例如 sha256
)和雜湊值。例如:sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07
。你可以在 OCI 映像規格 中找到更多關於摘要格式的資訊。
以下是一些 Kubernetes 可以使用的映像名稱範例
busybox
- 僅映像名稱,沒有標籤或摘要。Kubernetes 將使用 Docker 公共登錄檔和 latest 標籤。(與docker.io/library/busybox:latest
相同)busybox:1.32.0
- 帶有標籤的映像名稱。Kubernetes 將使用 Docker 公共登錄檔。(與docker.io/library/busybox:1.32.0
相同)registry.k8s.io/pause:latest
- 帶有自訂登錄檔和 latest 標籤的映像名稱。registry.k8s.io/pause:3.5
- 帶有自訂登錄檔和非 latest 標籤的映像名稱。registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07
- 帶有摘要的映像名稱。registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07
- 帶有標籤和摘要的映像名稱。僅摘要將用於提取 (pulling)。
更新映像
當你首次建立 Deployment、StatefulSet、Pod 或其他包含 Pod 範本的物件時,預設情況下,如果未明確指定,則該 Pod 中所有容器的提取策略 (pull policy) 將設定為 IfNotPresent
。此策略會使 kubelet 在映像已存在時跳過提取映像。
映像提取策略
容器的 imagePullPolicy
和映像的標籤會影響 kubelet 何時嘗試提取(下載)指定的映像。
以下是你可為 imagePullPolicy
設定的值及其效果列表
IfNotPresent
- 僅當映像在本地尚不存在時才提取映像。
Always
- 每次 kubelet 啟動容器時,kubelet 都會查詢容器映像登錄檔,以將名稱解析為映像摘要。如果 kubelet 在本地快取中具有具有該確切摘要的容器映像,則 kubelet 會使用其快取的映像;否則,kubelet 會提取具有已解析摘要的映像,並使用該映像來啟動容器。
Never
- kubelet 不會嘗試提取映像。如果映像以某種方式已存在於本地,則 kubelet 會嘗試啟動容器;否則,啟動將失敗。請參閱 預先提取的映像 以取得更多詳細資訊。
基礎映像供應商的快取語意使 imagePullPolicy: Always
即使在登錄檔可可靠存取的情況下也很有效率。你的容器執行期可以注意到映像層已存在於節點上,因此不需要再次下載它們。
注意
在生產環境中部署容器時,你應避免使用 :latest
標籤,因為這樣更難追蹤哪個版本的映像正在執行,且更難以正確地回滾。
相反地,請指定有意義的標籤,例如 v1.42.0
和/或摘要。
為了確保 Pod 始終使用相同版本的容器映像,你可以指定映像的摘要;將 <映像名稱>:<標籤>
替換為 <映像名稱>@<摘要>
(例如,image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2
)。
當使用映像標籤時,如果映像登錄檔要更改該映像標籤代表的程式碼,你最終可能會得到混合執行舊程式碼和新程式碼的 Pod。映像摘要唯一地識別映像的特定版本,因此 Kubernetes 每次啟動具有指定映像名稱和摘要的容器時,都會執行相同的程式碼。透過摘要指定映像可以固定你執行的程式碼,以便登錄檔中的變更不會導致該版本的混合。
有第三方許可控制器在 Pod(和 Pod 範本)建立時變更它們,以便基於映像摘要而不是標籤來定義執行的工作負載。如果你想確保你的所有工作負載都執行相同的程式碼,無論登錄檔發生什麼標籤變更,這可能會很有用。
預設映像提取策略
當你(或控制器)向 API 伺服器提交新的 Pod 時,當滿足特定條件時,你的叢集會設定 imagePullPolicy
欄位
- 如果你省略
imagePullPolicy
欄位,並且你為容器映像指定了摘要,則imagePullPolicy
會自動設定為IfNotPresent
。 - 如果你省略
imagePullPolicy
欄位,並且容器映像的標籤是:latest
,則imagePullPolicy
會自動設定為Always
; - 如果你省略
imagePullPolicy
欄位,並且你沒有為容器映像指定標籤,則imagePullPolicy
會自動設定為Always
; - 如果你省略
imagePullPolicy
欄位,並且你為容器映像指定的標籤不是:latest
,則imagePullPolicy
會自動設定為IfNotPresent
。
注意
容器的 imagePullPolicy
值始終在首次建立物件時設定,如果映像的標籤或摘要稍後變更,則不會更新。
例如,如果你建立一個 Deployment,其映像的標籤不是 :latest
,然後稍後將該 Deployment 的映像更新為 :latest
標籤,則 imagePullPolicy
欄位將不會更改為 Always
。你必須在物件初始建立後手動更改任何物件的提取策略。
必要的映像提取
如果你想要始終強制提取 (pull),你可以執行以下操作之一
- 將容器的
imagePullPolicy
設定為Always
。 - 省略
imagePullPolicy
並使用:latest
作為要使用的映像標籤;當你提交 Pod 時,Kubernetes 會將策略設定為Always
。 - 省略
imagePullPolicy
和要使用的映像標籤;當你提交 Pod 時,Kubernetes 會將策略設定為Always
。 - 啟用 AlwaysPullImages 許可控制器。
ImagePullBackOff
當 kubelet 開始使用容器執行期為 Pod 建立容器時,容器可能因為 ImagePullBackOff
而處於等待中狀態。
狀態 ImagePullBackOff
表示容器無法啟動,因為 Kubernetes 無法提取容器映像(原因例如無效的映像名稱,或從私有登錄檔提取但沒有 imagePullSecret
)。BackOff
部分表示 Kubernetes 將繼續嘗試提取映像,並增加退避延遲。
Kubernetes 每次嘗試之間都會增加延遲,直到達到編譯時限制,即 300 秒(5 分鐘)。
每個 RuntimeClass 的映像提取
Kubernetes v1.29 [alpha]
(預設為停用:false)如果你啟用 RuntimeClassInImageCriApi
功能閘道,則 kubelet 會透過 (映像名稱、執行期處理常式) 的元組而不是僅映像名稱或摘要來參考容器映像。你的 容器執行期 可以根據選定的執行期處理常式調整其行為。基於執行期類別提取映像將有助於虛擬機器 (VM) 型容器,例如 Windows Hyper-V 容器。
串列和並行映像提取
預設情況下,kubelet 串列提取映像。換句話說,kubelet 一次僅向映像服務發送一個映像提取請求。其他映像提取請求必須等到正在處理的請求完成。
節點獨立做出映像提取決策。即使你使用串列映像提取,兩個不同的節點也可以並行提取相同的映像。
如果你想啟用並行映像提取,你可以在 kubelet 設定 中將欄位 serializeImagePulls
設定為 false。當 serializeImagePulls
設定為 false 時,映像提取請求將立即發送到映像服務,並且將同時提取多個映像。
啟用並行映像提取時,請確保你的容器執行期的映像服務可以處理並行映像提取。
kubelet 永遠不會代表一個 Pod 並行提取多個映像。例如,如果你的 Pod 有一個 init 容器和一個應用程式容器,則這兩個容器的映像提取不會並行化。但是,如果你有兩個 Pod 使用不同的映像,則當啟用並行映像提取時,kubelet 會代表這兩個不同的 Pod 並行提取映像。
最大並行映像提取數
Kubernetes v1.32 [beta]
當 serializeImagePulls
設定為 false 時,kubelet 預設為對同時提取的最大映像數量沒有限制。如果你想限制並行映像提取的數量,你可以在 kubelet 設定中設定欄位 maxParallelImagePulls
。當 maxParallelImagePulls
設定為 n 時,一次只能提取 n 個映像,並且任何超出 n 的映像提取都必須等到至少一個正在進行的映像提取完成。
當啟用並行映像提取時,限制並行映像提取的數量將防止映像提取消耗過多的網路頻寬或磁碟 I/O。
你可以將 maxParallelImagePulls
設定為大於或等於 1 的正數。如果你將 maxParallelImagePulls
設定為大於或等於 2,則必須將 serializeImagePulls
設定為 false。kubelet 將無法以無效的 maxParallelImagePulls
設定啟動。
具有映像索引的多架構映像
除了提供二進位映像之外,容器登錄檔還可以提供容器映像索引。映像索引可以指向多個映像清單,用於特定架構版本的容器。其想法是,你可以為映像命名(例如:pause
、example/mycontainer
、kube-apiserver
),並允許不同的系統提取適用於其使用機器架構的正確二進位映像。
Kubernetes 本身通常使用後綴 -$(ARCH)
來命名容器映像。為了向後相容性,請產生帶有後綴的舊映像。這個想法是產生例如 pause
映像,它具有所有架構的清單,並產生例如 pause-amd64
映像,它與可能已硬式編碼帶有後綴的映像的舊配置或 YAML 檔案向後相容。
使用私有登錄檔
私有登錄檔可能需要金鑰才能從中讀取映像。
可以透過幾種方式提供憑證
- 設定節點以驗證私有登錄檔
- 所有 Pod 都可以讀取任何已設定的私有登錄檔
- 需要叢集管理員進行節點設定
- Kubelet 憑證提供者動態提取私有登錄檔的憑證
- 可以將 kubelet 設定為使用憑證提供者 exec 外掛程式來取得各自私有登錄檔的憑證。
- 預先提取的映像
- 所有 Pod 都可以使用節點上快取的任何映像
- 需要 root 存取權才能設定所有節點
- 在 Pod 上指定 ImagePullSecrets
- 只有提供自己金鑰的 Pod 才能存取私有登錄檔
- 供應商特定或本地擴充功能
- 如果你正在使用自訂節點配置,你(或你的雲端供應商)可以實作你的機制,用於驗證節點到容器登錄檔。
以下更詳細地說明這些選項。
設定節點以驗證私有登錄檔
設定憑證的具體說明取決於你選擇使用的容器執行期和登錄檔。你應參考你的解決方案文件以取得最準確的資訊。
有關配置私有容器映像登錄檔的範例,請參閱從私有登錄檔提取映像任務。該範例使用 Docker Hub 中的私有登錄檔。
Kubelet 憑證提供者用於驗證的映像提取
注意
當 kubelet 需要動態提取登錄檔憑證時,此方法尤其適用。最常用於雲端供應商提供的登錄檔,其中授權權杖的生命週期很短。你可以將 kubelet 設定為調用外掛程式二進位檔案,以動態提取容器映像的登錄檔憑證。這是提取私有登錄檔憑證最穩健和通用的方式,但也需要 kubelet 層級的設定才能啟用。
請參閱 設定 kubelet 映像憑證提供者 以取得更多詳細資訊。
config.json 的解譯
config.json
的解譯在原始 Docker 實作和 Kubernetes 解譯之間有所不同。在 Docker 中,auths
金鑰只能指定根 URL,而 Kubernetes 允許 glob URL 以及前綴匹配路徑。唯一的限制是 glob 模式 (*
) 必須包含點 (.
) 用於每個子網域。匹配的子網域數量必須等於 glob 模式 (*.
) 的數量,例如
*.kubernetes.io
將不匹配kubernetes.io
,但會匹配abc.kubernetes.io
*.*.kubernetes.io
將不匹配abc.kubernetes.io
,但會匹配abc.def.kubernetes.io
prefix.*.io
將匹配prefix.kubernetes.io
*-good.kubernetes.io
將匹配prefix-good.kubernetes.io
這表示像這樣的 config.json
是有效的
{
"auths": {
"my-registry.io/images": { "auth": "…" },
"*.my-registry.io/images": { "auth": "…" }
}
}
現在,映像提取操作會將憑證傳遞給 CRI 容器執行期以用於每個有效模式。例如,以下容器映像名稱將成功匹配
my-registry.io/images
my-registry.io/images/my-image
my-registry.io/images/another-image
sub.my-registry.io/images/my-image
但不會匹配
a.sub.my-registry.io/images/my-image
a.b.sub.my-registry.io/images/my-image
kubelet 會針對找到的每個憑證依序執行映像提取。這表示 config.json
中用於不同路徑的多個條目也是可能的
{
"auths": {
"my-registry.io/images": {
"auth": "…"
},
"my-registry.io/images/subpath": {
"auth": "…"
}
}
}
如果現在容器指定要提取的映像 my-registry.io/images/subpath/my-image
,則如果其中一個驗證來源失敗,kubelet 將嘗試從兩個驗證來源下載它們。
預先提取的映像
注意
如果你可以控制節點設定,此方法適用。如果你的雲端供應商管理節點並自動替換它們,則此方法將無法可靠地運作。預設情況下,kubelet 會嘗試從指定的登錄檔提取每個映像。但是,如果容器的 imagePullPolicy
屬性設定為 IfNotPresent
或 Never
,則會使用本地映像(分別為優先或獨佔)。
如果你想依靠預先提取的映像來替代登錄檔驗證,你必須確保叢集中的所有節點都具有相同的預先提取映像。
這可以用於預先載入某些映像以提高速度,或作為驗證私有登錄檔的替代方案。
所有 Pod 都將具有對任何預先提取映像的讀取權限。
在 Pod 上指定 imagePullSecrets
注意
這是基於私有登錄檔中的映像執行容器的建議方法。Kubernetes 支援在 Pod 上指定容器映像登錄檔金鑰。imagePullSecrets
必須與 Pod 位於相同的命名空間中。引用的 Secrets 必須是 kubernetes.io/dockercfg
或 kubernetes.io/dockerconfigjson
類型。
使用 Docker 設定建立 Secret
你需要知道用於驗證登錄檔的使用者名稱、登錄檔密碼和用戶端電子郵件地址,以及其主機名稱。執行以下命令,替換適當的大寫值
kubectl create secret docker-registry <name> \
--docker-server=DOCKER_REGISTRY_SERVER \
--docker-username=DOCKER_USER \
--docker-password=DOCKER_PASSWORD \
--docker-email=DOCKER_EMAIL
如果你已經有一個 Docker 憑證檔案,則可以匯入憑證檔案作為 Kubernetes Secrets,而不是使用上述命令。
根據現有的 Docker 憑證建立 Secret 說明如何設定此項。
如果你正在使用多個私有容器登錄檔,這尤其有用,因為 kubectl create secret docker-registry
建立的 Secret 僅適用於單個私有登錄檔。
注意
Pod 只能參考其自身命名空間中的映像提取密鑰 (image pull secret),因此每個命名空間都需要執行此程序一次。在 Pod 上參考 imagePullSecrets
現在,你可以透過將 imagePullSecrets
區段新增至 Pod 定義來建立參考該 Secret 的 Pod。imagePullSecrets
陣列中的每個項目只能參考相同命名空間中的 Secret。
例如
cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
namespace: awesomeapps
spec:
containers:
- name: foo
image: janedoe/awesomeapp:v1
imagePullSecrets:
- name: myregistrykey
EOF
cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF
對於每個使用私有登錄檔的 Pod,都需要執行此操作。
但是,可以透過在 ServiceAccount 資源中設定 imagePullSecrets 來自動化此欄位的設定。
請查看 將 ImagePullSecrets 新增至 Service Account 以取得詳細說明。
你可以將此與每個節點的 .docker/config.json
結合使用。憑證將會合併。
使用案例
有很多種解決方案可用於設定私有登錄檔。以下是一些常見的使用案例和建議的解決方案。
- 叢集僅執行非專有(例如,開放原始碼)映像。無需隱藏映像。
- 使用公共登錄檔中的公共映像
- 無需設定。
- 某些雲端供應商會自動快取或鏡像公共映像,這可以提高可用性並縮短提取映像的時間。
- 使用公共登錄檔中的公共映像
- 叢集執行一些專有映像,這些映像應對公司外部人員隱藏,但對所有叢集使用者可見。
- 使用託管的私有登錄檔
- 可能需要在需要存取私有登錄檔的節點上進行手動設定
- 或者,在你的防火牆後方執行具有開放讀取權限的內部私有登錄檔。
- 無需 Kubernetes 設定。
- 使用託管的容器映像登錄檔服務,該服務控制映像存取
- 與手動節點設定相比,它更適用於叢集自動擴展。
- 或者,在變更節點設定不方便的叢集上,使用
imagePullSecrets
。
- 使用託管的私有登錄檔
- 具有專有映像的叢集,其中一些映像需要更嚴格的存取控制。
- 確保 AlwaysPullImages 許可控制器 處於活動狀態。否則,所有 Pod 可能都有權存取所有映像。
- 將敏感資料移至「Secret」資源中,而不是將其封裝在映像中。
- 多租戶叢集,其中每個租戶都需要自己的私有登錄檔。
- 確保 AlwaysPullImages 許可控制器 處於活動狀態。否則,所有租戶的所有 Pod 可能都有權存取所有映像。
- 執行需要授權的私有登錄檔。
- 為每個租戶產生登錄檔憑證,放入 Secret 中,並將 Secret 填入每個租戶命名空間。
- 租戶將該 Secret 新增至每個命名空間的 imagePullSecrets。
如果你需要存取多個登錄檔,你可以為每個登錄檔建立一個 Secret。
舊版內建 kubelet 憑證提供者
在舊版本的 Kubernetes 中,kubelet 直接整合了雲端供應商憑證。這使其能夠動態提取映像登錄檔的憑證。
kubelet 憑證提供者整合有三種內建實作:ACR(Azure 容器登錄檔)、ECR(Elastic Container Registry)和 GCR(Google Container Registry)。
有關舊版機制的更多資訊,請閱讀你正在使用的 Kubernetes 版本的說明文件。Kubernetes v1.26 到 v1.32 不包含舊版機制,因此你需要
- 在每個節點上設定 kubelet 映像憑證提供者
- 使用
imagePullSecrets
和至少一個 Secret 指定映像提取憑證
下一步
- 閱讀 OCI 映像清單規格。
- 瞭解 容器映像垃圾收集。
- 瞭解更多關於從私有登錄檔提取映像。