使用 Private Registry 分享 image

若要寫開源的 Docker image,使用 Docker Hub 或 GitHub 分享 image 會非常方便。而今天要來聊聊,如果 image 只打算在企業內部共享的話,該如何做?

當然,Docker 官方有解決方案:使用 registry image,這可以建立一個自架的 registry 服務,就像 docker.io 一樣。

啟動 registry 服務

使用 Docker 啟動 registry 服務就像啟動 MySQL 一樣簡單:

docker run -d -p 5000:5000 --restart=always --name registry registry:2

此為官方範例

接著昨天有提到下載 image 的方法,現在再複習一次:下面這幾個指令會到一樣的位置,下載一樣的 image。

docker pull alpine
docker pull docker.io/alpine
docker pull docker.io/library/alpine

這次 registry 位置為 localhost:5000,標版號的方法如下:

# build 的時候直接給 tag
# docker build -t localhost:5000/laravel .

# 標 tag 在現有的 image 上
docker tag laravel localhost:5000/laravel

接著使用 docker push 推到 registry 裡:

docker push localhost:5000/laravel

測試看看是否能正常下載:

# 確認 SHA256 值為 16318b4b39f2
docker images laravel
docker images localhost:5000/laravel

# 移除本機所有 image
docker rmi localhost:5000/laravel laravel

# 重新下載 image
docker pull localhost:5000/laravel

# 確認 SHA256 值一樣為
docker images laravel

加上 TLS

Server 準備好了,下一步是為這個 server 加上基本的防護--TLS

以下使用mkcert產生 certificate 來做示範的,詳細 TLS certificate 怎麼產生或匯入,就不特別說明了。

安裝好 mkcert 後,初始化 mkcert 並新增 localhost certificate:

# 初始化
mkcert -install

# 建立與匯入本機憑證
mkcert localhost

# 會產生 localhost.pem 與 localhost-key.pem 兩個檔,要給 Web server 設定用的
ls *.pem

可以使用 Nginx 做測試,先建立設定檔 nginx.conf

server {
server_name localhost;
listen 80;
listen 443 ssl;
ssl_certificate /etc/mkcert/localhost.pem;
ssl_certificate_key /etc/mkcert/localhost-key.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}

接著啟動 Nginx container

# 啟動 Nginx
docker run -d -v $PWD/localhost-key.pem:/etc/mkcert/localhost-key.pem -v $PWD/localhost.pem:/etc/mkcert/localhost.pem -v $PWD/nginx.conf:/etc/nginx/conf.d/default.conf -p 443:443 nginx:alpine

# 驗證
curl https://localhost/

只要能正常 curl 到內容,就算驗證完成了,用瀏覽器也可以看到 TLS 正常運作的標示:

到目前為止,確認 certificate 可以正常運作,下一步是把 certificate 用在 registry 裡

docker run -d \
--restart=always \
--name registry \
-v $PWD/localhost.pem:/etc/mkcert/localhost.pem \
-v $PWD/localhost-key.pem:/etc/mkcert/localhost-key.pem \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/mkcert/localhost.pem \
-e REGISTRY_HTTP_TLS_KEY=/etc/mkcert/localhost-key.pem \
-p 443:443 \
registry:2

這裡把 port 換成 443 了,所以 image 的名稱也得跟著換成 localhost/laravel

# tag 新的名字
docker tag localhost:5000/laravel localhost/laravel

# push registry
docker push localhost/laravel

加上身分驗證

若沒有驗證身分功能,registry 等於是免費倉庫任人塞爆,因此來實做看看官方提到的身分驗證

官方提醒:必須要有 TLS,身分驗證才會生效

首先先照官方提示的指令建立 basic auth 的帳密:

# 使用 htpasswd 指令
htpasswd -Bbn user pass > auth/htpasswd

# 沒有 htpasswd?跟 Docker 借用一下
docker run --rm -it httpd htpasswd -Bbn user pass > auth/htpasswd

接著一樣移除 container 重新啟動一個新的

docker run -d \
--restart=always \
--name registry \
-v $PWD/localhost.pem:/etc/mkcert/localhost.pem \
-v $PWD/localhost-key.pem:/etc/mkcert/localhost-key.pem \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/mkcert/localhost.pem \
-e REGISTRY_HTTP_TLS_KEY=/etc/mkcert/localhost-key.pem \
-v $PWD/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-p 443:443 \
registry:2

接下來會需要用到 docker login 指令,它的用法是

docker login [OPTIONS] [SERVER]

但目前它有個小問題是,當 SERVER 沒有 . 的時候,Docker 會認為它不是一個合法的 server,會回下面這個錯誤:

$ docker login localhost
unknown backend type for cloud login: localhost

GitHub issue 也有人提到這個問題,Docker 維護者的回應是,把 enable cloud experience 關掉即可:

以下為測試過程:

# 登入前 push 會回 no basic auth credentials 錯誤
docker push localhost/laravel

# 登入剛剛設定的 user / pass
docker login localhost

# 再一次就會成功
docker push localhost/laravel

# 使用 logout 把帳密清除
docker logout localhost

官方也有提供其他進階的身分驗證,有興趣的讀者可以再上官網參考。

自建 registry 還有很多地方要注意的,像是儲存空間設定,或是負載均衡器設定等,Docker registry 已經把大多數困難的事都參數化了,若沒有很奇怪的需求,直接使用都不會有問題的。

其他 private registry 服務

到目前為止,這個服務已經有簡單的安全防護機制,可以實驗登入登出的過程。反過來說,當我們使用雲端的 registry 服務,正是需要登入登出過程,才能正常使用別人家開好的服務。

包括昨天提到的,目前已知的 private registry 服務如下:

不同家提供的內容差異,主要都在價錢或存放位置的差異,而使用上都沒有差--把它們當成自己建的 private registry 來用就對了!

只要知道各家提供的 registry host 名稱,剩下的就是 login 與 push 到正確的 path 即可。而 docker login 指令的詳細過程都在上面了,因此持續整合串接 push 至 registry,或持續部署 pull 進機器,相信都不是問題了!

今日自我回顧

  • 建立一個測試用的 registry
  • 串接雲端 registry 也是使用相同的概念