Docker映象倉庫清理的探索之路

用友雲平臺發表於2019-02-15

用友雲開發者中心是基於Docker容器進行微服務架構應用的落地與管理。相信各位同學在使用的過程中,會發現隨著Docker映象的增多,佔用磁碟空間也約來越多。這時我們需要清理私有映象倉庫中不需要的映象。但在實際操作時,才會發現這本以為很簡單的任務中卻暗藏玄機,遇到了不少的麻煩。在這裡我們分享一下清理映象倉庫時遇到的坑點。想要直接尋求解決方案的同學可以直接看第二部分。

一、那些年,我們在清理映象倉庫時走過的坑

坑點1:官方提供的介面並不能真正的刪除映象

這著實是最大的坑點。很多同學查資料發現,官方已經提供了刪除映象倉庫的API,所以可能相當然的以為直接使用就好,殊不知掉入了官方埋下的最大的坑點,也是本文要著手解決的核心問題:官方提供的刪除映象倉庫中映象的介面,僅僅是把manifest刪除了,真正的映象檔案還存在!官方並沒有提供刪除映象層的介面!這也就是說,當我們呼叫刪除映象的介面之後,僅僅是檢視映象的列表時看不到原映象了,然而原有映象仍然在磁碟中,佔用著寶貴的檔案儲存空間。

  坑點2:直接呼叫官方的刪除映象API,會返回405的錯誤碼

直接呼叫刪除映象的介面,可能會遇到以下錯誤提示:

「技術乾貨分享」Docker映象倉庫清理的探索之路

405,意味著方法不被允許。實際上,官方可能是處於安全性的考慮,在預設的情況下禁止了直接刪除映象的功能。若要開啟刪除映象功能,需要修改映象倉庫的配置檔案。具體操作為修改/etc/docker/registry/config.yml檔案,在storage下新增delete的許可之後,重啟映象倉庫服務。

  坑點3:使用官方提供的garbage-collect工具,會有無用的檔案殘留

官方為registry提供了garbage-collect(gc)工具清理映象的物理儲存,將沒有引用的layer刪除。

gc的清理過程分為兩部分:

1)mark:掃描所有的manifest,列出引用的layer;

2)sweep:掃描所有的layer,不在mark裡的layer將被清理刪除。

gc可以在dry-run的模式下執行(新增引數-d),只輸出gc資訊,不進行實際操作。我們可以通過這種方式來確認哪些映象會被清除。

使用gc工具清理映象的一個問題就是檔案清理得不夠乾淨,無法清理已經沒有tag的映象目錄,並且還殘存少部分檔案,從十KB到幾十KB不等。久而久之,垃圾檔案和目錄的數量會越來越多。

坑點4:garbage-collect不是事務操作,清理映象時可能會產生誤操作

gc不是事務操作,當gc過程中剛好有push操作時,則可能會誤刪資料。一個可行的解決辦法是手動更改映象倉庫的配置,暫時禁止映象的push操作。

在映象倉庫的配置檔案中可以配置read-only模式。當啟用read-only之後,再push映象時會得到405的錯誤。gc完成後取消read-only模式,再push映象即可。

坑點5:使用garbage-collect工具後,必須重啟映象倉庫才能正常使用

如果不重啟映象倉庫,則再次push該映象時可能會得到layer already exists錯誤:

「技術乾貨分享」Docker映象倉庫清理的探索之路

其可能的原因是映象被刪除後,倉庫的快取中還存有已經刪除的映象資訊,所以再次push會報層存在的錯誤。

二、兩種清理映象倉庫的方案

方案一:使用官方API + GC

使用官方提供的方法可以較為簡便的清理映象倉庫。整個清理過程可能需要幾百毫秒到幾秒的時間。此操作有一定的危險性,因此清理映象不宜過於頻繁。官方在git上也有類似描述。點選檢視:https://github.com/docker/docker-registry/issues/988

具體操作過程如下:

1、準備工作

在配置中許可刪除操作。修改映象倉庫的配置檔案,一般在如下路徑:

/etc/docker/registry/config.yml

在storage下新增delete的許可之後,重啟映象倉庫。

「技術乾貨分享」Docker映象倉庫清理的探索之路

用docker方式啟動的映象倉庫也可以新增環境變數:

REGISTRY_STORAGE_DELETE_ENABLED=true

2、獲取待刪映象的digest

獲取映象digest的API為:

GET /v2/<name>/manifests/<reference>

其中,name是倉庫名,reference是標籤,此時需要注意,呼叫時需要加上header內容:

Accept: application/vnd.docker.distribution.manifest.v2+json

其中Docker-Content-Digest的值就是映象的digest

3、呼叫官方的HTTP API V2刪除映象

刪除映象的API為:

DELETE /v2/<name>/manifests/<reference>

其中,name是倉庫名稱,reference是包含“sha256:”的digest。

4、呼叫GC清理映象檔案

使用gc工具的方式為:

bin/registry garbage-collect /etc/docker/registry/config.yml

gc清理需要時間,如果在gc過程中剛好有push操作,可能會產生未知的問題,建議設定read-only模式之後再進行gc,然後再改回來。

5、重啟docker registry

注意,如果不重啟會導致push相同映象時產生layer already exists錯誤。

方案二:使用第三方指令碼

在清理映象倉庫這件事上,業內已經有很多人進行過各種各樣的嘗試。本文挑選一種比較好的方式推薦使用。

1、宿主機安裝delete-docker-registry-image

可參考此命令的安裝和使用方式。參考連結:https://github.com/burnettk/delete-docker-registry-image

2、執行delete-docker-registry-image命令可以刪除某個倉庫(sb)

「技術乾貨分享」Docker映象倉庫清理的探索之路

或者某個具體的映象(如alpine:3.2)

「技術乾貨分享」Docker映象倉庫清理的探索之路

如果刪除某映象後該倉庫為空,可以用刪除倉庫的方式刪除此空倉。

「技術乾貨分享」Docker映象倉庫清理的探索之路

該工具也提供了dry-run的方式,只輸出待刪除的資訊不執行刪除操作。在命令後加上——dry-run即可。

3、重啟docker registry

跟gc方式一樣,刪除映象之後要重啟docker registry,不然還是會出現相同映象push不成功的問題。

以上就是本文推薦的兩種清理映象倉庫的兩種方案。第一種方案更多的使用了官方提供的工具,使用時相對更加安全,且無需額外安裝其他內容。第二種方案使用了第三方工具或指令碼,使用時更加靈活且簡便,且清理的更加徹底。具體操作時可根據自己的需求選擇方案。


相關文章