基於OSS搭建跨區域部署的分散式Docker映象倉庫

易立發表於2016-03-09

基於OSS搭建跨區域部署的分散式Docker映象倉庫

Docker映象是Docker的核心價值之一,Docker映象倉庫(Registry)是用於Docker映象的管理和分發的基礎設施。現在已經有了Docker Hub等多家公有映象管理服務供應商,阿里雲容器Hub服務也是您在雲端的一個非常好的選擇。但是有些情況,為了更加靈活的部署控制和一些管控要求,您也許會考慮在雲端的部署一個私有映象倉庫。

為了滿足異地容災和就近訪問等需求,需要在不同的區域(region)部署分散式Docker應用;在不同的region中,為了提升部署速度並節省網路成本,需要在每個region部署私有Docker Registry。然而,這就會給分散式部署中的映象管理帶來很多挑戰。本文將結合阿里雲OSS的新特性來介紹跨域部署的Docker映象倉庫的解決方案。

14572203169236

阿里雲搭建Docker Registry入門

Docker Registry是儲存和網路密集型應用。Docker映象儲存需要使用大量的儲存資源,採用本地儲存無法滿足使用者對容量和可用性的需求;同時映象的上傳,下載需要高速的網路頻寬。Docker Registry自從2.1版本開始,就已經加入了對阿里雲開放儲存服務(OSS)的正式支援。這為Docker Registry提供一個支援海量儲存,高效能訪問,高可用,安全,低成本,無需運維的儲存後端。而且利用ECS構建私有倉庫可以使用OSS內部資料流量,降低公網網路流量成本。在集團內部和阿里雲的映象倉庫服務,我們都採用了OSS的物件儲存服務,來支援對內和對外的Docker映象管理和分發。

在阿里雲上ECS上搭建一個Docker Registry是非常方便的,最方便的方法是利用Docker映象的方式來進行安裝。

首先我們要在ECS上有一個Docker執行環境,你可以手工安裝Docker Engine到已有的ECS例項上;或者,利用Docker Machine的ECS驅動方便的建立一個新的Docker就緒的ECS例項。請參見入門指南

啟動一個使用OSS的儲存的Docker Registry也是非常簡單的,我推薦的方法是利用Docker Compose的方式配置和啟動:

一個包含最簡單的配置的docker-compose.yml如下

registry:
  restart: always
  image: "registry:2.3"
  ports:
    - 5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-beijing
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-beijing
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

這裡,我們將利用Docker Registry 2.3官方映象建立一個私有映象倉庫,通過環境變數的方式配置了OSS的Access Key ID, Access Key Secret, Region, Bucket等資訊。關於OSS配置的詳細資訊請參見官方文件

然後執行 docker-compose up -d 命令, 私有映象就啟動成功了。

我們可以在ECS例項上執行下面命令來驗證相關工作

docker pull node:5.7
docker tag node:5.7 127.0.0.1:5000/node:5.7
docker push 127.0.0.1:5000/node:5.7

執行結果如下,已經成功將映象推送成功

[root@iZ25cz6gdslZ ~]# docker pull node:5.7
5.7: Pulling from library/node
fdd5d7827f33: Already exists 
a3ed95caeb02: Pull complete 
0f35d0fe50cc: Already exists 
627b6479c8f7: Already exists 
67c44324f4e3: Already exists 
b52090f6ca00: Pull complete 
1df855d9e713: Pull complete 
Digest: sha256:cde7a4fca0a3dd2330977078c3773164b172a0ec582bafced6db955dca02a5c4
Status: Downloaded newer image for node:5.7
[root@iZ25cz6gdslZ ~]# docker tag node:5.7 127.0.0.1:5000/node:5.7
[root@iZ25cz6gdslZ ~]# docker push 127.0.0.1:5000/node:5.7
The push refers to a repository [127.0.0.1:5000/node]
5f70bf18a086: Mounted from ubuntu 
1967867932fe: Pushed 
6b4fab929601: Pushed 
550f16cd8ed1: Mounted from python 
44267ec3aa94: Mounted from java 
bd750002938c: Mounted from java 
917c0fc99b35: Mounted from java 
5.7: digest: sha256:64413fb300f4dd491397dbf16edbc8499c521640ac52e68bdfee8241a8d0dafe size: 2389

