若要寫開源的 Docker image,使用 Docker Hub 或 GitHub 分享 image 會非常方便。而今天要來聊聊,如果 image 只打算在企業內部共享的話,該如何做?
當然,Docker 官方有解決方案:使用 registry image,這可以建立一個自架的 registry 服務,就像 docker.io
一樣。
使用 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
這裡特別把 image 的 SHA256 拿來比對了一下,確實一模一樣。
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 已經把大多數困難的事都參數化了,若沒有很奇怪的需求,直接使用都不會有問題的。
到目前為止,這個服務已經有簡單的安全防護機制,可以實驗登入登出的過程。反過來說,當我們使用雲端的 registry 服務,正是需要登入登出過程,才能正常使用別人家開好的服務。
包括昨天提到的,目前筆者已知的 private registry 服務如下:
不同家提供的內容差異,主要都在價錢或存放位置的差異,而使用上都沒有差--把它們當成自己建的 private registry 來用就對了!
只要知道各家提供的 registry host 名稱,剩下的就是 login 與 push 到正確的 path 即可。而 docker login
指令的詳細過程都在上面了,因此持續整合串接 push 至 registry,或持續部署 pull 進機器,相信都不是問題了!