Docker:搭建私有倉庫(Registry 2.4)

1、背景

首先,Docker Hub是一個很好的用於管理公共鏡像的地方,咱們能夠在上面找到想要的鏡像(Docker Hub的下載量已經達到數億次);並且咱們也能夠把本身的鏡像推送上去。可是,有的時候,使用場景須要咱們有一個私有的鏡像倉庫用於管理本身的鏡像,這個時候咱們就經過Registry來實現此目的。本文詳細介紹了本地鏡像倉庫Docker Registry & Portus的搭建過程。node

Registry做爲Docker的核心組件之一負責鏡像內容的存儲與分發,客戶端的docker pull以及push命令都將直接與registry進行交互。最第一版本的registry 由Python實現。因爲設計初期在安全性,性能以及API的設計上有着諸多的缺陷,該版本在0.9以後中止了開發,新的項目distribution(新的docker register被稱爲Distribution,你能夠在這裏找到文檔 。)來從新設計並開發下一代registry。新的項目由go語言開發,全部的API,底層存儲方式,系統架構都進行了全面的從新設計已解決上一代registry中存在的問題。2016年4月份rgistry 2.0正式發佈,docker 1.6版本開始支持registry 2.0,而八月份隨着docker 1.8 發佈,docker hub正式啓用2.1版本registry全面替代以前版本 registry。新版registry對鏡像存儲格式進行了從新設計並和舊版不兼容,docker 1.5和以前的版本沒法讀取2.0的鏡像。linux

另外,Registry 2.4版本以後支持了回收站機制,也就是能夠刪除鏡像了。在2.4版本以前是沒法支持刪除鏡像的,因此若是你要使用最好是大於Registry 2.4版本的。nginx

2、Registry V2的變化

Docker build鏡像時會爲每一個layer生成一串layer id,這個layer id是一個客戶端隨機生成的字符串,和鏡像內容無關。咱們能夠經過一個簡單的例子來查看。提供一個簡單的dockerfile。docker

加上–no-cache強制從新build。shell

接下來再次build。json

能夠看到使用cache層的layer id一致,其他layer的id都發生了變化。這種隨機layer id以及layer id與內容無關的設計會帶來不少的問題。swift

首先, registry v1經過id來判斷鏡像是否存在,客戶需不須要從新push,而因爲鏡像內容和id無關,再從新build後layer在內容不變的狀況下極可能id發生變化,形成沒法利用registry中已有layer反覆push相同內容。服務器端也會有重複存儲形成空間浪費。後端

其次,儘管id由32字節組成可是依然存在id碰撞的可能,在存在相同id的狀況下,後一個layer因爲id和倉庫中已有layer相同沒法被push到registry中,致使數據的丟失。用戶也能夠經過這個方法來探測某個id是否存在。安全

最後,一樣是因爲這個緣由若是程序惡意僞造大量layer push到registry中佔位會致使新的layer沒法被push到registry中。Docker官方從新設計新版registry的一個主要緣由也就是爲了解決該問題。bash

新版的registry吸收了舊版的教訓,在服務器端會對鏡像內容進行哈希,經過內容的哈希值來判斷layer在registry中是否存在,是否須要從新傳輸。這個新版本中的哈希值被稱爲digest是一個和鏡像內容相關的字符串,相同的內容會生成相同的digest。因爲digest和內容相關,所以只要從新build的內容相同理論上講無需從新push,可是因爲安全性的考量在特定狀況下layer依然要從新傳輸。因爲layer是按digest進行存儲,相對v1按照隨機id存儲能夠大幅減少磁盤空間佔用。registry服務端會對衝突digest進一步進行處理,同時因爲digest是由registry服務端生成,用戶沒法僞造digest也很大程度上保證了registry內容的安全性。

1)安全性改進

除了對image內容進行惟一性哈希外,新版registry還在鑑權方式以及layer權限上上進行了大幅度調整。鑑權方式:

舊版本的服務鑑權模型以下圖所示:

Docker:搭建私有倉庫(Registry 2.4)

該模型每次client端和registry的交互都要屢次和index打交道,新版本的鑑權模型去除了上圖中的第四第五步,以下圖所示:

Docker:搭建私有倉庫(Registry 2.4)

新版本的鑑權模型須要registry和authorization service在部署時分別配置好彼此的信息,並將對方信息做爲生成token的字符串,已減小後續的交互操做。新模型客戶端只須要和authorization service進行一次交互得到對應token便可和registry進行交互,減小了複雜的流程。同時registry和authorization service一一對應的方式也下降了被攻擊的可能。

2)權限控制

舊版的registry中對layer沒有任何權限控制,全部的權限相關內容都由index完成。在新版registry中加入了對layer的權限控制,每一個layer都有一個manifest來標識該layer由哪些repository共享,將權限作到repository級別。

3)Pull性能改進

舊版registry中鏡像的每一個layer都包含一個ancestry的json文件包含了父親layer的信息,所以當咱們pull鏡像時須要串行下載,下載完一個layer後才知道下一個layer的id是多少再去下載。以下圖所示:

Docker:搭建私有倉庫(Registry 2.4)

新版registry在image的manifest中包含了全部layer的信息,客戶端能夠並行下載全部的layer以下圖所示:

Docker:搭建私有倉庫(Registry 2.4)

4)其餘改進

– 全新的API。

– push和pull支持斷點。

– 後端存儲的插件。

– notification機制。

– 支持刪除鏡像,有了回收站機制。

3、安裝配置Registry

直接下載registry

v2.4.1的registry是把image文件放到了/var/lib/registry下。

