我這幾個星期在一間企業進行為期五天的 Kubernetes 教育訓練,我們的 Lab 環境都是用輕量級的 MicroK8s 為主,但是課程一開始就不太順利,因為上課人數有 20 位左右,他們都使用公司的網路,大家都共用一個 IP 連外,以致於碰上討人厭的 Rate limit on Docker Hub 問題,所以有些人無法成功架設起叢集,原因就是 image 下載不到造成的。這篇文章我就來說明在 MicroK8s 如何正確的解決 Docker Hub 無法下載 image 的問題。
問題檢測
當問題發生時,你用 kubectl get po
應該會看到 ErrImagePull
或 ImagePullBackOff
字樣,這代表 Image 在拉取的時候發生異常。
此時你可以用 kubectl describe po/$PODNAME
查看 Events
事件資料,藉此判斷問題發生的原因,錯誤訊息如下:
Warning Failed 19m (x2 over 19m) kubelet Failed to pull image "docker.io/calico/cni:v3.19.1": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/calico/cni:v3.19.1": failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/calico/cni/manifests/sha256:f301171be0add870152483fcce71b28cafb8e910f61ff003032e9b1053b062c4: 429 Too Many Requests - Server message: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
這個 kubectl describe
是我們在 Kubernetes 做 Troubleshooing 的時候一定會用的命令!
解決方案
其實解決方案有非常多種,你可以從 MicroK8s 官網的 DockerHub download rate limits 文件看到各種解決方案。
- 直接設定登入 DockerHub 通過 pull image 的驗證
- 使用替代的 Registry 來源,透過編輯現有 Deployment 的內容來修正問題
- 使用自行架設的 Private image registry 並用代理伺服器的方式快取 DockerHub 的 image 內容
本篇文章我主要分享登入 DockerHub 的兩種標準作法。
解決方案一:調整 containerd 的 Docker Hub Registry 設定
由於 MicroK8s 主要採用 containerd 做為容器引擎 (Container Runtime),所以最一勞永逸的方式,就是直接調整「每個節點」的 containerd
設定,讓任何要從 Docker Hub 下載的 image 都可以輸入 Docker Hub 的認證資訊(帳號密碼),以解除 Docker Hub 的 Rate limit 限制。
以下是設定步驟:
-
先取得 Docker Hub 的帳號與密碼
設定時建議不要直接使用你在 Docker Hub 的密碼,而是到 Docker Hub 的 Security 設定頁面,建立一個 Access Token 來當作密碼,建立時可以在 Access permissions 選擇 Read-only
即可,確保你的帳戶安全!
-
編輯叢集節點中的 /var/snap/microk8s/current/args/containerd-template.toml
檔案
multipass exec 'microk8s-vm' -- vi /var/snap/microk8s/current/args/containerd-template.toml
剛進入 vim
編輯器的時候,由於 Vim 預設 theme 的設定會讓你看不太清楚部分文字,建議可以輸入以下命令讓文字可以顯示的更清晰:
:set background=dark
接著在該檔案的最下方,新增以下內容: (排版沒有很重要)
[plugins."io.containerd.grpc.v1.cri".registry.configs."registry-1.docker.io".auth]
username = "DOCKERHUB_Username"
password = "DOCKERHUB_AccessToken"
請務必在每個節點都做一樣的設定,但叢集在升級後是否會保留設定,我還沒測試過,我會等下次升級的時候測試看看!
以下是另一種不用開 vim
就可以將內容加入 /var/snap/microk8s/current/args/containerd-template.toml
的技巧:
先進入 VM 的 Shell 環境:
multipass shell microk8s-vm
再將內容一次加入:
cat <<EOF >> /var/snap/microk8s/current/args/containerd-template.toml
[plugins."io.containerd.grpc.v1.cri".registry.configs."registry-1.docker.io".auth]
username = "DOCKERHUB_Username"
password = "DOCKERHUB_AccessToken"
EOF
-
重新啟動 MicroK8s 即可
microk8s stop
microk8s start
-
測試部署應用程式
kubectl create deployment microbot --image=dontrebootme/microbot:v1
kubectl expose deployment microbot --type=NodePort --port=80 --name=microbot-service
kubectl describe pod
解決方案二:使用自訂的 Private Registry 當成 Image 來源
我們自己與我們的客戶很多都會自行架設 Private Registry 當成 Image 來源,像是 ACR (Azure Container Registry) 或 Harbor 等等。當你要部署自行製作並上傳到 Private Registry 的 Image 時,就一定需要通過身份驗證,否則你將無法下載任何 Image 回來。
以下是設定步驟:
-
先取得 Private Registry 的帳號與密碼
這裡我一樣以 Docker Hub 為例,設定時建議不要直接使用你在 Docker Hub 的密碼,而是到 Docker Hub 的 Security 設定頁面,建立一個 Access Token 來當作密碼,建立時可以在 Access permissions 選擇 Read-only
即可,確保你的帳戶安全!
-
建立一個名為 regcred
的 Secret 物件
Bash
kubectl create secret docker-registry regcred \
--docker-server="https://index.docker.io/v1/" \
--docker-username="<Username>" \
--docker-password="<AccessToken>" \
--docker-email="<Email>"
PowerShell
kubectl create secret docker-registry regcred `
--docker-server="https://index.docker.io/v1/" `
--docker-username="<Username>" `
--docker-password="<AccessToken>" `
--docker-email="<Email>"
建立完成後,你可以透過以下命令看到實際的設定內容:
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode | jq -C
取得當初設定的帳號與密碼
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d | jq '.auths."https://index.docker.io/v1/".username' -Cr
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d | jq '.auths."https://index.docker.io/v1/".password' -Cr
-
在 Pod Template 之中的 Container Spec 指定 imagePullSecrets
欄位為 regcred
即可
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred
設定好之後,你的 Pod 在啟動時,就可以正確的從 Private Registry 下載 Image 了! 👍
相關連結