Kubernetes Image 拉取指南
什麼是容器映像拉取?
在 Kubernetes 中,Pod 需要使用容器映像來啟動容器。根據映像的來源和存取方式不同,Kubernetes 提供了多種映像拉取策略。了解這些不同的拉取方式對於有效管理應用程式部署至關重要。
映像拉取的主要場景:
- 本地映像:使用本地構建並載入到節點的映像
- 公開倉庫:從 Docker Hub 等公開倉庫拉取映像
- 私有倉庫:從需要身份驗證的私有倉庫拉取映像
- 企業倉庫:從組織內部的私有映像倉庫拉取映像
為什麼需要了解不同的拉取方式?
根據不同的使用場景,選擇合適的映像拉取方式可以:
- 提升效率:減少不必要的網路傳輸和下載時間
- 增強安全性:保護私有映像不被未授權存取
- 降低成本:避免重複拉取相同的映像
方式一:本地 Docker 映像直接引用
概述
當您在本地環境(如 Minikube、Docker Desktop)開發時,可以直接使用本地構建的 Docker 映像,無需推送到遠端倉庫。
使用場景
- 開發和測試階段
- 本地 Kubernetes 環境(Minikube、Kind)
- 不希望將映像推送到外部倉庫的情況
實作步驟
1. 確保 Docker 環境與 Kubernetes 共享
在 Minikube 中:
1 2 3 4 5 6 7 8 9 10 11
| eval $(minikube docker-env)
minikube docker-env | Invoke-Expression
docker context ls
echo $DOCKER_HOST
|
切回原本的 Docker 環境:
1 2 3 4 5 6 7 8
| eval $(minikube docker-env -u)
minikube docker-env -u | Invoke-Expression
|
在 Docker Desktop 中:
Docker Desktop 的 Kubernetes 會自動共享本地 Docker 映像。
2. 構建本地映像
1 2 3 4 5
| docker build -t my-local-app:latest .
docker images | grep my-local-app
|
3. 在 Kubernetes 中使用本地映像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: apps/v1 kind: Deployment metadata: name: local-app-deployment namespace: default spec: replicas: 1 selector: matchLabels: app: local-app template: metadata: labels: app: local-app spec: containers: - name: app image: my-local-app:latest imagePullPolicy: Never ports: - containerPort: 8080
|
4. 部署應用程式
1
| kubectl apply -f local-deployment.yaml
|
重要注意事項
- imagePullPolicy: 必須設定為
Never
或 IfNotPresent
- 映像標籤: 建議使用具體的標籤而非
latest
- 節點限制: 映像只存在於特定節點上
- Docker 環境切換: 使用
minikube docker-env
後記得切回原本環境
- 使用
eval $(minikube docker-env -u)
來取消設定
- 或重新啟動終端機會話
Docker 環境管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| echo $DOCKER_HOST
docker context ls
docker images
eval $(minikube docker-env) echo "當前 Docker Host: $DOCKER_HOST"
eval $(minikube docker-env -u) echo "當前 Docker Host: $DOCKER_HOST"
|
方式二:拉取 Docker Hub 公開倉庫映像
概述
從 Docker Hub 等公開倉庫拉取映像是最常見的方式,適用於使用開源軟體或公開可用的應用程式映像。
使用場景
- 使用官方映像(如 nginx、redis、mysql)
- 使用開源專案的公開映像
- 生產環境中的標準化映像
實作步驟
1. 基本公開映像使用範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21-alpine imagePullPolicy: Always ports: - containerPort: 80
|
2. 進階公開映像配置範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deployment namespace: default spec: replicas: 1 selector: matchLabels: app: tomcat template: metadata: labels: app: tomcat spec: containers: - name: tomcat image: tomcat:10.1-jdk17 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 command: ["/bin/sh","-c"] args: - cp -r /usr/local/tomcat/webapps.dist/ROOT /usr/local/tomcat/webapps/ && exec catalina.sh run readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 10 periodSeconds: 5
|
3. 部署應用程式
1 2 3 4 5 6 7 8 9
| kubectl apply -f nginx-deployment.yaml
kubectl apply -f tomcat-deployment.yaml
kubectl get deployments kubectl get pods
|
ImagePullPolicy 選項說明
- Always: 每次都重新拉取映像
- IfNotPresent: 本地不存在時才拉取(預設值)
- Never: 絕不拉取,只使用本地映像
方式三:拉取 Docker Hub 私有倉庫映像
概述
當使用私有倉庫中的映像時,需要提供身份驗證資訊。Kubernetes 使用 Image Pull Secret 來安全地存儲這些憑證。
使用場景
- 使用組織的私有映像
- 商業軟體的私有映像
- 包含敏感資訊的應用程式映像
實作步驟
1. 建立 Docker Registry Secret
為了讓 Kubernetes 能夠從 Docker Hub 私有倉庫拉取映像檔,需要建立包含認證資訊的 Secret 資源:
1 2 3 4 5 6
| kubectl create secret docker-registry regcred \ --docker-server=https://index.docker.io/v1/ \ --docker-username=<username> \ --docker-password=<password> \ --docker-email=<mail> \ --namespace=<namespace>
|
參數說明:
regcred
:Secret 的名稱,可以自行定義
--docker-server
:Docker Hub 的伺服器地址,固定為 https://index.docker.io/v1/
--docker-username
:您的 Docker Hub 使用者名稱
--docker-password
:建議使用 Personal Access Token (PAT) 而非密碼
--namespace
:指定 Secret 建立的命名空間
關於如何獲取 Docker Hub Personal Access Token 的詳細說明,請參考之前的文章
重要提醒:
- 出於安全考量,強烈建議使用 Personal Access Token (PAT) 而非帳戶密碼
--docker-email
參數為可選,現代 Docker 倉庫通常不需要此參數
- Secret 必須建立在與 Pod 相同的命名空間中才能使用
2. 在 Deployment 中使用私有映像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| apiVersion: apps/v1 kind: Deployment metadata: name: k8s-deployment namespace: k8s-namespace spec: replicas: 1 selector: matchLabels: app: k8s-app template: metadata: labels: app: k8s-app spec: containers: - name: k8s-app image: <username>/<repo-name>:latest imagePullPolicy: Always ports: - containerPort: 8080 imagePullSecrets: - name: regcred
|
3. 使用 ServiceAccount 自動套用 Secret
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| apiVersion: v1 kind: ServiceAccount metadata: name: k8s-sa namespace: k8s-namespace imagePullSecrets: - name: regcred
--- apiVersion: apps/v1 kind: Deployment metadata: name: k8s-deployment namespace: k8s-namespace spec: replicas: 1 selector: matchLabels: app: k8s-app template: metadata: labels: app: k8s-app spec: serviceAccountName: k8s-sa containers: - name: k8s-app image: <username>/<repo-name>:latest imagePullPolicy: Always ports: - containerPort: 8080
|
不同私有倉庫的設定
AWS ECR
1 2 3 4 5
| kubectl create secret docker-registry ecr-secret \ --docker-server=<account-id>.dkr.ecr.<region>.amazonaws.com \ --docker-username=AWS \ --docker-password=$(aws ecr get-login-password) \ --namespace=<namespace>
|
Azure ACR
1 2 3 4 5
| kubectl create secret docker-registry acr-secret \ --docker-server=<registry-name>.azurecr.io \ --docker-username=<username> \ --docker-password=<password> \ --namespace=<namespace>
|
Google GCR
1 2 3 4 5
| kubectl create secret docker-registry gcr-secret \ --docker-server=gcr.io \ --docker-username=_json_key \ --docker-password="$(cat key.json)" \ --namespace=<namespace>
|
常用管理指令
查看映像拉取狀態
1 2 3 4 5 6 7 8
| kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl get events --field-selector reason=Pulling -n <namespace>
|
管理 Image Pull Secrets
1 2 3 4 5 6 7 8
| kubectl get secrets -n <namespace>
kubectl describe secret <secret-name> -n <namespace>
kubectl delete secret <secret-name> -n <namespace>
|
手動拉取映像進行測試
1 2 3 4 5
| docker pull <image-name>
docker images | grep <image-name>
|
疑難排解
常見問題與解決方案
1. ImagePullBackOff 錯誤
1 2 3 4 5 6 7 8
| kubectl describe pod <pod-name>
|
2. 本地映像無法拉取
- 確認
imagePullPolicy
設定為 Never
或 IfNotPresent
- 檢查映像是否存在於正確的節點上
- 在 Minikube 中確認 Docker 環境設定正確
- Docker 環境問題:確認是否在正確的 Docker 環境中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| echo $DOCKER_HOST
env | grep DOCKER
eval $(minikube docker-env) docker images
eval $(minikube docker-env -u)
|
3. 私有倉庫認證失敗
- 驗證 Secret 中的憑證是否正確
- 檢查 Secret 是否在正確的命名空間中
- 確認倉庫伺服器地址格式正確
4. 映像拉取速度緩慢
- 考慮使用映像快取或本地倉庫
- 檢查網路連線品質
- 使用較小的映像或多階段構建
最佳實務建議
映像管理
- 使用具體標籤:避免使用
latest
標籤
- 映像掃描:定期掃描映像的安全漏洞
- 映像分層:優化 Dockerfile 以減少映像大小
- 定期更新:保持映像為最新版本
安全性
- 最小權限:使用最小權限的 ServiceAccount
- Secret 管理:定期輪換 Image Pull Secret
- 網路隔離:在適當的情況下使用網路策略
- 映像簽章:考慮使用映像簽章驗證
效能優化
- 本地快取:在開發環境中使用本地映像
- 並行拉取:合理設定 Pod 的並行啟動數量
- 映像預拉取:在節點上預先拉取常用映像
- 資源限制:設定適當的資源限制避免資源競爭
透過了解和正確使用這三種映像拉取方式,您可以在不同的環境和場景中高效、安全地管理 Kubernetes 應用程式的容器映像。