microk8s使用自建的mirror registry

文件在這邊:How to work with a private registry

設定方法很簡單,設定檔案位置在 /var/snap/microk8s/current/args/certs.d/ ,每個 registry server 都有一個對應的目錄,裏面會有 hosts.toml 。例如 docker.io ,目錄就是

/var/snap/microk8s/current/args/certs.d/docker.io ,hosts.toml 的內容是
server = "https://docker.io"

[host."https://registry-1.docker.io"]
  capabilities = ["pull", "resolve"]

要改為 mirror registry,就變為

server = "https://docker.io"

[host."http://your_registry_server/v2"]
  capabilities = ["pull", "resolve"]
  override_path = true

關鍵在於 [host.””] 裡的 server 位置還有 override_path = true

修改完成以後,重新啟動 microk8s 即可。

sudo snap restart microk8s

基本設定方法就是這樣。之前在看的時候因為眼花,一直想說為什麼會有 “‘ | sudo tee -a /var/snap/microk8s/current/args/certs.d/k8s.gcr.io/hosts.toml” 這一段,後來仔細看,才知道文件裡貼的是一個指令。

以後改為這樣,就可以不用去外部拉取,加快拉取 image 速度了。

podman如何使用registry mirror

之前弄好 registry mirror,因為是用 docker,所以需要調整的設定檔是 /etc/docker/daemon.json

那在 podman 裡,該怎麼設定呢?

這部份可以參考 /etc/containers/registries.conf 裡面的說明,然後在 /etc/containers/registries.conf.d 資料夾裏面加上新的設定檔就可以。

例如可以在 /etc/containers/registries.conf.d/my-mirror.conf 加入以下內容

[[registry]]
location = "docker.io"

[[registry.mirror]]
location = "192.168.11.2:6000"
insecure = true

依照行號說明如下:

  1. [[registry]] 必須要加
  2. location = "docker.io" 是表示,遇到 docker.io 時,就要參考這裡的設定。
  3. [[registry.mirror]] 這是表示下面要寫 registry mirror 設定了。
  4. location = "192.168.11.2:6000" 是表示 registry mirror 的位置。
  5. insecure = true 是表示不要檢查這座 registry mirror 的 SSL 憑證。

設定完以後,在 podman pull docker.io/<image> 的時候,實際就會到 registry mirror 拉取 容器映像 ,由 registry mirror 再去決定是否到外面的 docker.io 拉取容器映像。

參考資料

Registry Mirror

最近在建置 container image 時,常會踩到 exceeded 的錯誤,這是因為 docker 在 2020 時,公告了新的收費機制,並為拉取 container image 的 API 加上了限制,沒有登入的使用者現在每6個小時只能有 100 個 pull requests可用;有登入且採用免費方案的使用者,每6個小時有 200 個 pull requests 可用。這在初期測試 pipeline 時,根本很容易就用超過。

上網搜尋看有沒有方法可以避過這限制,後來在 gitlab 網站上找到文章:Caching Docker images to reduce the number of calls to DockerHub from your CI/CD infrastructure | GitLab

文章裡有提到兩個方法,第一個簡單的方法就是登入,這樣可以提升到 200 個 pull requests。

因為大部分的 executor 都是使用 docker 或 docker + machine,所以設定方法可以單純的在 pipeline 裏面作 docker login,但這樣還要多塞指令跟 credential 。gitlab 很貼心的提供了一個內建的變數,要用這個變數,需要在 gitlab 專案的 settings > CI/CD > Variables 裡,去增加 DOCKER_AUTH_CONFIG ,那在執行 pipeline 時,gitlab-runner 看到有這個變數,就會自動做 login 的動作。

DOCKER_AUTH_CONFIG 的內容可以透過以下方式取得:

  1. 在終端機用指令先登入 index.docker.io: docker login
  2. 用 docker 指令登入後,在家目錄的 .docker 目錄下就會出現 config.json : cat ~/.docker/config.json
  3. 用 jq 指令讓內容變成一行: jq -c "." ~/.docker/config.json

輸出的結果,就可以拿來填了。

第二個方法,則是建置 Registry mirror。

找一台已經安裝 docker 的主機,然後使用 docker 啟動 registry container。在啟動的時候帶入環境參數 REGISTRY_PROXY_REMOTEURL

docker run -d -p 6000:5000 \
    -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \
    --restart always \
    --name registry registry:2

然後登入到 gitlab-runner 所在的主機,修改 /etc/docker/daemon.json ,內容如下

{
  "registry-mirrors": ["http://<your-registry-mirror-server:6000"]
}

修改完以後,讓 dockerd 重新載入設定:

sudo systemctl reload docker

再用 docker info | grep -A 1 -B 1 Mirror 確認。

這樣就設定完成了。

那要怎麼知道 gitlab-runner 在建置時有使用這個 registry mirror 呢?這時可以用 curl 指令來檢查