注意:一定要配置Docker Hub加速器呀,要不會有欲哭無淚的趕腳。

在生產環節中使用,您還需要新增Nginx等元件來增加TLS訪問,認證授權,負載均衡等能力。詳見官方參考),本文不再詳述。

分散式跨區域Docker Registry方案討論

回到正題,為了支援多區域部署Docker應用的需求,我們需要在每個region部署Docker Registry。然而如何在分散式的Docker Registry之間實現內容同步?我們有以下幾種可能的方案

  1. 當客戶端推送映象時,分別向不同region的Docker Registry推送。

    • 好處:沒有任何外部依賴
    • 不足:手工同步導致客戶端邏輯複雜;當擴充套件region之後需要手工同步已有映象
  2. 利用Docker Registry的通知機制,實現Web Hook;當一個Docker Registry收到映象推送完成事件之後,由Web Hook的實現向其他region的Docker Registry推送剛完成的映象

    • 好處:沒有任何外部依賴,自動化同步
    • 不足:基於事件的同步邏輯實現複雜,需要考慮網路中斷,region變更等多種邊界情況
  3. 利用儲存複製的機制,實現不同region的映象複製

    • 好處:自動化同步,實現簡單
    • 不足:需要底層儲存驅動支援

由於Docker Registry本身是無狀態的應用,非常適合採用資料複製的方案實現分散式部署。去年一系列公司提出了分散式Docker Registry的解決方案,大多基於其商業化的資料複製技術,比如NetApp在DockerCon的演講。

然而利用阿里雲OSS的新特性,Bucket跨區域複製和回源設定,我們也可以輕鬆實現一個大規模分散式的映象倉庫。在下面示例中:我們會把北京registry作為主registry,允許使用者推送、拉取映象;建立上海registry作為從registry,允許使用者拉取映象。其高層架構圖如下:

14571909981240

利用OSS跨區域複製輕鬆實現分散式映象倉庫

OSS的Bucket Cross-Region Replication是跨不同區域資料中心的自動化、非同步複製技術。它會將對源Bucket中的物件的改動(新建、覆蓋、刪除等)同步到目標Bucket。詳細資訊請參見幫助文件

首先,我們建立一個上海region的bucket,作為目標bucket

14571876877887

然後選擇北京region的bucket作為源bucket; 並配置跨區域複製規則到目標bucket
14571885643390

14571886754062

同步規則配置完成之後,等待幾分鐘同步完成的效果如下
14571877603740

在上海region的ECS例項上,我們利用上文的方法也建立一個Docker Registry,”docker-compose.yml”的配置如下,並配置上海region的OSS Bucket作為映象儲存

registry:
  restart: always
  image: registry:2.3
  ports:
    - 127.0.0.1:5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-shanghai
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-shanghai
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

然後執行docker-compose up -d命令啟動Docker Registry

我們可以通過下面的命令來驗證映象複製是否成功

# docker pull 127.0.0.1:5000/node:5.7
5.7: Pulling from node
fdd5d7827f33: Already exists 
a3ed95caeb02: Pull complete 
0f35d0fe50cc: Already exists 
627b6479c8f7: Already exists 
67c44324f4e3: Already exists 
b52090f6ca00: Pull complete 
1df855d9e713: Pull complete 
Digest: sha256:64413fb300f4dd491397dbf16edbc8499c521640ac52e68bdfee8241a8d0dafe
Status: Downloaded newer image for 127.0.0.1:5000/node:5.7

大家可以看到,無需任何程式設計,我們已經簡單地實現了分散式資料的Docker Registry的自動化資料同步。使用者可以在北京registry上push新的映象,在上海registry上pull映象,沒有任何的手工維護工作。

需要注意的是:OSS的bucket複製是單向的,所以我們要在部署方案中確定registry的主從關係。只有在主registry的映象是可以讀寫的,而在從registry中,映象應是隻讀的。本文中主registy在北京region,而從registry在上海region。

目前為止,這個方案還不夠完美。由於Bucket複製是非同步的,採用的是最終一致性。物件從源複製到目的bucket需要一定的時間,這取決於複製物件的大小。我們知道Docker映象是採用分層儲存機制,每個layer包含相應的blob物件,後設資料和digest資訊。其中layer的blob物件可能非常大,資料複製完成時間會比較長。

所以,當我們在上海registry拉取映象時,如果blob物件沒有複製完成,則我們會遇到如下”unknown blob”錯誤

# docker pull 127.0.0.1:5000/redis:2
2: Pulling from redis
fdd5d7827f33: Already exists 
a3ed95caeb02: Download complete 
3868e1e933d6: Pulling fs layer 
1d007c18c656: Pulling fs layer 
ad75a8697e9c: Waiting 
8de500daf5d7: Waiting 
788fee3bdabf: Waiting 
8f359895dbf8: Waiting 
unknown blob

目前實現對於時效性不敏感的場景,這個方案已經足夠。當然,也需要應用層做一些調整,在映象未複製完成之前,需要反覆嘗試等待複製完成。

如果使用者希望能夠立刻從上海region的registry訪問剛在北京region推送的映象,有沒有更好的解決方案?

利用OSS回源設定實現映象按需熱遷移

對於上面的問題一個自然的想法就是:如果在上海registry請求尚未同步完成的Docker layer資料時,就從北京region的源bucket中讀取物件,並返回。

為了減少開發的複雜度,我們嘗試使用OSS的回源設定(詳見幫助文件)來自動化這個過程。當上海region的bucket中所需blob物件不存在時,讓OSS可以從北京region的bucket中自動進行回源讀取;在將layer內容返回給Docker請求的同時,自動將內容複製到上海region的目標bucket。

我們在上海region的bucket上配置回源規則如下
14571903064338

這裡我們使用映象方式:將回源地址指向北京bucket的公網訪問地址
14571903652298

當然我們還需要對registry中的OSS driver的Stat和URLFor實現做一些調整,當Registry檢查到檔案的後設資料不存在時,強制通過回源方式返回北京registry中的內容。對Docker Registry的修改可以從Github訪問

您也可以直接利用編譯過的”registry.aliyuncs.com/denverdino/registry:2.3″映象來替換官方映象。只需修改上海region部署所用的”docker-compose.yml”的image值修改即可。

registry:
  restart: always
  image: registry.aliyuncs.com/denverdino/registry:2.3
  ports:
    - 127.0.0.1:5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-shanghai
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-shanghai
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

再次嘗試,我們已經近乎同時地從上海region的registry訪問剛剛在北京region推送的Docker映象了。在這裡,我們將非同步的物件複製,和同步的按需複製結合在一起,可以滿足絕大多數場景對分散式映象倉庫的要求。

大功告成!

總結

跨區域部署的Docker Registry可以在不同資料中心的使用者高效、簡單的利用Docker映象進行軟體交付、部署和運維;可以支援異地容災、分散式DevOps等場景。

在本文介紹的這個分散式、跨域部署的Docker Registry的方案中,無需額外的手工運維就可保證不同地域Docker映象倉庫的資料一致性。其技術要點如下:

  • 使用OSS作為Docker映象儲存實現,不同region的registry配置到本地region的bucket上
  • 利用OSS提供的跨區域bucket複製能力,在主從registry中實現自動資料複製
  • 在從registry中,如果映象layer物件存在於本地的OSS bucket中,則直接利用bucket中物件返回;
    如果映象layer物件還未同步成功,則回源到主registry的bucket中

感謝阿里雲OSS團隊一直以來的大力協助和支援。

歡迎大家使用阿里雲容器服務阿里雲Docker映象倉庫服務。它能幫助你大大加速雲端Docker應用的交付流程。


相關文章