Kubernetes Image 拉取指南

Kubernetes Image 拉取指南

什麼是容器映像拉取?

在 Kubernetes 中,Pod 需要使用容器映像來啟動容器。根據映像的來源和存取方式不同,Kubernetes 提供了多種映像拉取策略。了解這些不同的拉取方式對於有效管理應用程式部署至關重要。

映像拉取的主要場景:

  • 本地映像:使用本地構建並載入到節點的映像
  • 公開倉庫:從 Docker Hub 等公開倉庫拉取映像
  • 私有倉庫:從需要身份驗證的私有倉庫拉取映像
  • 企業倉庫:從組織內部的私有映像倉庫拉取映像

為什麼需要了解不同的拉取方式?

根據不同的使用場景,選擇合適的映像拉取方式可以:

  1. 提升效率:減少不必要的網路傳輸和下載時間
  2. 增強安全性:保護私有映像不被未授權存取
  3. 降低成本:避免重複拉取相同的映像

方式一:本地 Docker 映像直接引用

概述

當您在本地環境(如 Minikube、Docker Desktop)開發時,可以直接使用本地構建的 Docker 映像,無需推送到遠端倉庫。

使用場景

  • 開發和測試階段
  • 本地 Kubernetes 環境(Minikube、Kind)
  • 不希望將映像推送到外部倉庫的情況

實作步驟

1. 確保 Docker 環境與 Kubernetes 共享

在 Minikube 中:

1
2
3
4
5
6
7
8
9
10
11
# 設定 Docker 環境指向 Minikube
eval $(minikube docker-env)

# 或在 Windows PowerShell 中
minikube docker-env | Invoke-Expression

# 驗證已切換到 Minikube Docker 環境
docker context ls
# 或者檢查 Docker Host
echo $DOCKER_HOST
# Minikube 環境會顯示類似:tcp://192.168.49.2:2376

切回原本的 Docker 環境:

1
2
3
4
5
6
7
8
# 在 Linux/macOS 中
eval $(minikube docker-env -u)

# 或在 Windows PowerShell 中
minikube docker-env -u | Invoke-Expression

# 或者直接重新啟動終端機會話
# 新的終端會自動使用本地 Docker 環境

在 Docker Desktop 中:
Docker Desktop 的 Kubernetes 會自動共享本地 Docker 映像。

2. 構建本地映像

1
2
3
4
5
# 構建 Docker 映像
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: 必須設定為 NeverIfNotPresent
  • 映像標籤: 建議使用具體的標籤而非 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
# 檢查當前 Docker 環境和主機
echo $DOCKER_HOST
# 本地:通常為空或顯示 unix:///var/run/docker.sock
# Minikube:顯示 tcp://192.168.49.2:2376 (或類似的 IP)

# 查看 Docker 上下文
docker context ls

# 列出 Docker 映像(確認在正確的環境中)
docker images

# 如果需要在不同環境間切換:
# 切換到 Minikube
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 # Docker Hub 官方映像
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
# 部署基本的 Nginx 應用
kubectl apply -f nginx-deployment.yaml

# 部署進階的 Tomcat 應用
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: # 指定用於身份驗證的 Secret
- 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 # 使用 ServiceAccount
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
# 查看 Pod 狀態
kubectl get pods -n <namespace>

# 查看 Pod 詳細資訊(包含映像拉取事件)
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
# 查看 Secret 列表
kubectl get secrets -n <namespace>

# 查看 Secret 詳細資訊
kubectl describe secret <secret-name> -n <namespace>

# 刪除 Secret
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
# 檢查 Pod 事件
kubectl describe pod <pod-name>

# 常見原因:
# - 映像名稱錯誤
# - 網路連線問題
# - 身份驗證失敗
# - 映像不存在

2. 本地映像無法拉取

  • 確認 imagePullPolicy 設定為 NeverIfNotPresent
  • 檢查映像是否存在於正確的節點上
  • 在 Minikube 中確認 Docker 環境設定正確
  • Docker 環境問題:確認是否在正確的 Docker 環境中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 檢查當前 Docker 環境(更準確的方法)
    echo $DOCKER_HOST
    # 本地環境:通常為空或 unix:///var/run/docker.sock
    # Minikube 環境:tcp://192.168.49.2:2376 或類似 IP

    # 或者檢查環境變數
    env | grep DOCKER

    # 如果在 Minikube 環境中找不到映像,切換到正確環境
    eval $(minikube docker-env) # 切換到 Minikube
    docker images # 確認映像存在

    # 如果需要切回本地環境
    eval $(minikube docker-env -u)

3. 私有倉庫認證失敗

  • 驗證 Secret 中的憑證是否正確
  • 檢查 Secret 是否在正確的命名空間中
  • 確認倉庫伺服器地址格式正確

4. 映像拉取速度緩慢

  • 考慮使用映像快取或本地倉庫
  • 檢查網路連線品質
  • 使用較小的映像或多階段構建

最佳實務建議

映像管理

  1. 使用具體標籤:避免使用 latest 標籤
  2. 映像掃描:定期掃描映像的安全漏洞
  3. 映像分層:優化 Dockerfile 以減少映像大小
  4. 定期更新:保持映像為最新版本

安全性

  1. 最小權限:使用最小權限的 ServiceAccount
  2. Secret 管理:定期輪換 Image Pull Secret
  3. 網路隔離:在適當的情況下使用網路策略
  4. 映像簽章:考慮使用映像簽章驗證

效能優化

  1. 本地快取:在開發環境中使用本地映像
  2. 並行拉取:合理設定 Pod 的並行啟動數量
  3. 映像預拉取:在節點上預先拉取常用映像
  4. 資源限制:設定適當的資源限制避免資源競爭

透過了解和正確使用這三種映像拉取方式,您可以在不同的環境和場景中高效、安全地管理 Kubernetes 應用程式的容器映像。