從 GCE 上拉取 GCR 私有 Docker Image

Jun 30, 2020

繼先前的「透過 Ansible playbook 來手動安裝 Docker」和「在 GCP 上執行你第一個 Ansible Ad-Hoc Command」這兩篇文章, 我依舊正在學習怎麼用 ansible,透過 playbook 的方式來設定機器真的非常便利,也很酷。

這篇文章主要是要分享我在 GCE 上想要 pull 私有 image 所遇到的問題,希望有遇到類似問題的人可以透過這篇文章解決。

Installation & Setup Docker

在「透過 Ansible playbook 來手動安裝 Docker」這篇文章中,參考了官方手動安裝的方式來安裝 docker,我自己在安裝 docker 過程中沒有遇到什麼問題,如果你覺得自己寫這些 playbook 很煩瑣的話,可以去找一些好用的 role 來直接使用。

在安裝完成 docker 之後,請不要忘了將你的使用者帳號加入 docker group:

$ sudo usermod -a -G docker ${USER}

完成上述之後,你可以試著使用 docker pull 去 pull 一些 public 的 image 做測試,例如 busybox

$ docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
91f30d776fb2: Pull complete
Digest: sha256:9ddee63a712cea977267342e8750ecbc60d3aab25f04ceacfa795e6fce341793
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest

接著用 docker images 看一下 images:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest c7c37e472d31 10 hours ago 1.22MB

Push Your Image To GCR

如果要將本機端的 image 推到 GCR 上面,請參考官方的文件進行,請注意 Before you begin 所提到的幾點一定要先完成,把權限設定好了才能順利將 image 推到 GCR 上。

$ docker push asia.gcr.io/[PROJECT-ID]/[IMAGE]

Pull Docker Container On GCE

我透過 playbook 來安裝 docker 並從 private registry 去拉取我推上去的 image,遇到了權限的問題,為了排除問題,我先遠端連線到 GCE 內去直接操作指令。

我直接下了 pull 的指令結果看到以下的錯誤資訊:

Error response from daemon: unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication

很明顯的就是權限上有一些問題,於是去查了文件,而驗證的方式有四種,我先選擇了第一個 gcloud as credential helper 的方式先測試。

使用 gcloud auth login 方式認證

此操作在 GCE 內進行

從這個角度來看,我是開啟這個專案的人,如果我登入後就會是 project owner 的角色,基本上這個角色的權限是很大的。

接著可以下這個指令來看看會出現什麼訊息:

$ gcloud auth login
You are running on a Google Compute Engine virtual machine.
It is recommended that you use service accounts for authentication.
You can run:
$ gcloud config set account `ACCOUNT`
to switch accounts if necessary.
Your credentials may be visible to others with access to this
virtual machine. Are you sure you want to authenticate with
your personal account?
Do you want to continue (Y/n)?

你可以選擇設定 config 的方式來設定 account,但這裡選擇繼續用原來的方式,所以輸入 Y

Go to the following link in your browser:
https://accounts.google.com/o/oauth2/auth?...
Enter verification code:

這時候會出現一串網址,請將他複製到網頁上,接著授予權限,你就會拿到一串 token,請將它貼回到 terminal 上,這時候就認證並登入完成,最後執行:

$ gcloud auth configure-docker

現在 docker 設定已經可以通過 Container Registry 的認證,就可以拉取私有的 image 了。

使用 gcloud auth activate-service-account 方式認證

此操作在 GCE 內進行

另外一種方式是透過 IAM 管理來新增不同的使用者來指定權限,首先可以到「 IAM管理 -> 服務帳戶」新增帳戶。在新增完成後,會得到一把 key,將它下載後請妥善保管,因為所有相關的身份認證都會用到。

Add service account

接著到「IAM -> 新增」成員,並且選擇角色,這裡選擇「Cloud Storage -> 儲存空間物件檢視者」,讓此帳戶具備有 read(讀取) storage 的功能。

Add account into project

接著進入到 GCE 內,透過以下方式進行驗證:

$ gcloud auth activate-service-account ACCOUNT --key-file=KEY-FILE

參數 --key-file 就是一開始你在 IAM 新增帳戶後所下載的 key,因為在遠端機器需要用到,所以你必須從你本機端 scp 到 GCE 上。

複製到遠端完成後,再執行上述的指令,如果成功應該可以看到以下的訊息:

$ [email protected]:~$ gcloud auth activate-service-account [email protected] --key-file=keyfile.json
Activated service account credentials for: [[email protected]]

然後再執行:

$ gcloud auth configure-docker
Adding credentials for all GCR repositories.
WARNING: A long list of credential helpers may cause delays running 'docker build'. We recommend passing the registry name to configure only the registry you are using.
After update, the following will be written to your Docker config file
located at [/home/jiepeng/.docker/config.json]:
{
"credHelpers": {
"gcr.io": "gcloud",
"marketplace.gcr.io": "gcloud",
"eu.gcr.io": "gcloud",
"us.gcr.io": "gcloud",
"staging-k8s.gcr.io": "gcloud",
"asia.gcr.io": "gcloud"
}
}

credentials 會放在使用者的目錄下,以 Linux 來說會在 $HOME/.docker/config.json

這樣就完成身份的認證,這時候執行 docker pull 去拉取 GCR 上私有 image 就可以成功了。

如果在完成設定使用者權限後,進入到 GCE 完成上述步驟還是失敗的話,請重新將 GCE 重啟試試 🙃。

Login Private Registry by Ansible Module

Ansible playbook 提供 docker_login,可以透過這個 module 登入 docker account,將你的 keyfile.json 放在目錄下,但是不要加入到版本控制。

要使用 docker_login module 請確認你的 server 端有 docker for python 的 SDK,若是沒有則會無法透過 docker_login 登入。

- name: Log into private registry and force re-authorization
docker_login:
registry: https://asia.gcr.io
username: _json_key
password: "{{ lookup('template', {{ keyfile_path }}, convert_data=False) | string }}"
reauthorize: yes

請記得將 password{{ keyfile_path }} 替換成實際檔案位置,成功後就可以透過 docker_image module 來 pull GCR 上的 private image。

- name: Pull docker instagpx image.
docker_image:
name: "{{ your_image_name }}"
source: pull

Reference