最簡單方式啓動,啓動一個registry是很容易的,以下:

--name :指定容器名稱。

--privileged=true :CentOS7中的安全模塊selinux把權限禁掉了,參數給容器加特權,不加上傳鏡像會報權限錯誤。

這裏指定了一個/var/lib/registry的卷,是爲了把真實的鏡像數據儲存在主機上,而別在容器掛掉以後丟失數據。就算這樣,也仍是不保險。要是主機掛了呢?Docker官方建議能夠放到ceph 、 swift這樣的存儲裏,或是亞馬遜S3 、微軟Azure 、谷歌GCS 、阿里雲OSS之類的雲商那裏。Docker registry提供了配置文件,能夠從容器裏複製出來查看:

配置文件裏有一個storage ,按照這裏寫的配置,而後執行如下命令從新掛載這個文件來啓動registry就能夠了,有條件的話能夠去試一試:

Docker Registry配置完了,而後能夠在本機經過docker push 127.0.0.1:5000/xxx的方式推送鏡像到registry中(推送鏡像必須使用docker images可查看)。

可是隻能在本地使用127.0.0.1進行推送,不能在其餘主機push鏡像,包括本機經過IP地址也不能夠推送鏡像。當在其餘主機或者在本機經過IP推送鏡像時,docker默認會認爲地址是HTTPS加密的,而實際上咱們啓動registry時並無加密,因此會報錯。以下:

解決方案:

第一種:在須要推送鏡像的服務器上修改dockerd啓動參數【官方資料】,而後重啓docker。再推送鏡像時就會認爲這個地址是HTTP,不會報錯了,但在每一臺主機添加這個配置是很麻煩和危險的。另外我參照官方的作法和網上的作法根本沒有辦法解決。後來就在網上翻了好久找到了一個解決辦法,在docker host端的/etc/docker目錄下添加一個daemon.json文件,內容以下:

而後重啓docker,就OK了。

若是有多個地址,能夠這麼寫。

再次PUSH鏡像就成功了。

第二種:自建證書,讓register以TLS的方式啓動,【官方資料】。

1. 建立你本身的CA證書

2. 生成證書籤名請求

若是使用像dockerhub.ywnds.com這樣的FQDN鏈接register主機,則必須使用dockerhub.ywnds.com做爲CN(通用名稱)。不然,若是你使用IP地址鏈接你的register主機,CN能夠是任何相似你的名字等等:

3. 生成register主機的證書

若是你使用的是像dockerhub.ywnds.com這樣的FQDN來鏈接您的register主機,請運行如下命令以生成register主機的證書:

若是你使用的是IP,好比你的register主機10.99.73.10,你能夠運行下面的命令生成證書:

啓動register:

啓動後訪問會報錯:certificate signed by unknown authority,由於這是個自簽名的證書(沒有通過CA簽證的)。docker在驗證TLS時會自動讀取這個目錄下的證書。而後重啓docker便可。

解決方案是將剛生成的docker.crt複製到客戶端/etc/docker/certs.d/${registry}:${port}/ca.crt(${registry}是域名或你的register主機IP),若是該目錄不存在,請建立它。客戶端操做以下,須要把此證書複製到客戶端便可(改名爲ca.crt),操做以下:

此時再push就ok了,以下:

若是報cannot validate certificate for 10.99.73.10 because it doesn’t contain any IP SANs錯誤,檢查一下ca.crt證書是否正確,以及生成register主機的證書的時候使用的是域名仍是IP,其方式是否正確。

問題解決。至此, docker registry私有倉庫安裝成功。可是仍是有些缺點:只要有了證書,仍是誰均可以往庫裏推鏡像。簡單的解決方案就是使用用戶認證。

4、操做Registry鏡像

下面都是以http方式訪問,若是你加了證書就須要使用https進行訪問了。

1)列出當前全部鏡像

2)列出當前指定鏡像

3)搜索鏡像

4)確認Registry是否正常工做

返回{}就表示正常工做。

5)刪除鏡像

Docker倉庫在2.1版本中支持了刪除鏡像的API,但這個刪除操做只會刪除鏡像元數據,不會刪除層數據。在2.4版本中對這一問題進行了解決,增長了一個垃圾回收命令,刪除未被引用的層數據。但有一些條件限制,具體操做步驟以下:

啓動倉庫容器

這裏須要說明一點,在啓動倉庫時,需在配置文件中的storage配置中增長delete=true配置項,容許刪除鏡像,本次試驗採用以下配置文件:

查看數據進行倉庫容器中,經過du命令查看大小,能夠看到當前倉庫數據大小爲339M。

刪除鏡像對應的API以下:

name:鏡像名稱。

reference:鏡像對應sha256值。

首先查看要刪除鏡像的sha256

進行刪除操做

執行垃圾回收

命令:registry garbage-collect config.yml

再看數據大小

能夠看到鏡像數據已被刪除,從339M變成了88K。

PS:嘗試過直接在目錄中把鏡像刪除,而後重啓docker daemon,此鏡像也會刪除。

下載鏡像

PS:注意後面還能夠跟上tags,默認就是latest。

5、用戶認證

首先在registry生成用戶名hello和密碼world:

還得指定認證方式和認證文件等參數,從新啓動registry容器:

再次push就會失敗啦。

可是咱們能夠用用戶名hello和密碼world登陸,而後在進行push:

登陸成功後,再次push就會成功了。若是想退出登陸,使用logout便可。

Docker私有倉庫到這裏就結束了,我的感受仍是有不少不足。有興趣能夠看看:

喜歡 (16) or分享 (1)
相關文章
相關標籤/搜索