watch -n 60 curl -s http://<your-registry-server>:6000/v2/_catalog

輸出結果大致會是這樣

{"repositories":["library/docker","library/python"]}

至此,就可以算是解決了 exceeded 的問題啦。

docker-gitlab 與 container registry

之前有試了兩三次,但都卡在憑證部份,昨天終於搞定了。

主要參考文件是 https://github.com/sameersbn/docker-gitlab/blob/master/docs/container_registry.md

第一步是產生憑證,不要用上面文章提供的 openssl 指令,用 https://gitlab.com/gitlab-org/gitlab-ce/issues/25967 所提供的:

# 假定是在 docker-compose.yml 所在的目錄下
mkdir -p certs
cd certs
openssl req -nodes -newkey rsa:4096 -keyout registry-auth.key -out registry-auth.csr -subj "/CN=gitlab-issuer"
openssl x509 -in registry-auth.csr -out registry-auth.crt -req -signkey registry-auth.key -days 3650

第二步是修改、調整原有的 docker-compose.yml

# gitlab
gitlab:
  environments:
    # ... other environment variables
    # ...
    # Registry
    - GITLAB_REGISTRY_ENABLED=true
    - GITLAB_REGISTRY_HOST=registry.example.com
    - GITLAB_REGISTRY_PORT=443
    - GITLAB_REGISTRY_API_URL=http://registry:5000
    - GITLAB_REGISTRY_KEY_PATH=/certs/registry-auth.key
    - SSL_REGISTRY_KEY_PATH=/certs/registry-auth.key
    - SSL_REGISTRY_CERT_PATH=/certs/registry-auth.crt
  volumes:
    # ... other volumes
    # ...
    # 將前面建立的 certs 資料夾掛載到 /certs
    - ./certs:/certs
  links:
    # ... other service links
    # ...
    - registry
registry:
  image: registry:2.4.1
  expose:
    - "5000"
  ports:
    - "5000:5000"
  volumes:
    - /var/gitlab/shared/registry:/registry
    - ./certs:/certs
  environment:
    - REGISTRY_LOG_LEVEL=info
    - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/registry
    - REGISTRY_AUTH_TOKEN_REALM=https://git.example.com/jwt/auth
    # 如果你用的 gitlab 設定為 relative url root,那就是
    # - REGISTRY_AUTH_TOKEN_REALM=https://example.com/git/jwt/auth
    - REGISTRY_AUTH_TOKEN_SERVICE=container_registry
    - REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
    - REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/registry-auth.crt
    - REGISTRY_STORAGE_DELETE_ENABLED=true

第三步是改 Apache 或 Nginx 的設定,Nginx 的設定可以參考 https://github.com/sameersbn/docker-gitlab/blob/master/docs/container_registry.md

我用的是 Apache ,所以我是參考 https://gist.github.com/dkarlovi/5f6ab416aa882086c7305b004b590dd4 來做修改,改完記得重新啟動 Apache 或 Nginx。

修改完以後,執行 docker-compose up ,應該就沒問題了。

我遇過以下問題:

  1. 瀏覽 https://git.example.com/group1/project1/container_registry 時,出現 Internal server error:主要是 gitlab 環境變數裡的 GITLAB_REGISTRY_KEY_PATH、SSL_REGISTRY_KEY_PATH、SSL_REGISTRY_CERT_PATH 跟 registry 環境變數裡的 REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE 沒有設定好,當然其他的也有可能,儘可能都檢查一次。
  2. docker login 失敗:其實也是上面提的那幾個環境變數沒設定好。

檢討之前為什麼沒能架設好,原因如下:

  1. 對 SSL 憑證不了解:我的 git.example.com / registry.example.com 都使用 SSL 憑證,但又跟 registry-auth 的憑證搞混,總的來說,總共三個憑證,git.example.com 一個,registry.example.com 一個,registry-auth 一個。gitlab.example.com/registry.example.com 的憑證是給網頁伺服器(Apache/Nginx)使用,Apache/Nginx 設定裡要設定,然後 docker-compose.yml gitlab 服務裡只用到 gitlab.example.com 的憑證,要用 SSL_KEY_PATH, SSL_CERTIFICATE_PATH 跟 SSL_DHPARAM_PATH 這三個環境變數來設定。而 registry-auth 則是 gitlab 服務與 registry 服務作 token 認証用的,主要是 gitlab 環境變數裡的 GITLAB_REGISTRY_KEY_PATH、SSL_REGISTRY_KEY_PATH、SSL_REGISTRY_CERT_PATH 跟 registry 環境變數裡的 REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE。
  2. Apache 的 SSL 設定錯誤:SSLCertificateFile, SSLCertificateKeyFile, SSLCertificateChainFile 跟 SSLCACertificateFile 都要設定,我少設了 SSLCertificateChainFile,導致 registry 服務去問 gitlab 時,有憑證錯而有 HTTP request fail 的問題。