Ansible 自動選擇 Docker registry

前言

生活在台灣,總是要因為中華電信時不時海底電纜故障
連外國網路延遲超高,不是在找 VPN、就是在找替代方案…
打打遊戲無所謂,但如果是牽扯到正事,就讓人很不開心了
筆者習慣使用的 docker image registry 是 github 自帶的 ghcr.io,整合 github action 還蠻方便
這次中華電信故障後,從 ghcr.io pull image 變成非常的慢,觸發的部署也常常因為 timeout 而失敗
所以我要讓 Ansible 自動選擇 Docker registry

Ansible 自動選擇 Docker registry

為什麼要選擇 Github Container Registry

大概有兩個原因
下面附上連結
以這次的案例來說
Docker hub 完全沒有受到影響
當然可能某一天兩個都會無法使用
但至少在 CI/CD 中加入一個第二選項
也是有備無患

備援策略

上面提到 Docker hub 是有下載限制的

Docker Hub limits the number of Docker image downloads (“pulls”) based on the account type of the user pulling the image. Pull rates limits are based on individual IP address. For anonymous users, the rate limit is set to 100 pulls per 6 hours per IP address. For authenticated users, it’s 200 pulls per 6 hour period. Users with a paid Docker subscription get up to 5000 pulls per day. If you require a higher number of pulls, you can also purchase an Enhanced Service Account add-on.

匿名下載是 100 times / 6 hour
註冊帳號是 200 times / 6 hour

以筆者來說,我幾乎不會在本機運行我整個架構
都是改完 code 就跑 github action 到部署
加上我整個架構有 3 個 container
每次的部署都是使用 latest tag,為了確保是最新的
都還會重新 pull
這樣的速度,很快就會達到上限
所幸 Docker 是有提供 API 可以查詢目前剩下的數量

最簡單的策略就是用數量判斷
數量太少,就使用 ghcr.io
數量足夠,就使用 docker.io

Ansible 自動選擇 Docker registry Playbook

改天再來寫寫我對 Ansible 的使用心得
今天直接上這次踩到的網路的坑

- name: Check docker hub remaining pull limit
  block:
      - name: Get temp docker token
        ansible.builtin.uri:
            url: https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull
            user: "{{ github_user }}"
            password: "{{ docker_password }}"
            method: GET
            return_content: true
        register: http_response

      - name: Parse token
        ansible.builtin.set_fact:
            temp_docker_token: "{{ http_response.content | from_json | json_query('token') }}"

      - name: Get remaining
        ansible.builtin.uri:
            url: https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
            headers:
                Authorization: "Bearer {{ temp_docker_token }}"
            method: GET
            return_content: true
        register: http_response_remaining

      - name: Parse remaining
        ansible.builtin.set_fact:
            docker_remaining: "{{ http_response_remaining.ratelimit_remaining | split(';') }}"

      - name: Use docker hub
        ansible.builtin.set_fact:
            image_owner: "{{ docker_user }}"
            use_registry: "docker"
        when: docker_remaining[0] | int > 10

      - name: Use github container registry
        ansible.builtin.set_fact:
            image_owner: ghcr.io/toc-taiwan
            use_registry: "github"
        when: docker_remaining[0] | int < 10

      - name: Decide registry
        ansible.builtin.debug:
            msg: "Use {{ image_owner }}, remaining {{ docker_remaining[0] }}"

大致說明一下

  • Get temp docker token

先透過 docker hub 的帳號、密碼取得一組查詢 API 用的 token
https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull

  • Parse token

這邊就用到 ansible 中的 set_fact
將剛剛取得的 token 存到 temp_docker_token

  • Get remaining

再來就可以使用剛剛的
https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
比較特別的是,Docker 沒有把剩餘數量放在 body 之中
而是放在 response 的 header

Ansible 自動選擇 Docker registry
  • Parse remaining

這邊簡單處理一下字串,取出數量

  • Use docker hub or Use github container registry

這邊用到 ansible 的 when 語句
筆者這邊設定邊界數量是 10
本身有 3 個 image 要 pull
只要大於 3 基本就足夠

  • Decide registry

這邊就是 log 一下目前被 Ansible 決定的 registry 是哪一個

Ansible 自動選擇 Docker registry

總結

本篇文章很簡單的使用 docker.io 所剩下的限制來決定要使用哪個 registry
可能等到中華電信修好,也不太會有人記得這件事
但能夠在 CI/CD 中提供一個第二甚至第三個備援選項,總是不會錯的!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *