深度應用 Docker 容器後常會走到這一步 - 自建 Docker Registry (容器 Image 倉庫)。

不管用 docker 指令或跑 Docker Compose,建立容器都需先載入 Docker Image,若是公開 Image,透過 docker pull 指令、在 docker-compose.yml 指定 image 來源、或 Dockerfile 寫 FROM imageName:tag,都可從 Docker Hub下載,私有程式或內部應用系統不適合上傳第三方系統,企業內部主機則可能位於無法連 Internet 的環境,從 Docker Hub 下載這條路便不可行。簡單做法是用 docker save container-name > container-name.tar 再 scp 上傳到 Docker 主機用 docker load -i container-name.tar 載入,但儲存、上傳、載入(有時還需要壓縮解壓縮)程序複雜,若要部署多台主機格外沒效率。因此,建立私有 Docker Registry 取代 Docker Hub 的角色,是較省事有效率的實務做法。
(補充:關於 Container Image 部署,可參考保哥這篇遷移容器映像(Container Image)到另一台主機的各種作法)

Docker 支援自建私有 Registry 伺服器,不意外地有安裝成 Docker 容器的便捷做法。經簡單設定與安裝,架一台私有 Docker Registry 儲存非公開容器 Image 並不困難。說是一回事,做是一回事,這篇來實地演練一次。

參考資料:

首先準備一台 Docker 主機,裝好 Nginx + Certbot 服務,我是在 Azure 開一個 B1s 小 VM 來跑。(參考:HTTPS Nginx Docker 之懶人安裝法)

註:Azure 有 Azure Container Registry 的現成雲端服務,做法更簡便。學習在 Linux 跑 Docker 做法是為將來在離線環境建立 Docker Registry 做準備。

以我的標準,即便內部伺服器也要控管存取身分,不能讓閒雜人等隨便用。Docker Registry 支援帳號密碼登入,但前題要啟甪 TLS HTTPS 連線,故除了安裝 htpasswd 工具設定密碼雜湊檔,並需要安裝 mkcert 建立 TLS 憑證:

sudo apt-get install apache2-utils mkcert

我在主機端建了一個 /var/registry 資料夾放 Docker Registry 相關檔案,接著用 mkcert 建立自簽憑證給 Registry 用:

設定帳號密碼:

準備好 Docker Compose 設定檔,REGISTRY_HTTP_TLS_CERTIFICATE 及 REGISTRY_HTTP_TLS_KEY 環境變數指向 mkcert 剛才製作的兩個 pem 檔名、REGISTRY_AUTH_HTPASSWD_PATH 指向密碼檔名;volumes 部分將 Docker 的 Image 資料、憑證、認證資料對應到 /var/registry 實體路徑保存,以免容器關閉後資料消失:

version: "3"
services:
  registry:
    restart: always
    image: registry:2
    ports:
      - 5000:5000
    environment:
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/localhost.pem
      REGISTRY_HTTP_TLS_KEY: /certs/localhost-key.pem
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
    volumes:
      - /var/registry/data:/var/lib/registry
      - /var/registry/certs:/certs
      - /var/registry/auth:/auth

用 docker-compose up -d 啟動容器,若一切正常,用curl https://localhost:5000/v2/測試,若傳回{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":null}]}就代表成功了。

接著來測試 Push Image 到私有 Registry,操作程序是用 docker tag 為己載入容器加上 localhost:5000/aspnetapp 這種標籤,此時等同同一個 IMAGE ID 有兩個 Tag,由於 Registry 需要登入,用剛才的設定帳號密碼以指令 docker login 登入,接著 docker push localhost:5000/aspnetsapp 就能完成上傳:

檢查資料夾 /var/registry/data/docker/registry/v2/repositories/aspnetapp/_layers/sha256 可看見上傳過程出現的四個 Layer ID,成功!

接下來試試從 Windows Docker Desktop 從 VM 的對外網域名稱下載容器 Image 執行,一樣輕鬆秒殺:

就醬,一台自建 Docker Registry 便上線服役囉~

Tutorial of how to builld a private docker registry and upload private container to it.


Comments

# by Ming

不考慮裝個gitlab嗎?不過有點肥大就是了

# by Victoria City Lahore

Victoria City Lahore is the premium Housing Society Society in Lahore by the Sheranwala Developers. <a href="https://sheranwala.com">victoria city lahore</a>

# by 小白

請問黑大Registry client連線時不會出現x509: certificate signed by unknown authority問題嗎?我卡在如何讓另外一台要login到registry的主機信任server的憑證...

# by Jeffrey

to 小白,本文範例的 Linux 是用 Nginx + Certbot Docker 當 Reverse-Proxy,將 localhost:5000 映對成對 外 IP 的 443 Port 並自動取得 Let's Encrypt TLS 憑證,故不會有 mkcert 自建憑證不被信任問題。 若在內部使用跨主機登入,會遇到 x509: certificate signed by unknown authority 問題,需先信任 mkcert CA 根憑證。Windows 設定可參考這篇:https://blog.darkthread.net/blog/docker-trust-priv-registry-tls-cert/

# by 小白

謝謝黑大,我有找到mkcert產生的rootCA,參考https://docs.docker.com/engine/security/certificates/ 將pem轉成crt放到Client的/etc/docker/certs.d/host:5000/下面重啟docker,也試過丟到/usr/local/share/ca-certificates/並update-ca-certificate,但都無效

# by 小白

我找到問題了 黑大是直接pem更副檔名為crt,而我是用steakoverflow找的指令openssl x509 -outform der -in host.pem -out host.crt去轉pem為crt,看起來直接更副檔名放到/etc/docker/certs.d/host:5000/下重啟docker就能用了,用openssl轉反而不行= =

# by Jeffrey

to 小白,Linux 用的是 PEM 格式,直接用 host.pem 就好,用 openssl -outform der 轉成 DER 格式反而是錯的。PEM 與 DER 差異可參考保哥這篇:https://blog.miniasp.com/post/2018/04/21/PKI-Digital-Certificate-Format-Convertion-Notes

# by piyakker

黑大,好像有人抄襲文章? https://wayne-blog.com/2023-01-31/docker-private-registry/

# by Jeffrey

to piyakker, 謝謝告知。

Post a comment