玩兒轉(zhuǎn)Docker 鏡像
前言
Docker是Docker.Inc公司開源的一個(gè)基于輕量級(jí)虛擬化技術(shù)的容器引擎項(xiàng)目,整個(gè)項(xiàng)目基于Go語言開發(fā),并遵從Apache 2.0協(xié)議。通過分層鏡像標(biāo)準(zhǔn)化和內(nèi)核虛擬化技術(shù),Docker使得應(yīng)用開發(fā)者和運(yùn)維工程師可以以統(tǒng)一的方式跨平臺(tái)發(fā)布應(yīng)用,并且以幾乎沒有額外開銷的情 況下提供資源隔離的應(yīng)用運(yùn)行環(huán)境。由于眾多新穎的特性以及項(xiàng)目本身的開放性,Docker在不到兩年的時(shí)間里迅速獲得諸多IT廠商的參與,其中更是包括 Google、Microsoft、VMware等業(yè)界行業(yè)***。同時(shí),Docker在開發(fā)者社區(qū)也是一石激起千層浪,許多如我之碼農(nóng)紛紛開始關(guān)注、學(xué) 習(xí)和使用Docker,許多企業(yè),尤其是互聯(lián)網(wǎng)企業(yè),也在不斷加大對(duì)Docker的投入,大有掀起一場(chǎng)容器革命之勢(shì)。
Docker鏡像命名解析
鏡像是Docker最核心的技術(shù)之一,也是應(yīng)用發(fā)布的標(biāo)準(zhǔn)格式。無論你是用docker pull image,或者是在Dockerfile里面寫FROM image,從Docker官方Registry下載鏡像應(yīng)該是Docker操作里面最頻繁的動(dòng)作之一了。那么在我們執(zhí)行docker pull image時(shí)背后到底發(fā)生了什么呢?在回答這個(gè)問題前,我們需要先了解下docker鏡像是如何命名的,這也是Docker里面比較容易令人混淆的一塊概念:Registry,Repository, Tag and Image。
下面是在本地機(jī)器運(yùn)行docker images的輸出結(jié)果:
我們可以發(fā)現(xiàn)我們常說的“ubuntu”鏡像其實(shí)不是一個(gè)鏡像名稱,而是代表了一個(gè)名為ubuntu的Repository,同時(shí)在這個(gè) Repository下面有一系列打了tag的Image,Image的標(biāo)記是一個(gè)GUID,為了方便也可以通過Repository:tag來引用。
那么Registry又是什么呢?Registry存儲(chǔ)鏡像數(shù)據(jù),并且提供拉取和上傳鏡像的功能。Registry中鏡像是通過Repository來組織的,而每個(gè)Repository又包含了若干個(gè)Image。
- Registry包含一個(gè)或多個(gè)Repository
- Repository包含一個(gè)或多個(gè)Image
- Image用GUID表示,有一個(gè)或多個(gè)Tag與之關(guān)聯(lián)
那么在哪里指定Registry呢?讓我們?cè)倮∫粋€(gè)更完整命名的鏡像吧:
上面我試圖去拉取一個(gè)ubuntu鏡像,并且指定了Registry為我本機(jī)搭建的私有Registry。下面是Docker CLI中pull命令的代碼片段 (docker/api/client/command.go中的CmdPull函數(shù))
在運(yùn)行時(shí),上面的taglessRemote變量會(huì)被傳入localhost:5000/ubuntu。上面代碼試圖從taglessRemote變量中解析出Registry的地址,在我們的例子中,它是localhost:5000。
那我們回過頭再來看看下面這個(gè)耳熟能詳?shù)膒ull命令背后的故事吧:
我們跟著上面的示例代碼,進(jìn)一步進(jìn)入解析函數(shù)ResolveRepositoryName的定義代碼片段(docker/registry/registry.go)
我們發(fā)現(xiàn),Docker CLI會(huì)判斷傳入的taglessRemote參數(shù)的***部分中是否包含’.’或者':’,如果存在則認(rèn)為***部分是Registry地址,否則會(huì)使用Docker官方默認(rèn)的Registry(即index.docker.io其實(shí)這里是一個(gè)Index Server,和Registry的區(qū)別留在后面再去深究吧),即上面代碼中高亮的部分。背后的故事還沒有結(jié)束,如果你向DockerHub上傳過鏡像,應(yīng)該記得你上傳的鏡像名稱格式為user-name/repository:tag,這樣用戶Bob和用戶Alice可以有相同名稱的Repository,通過用戶名前綴作為命名空間隔離,比如Bob/ubuntu和Alice/ubuntu。官方鏡像是通過用戶名library來區(qū)分的,具體代碼片段如下(docker/api/client/command.go中的CmdPull函數(shù))
我們回過頭再去看Docker命令行中解析Tag的邏輯吧(docker/api/client/command.go中的CmdPull函數(shù)):
代碼會(huì)試著在用戶輸入的Image名稱中找’ : ‘后面的tag,如果不存在,會(huì)使用默認(rèn)的‘DEFAULTTAG
’,即‘latest’。
也就是說在我們的例子里面,命令會(huì)被解析為下面這樣(注意,下面的命令不能直接運(yùn)行,因?yàn)镈ocker CLI不允許明確指定官方Registry地址)
#p#
配置Registry Mirror
Docker之所以這么吸引人,除了它的新穎的技術(shù)外, 圍繞官方Registry(Docker Hub)的生態(tài)圈也是相當(dāng)吸引人眼球的地方。在Docker Hub上你可以很輕松下載到大量已經(jīng)容器化好的應(yīng)用鏡像,即拉即用。這些鏡像中,有些是Docker官方維護(hù)的,更多的是眾多開發(fā)者自發(fā)上傳分享的。而且 你還可以在Docker Hub中綁定你的代碼托管系統(tǒng)(目前支持Github和Bitbucket)配置自動(dòng)生成鏡像功能,這樣Docker Hub會(huì)在你代碼更新時(shí)自動(dòng)生成對(duì)應(yīng)的Docker鏡像,是不是很方便?
不幸的是Docker Hub并沒有在國內(nèi)放服務(wù)器或者用國內(nèi)的CDN,下載個(gè)鏡像20分鐘最起碼,我等碼農(nóng)可耗不起這么長(zhǎng)時(shí)間,老板正站在身后催著我們搬運(yùn)代碼呢。為了克服跨 洋網(wǎng)絡(luò)延遲,一般有兩個(gè)解決方案:一是使用私有Registry,另外是使用Registry Mirror,我們下面一一展開聊聊.
方案一就是搭建或者使用現(xiàn)有的私有Registry,通過定期和Docker Hub同步熱門的鏡像,私有Registry上保存了一些鏡像的副本,然后大家可以通過
docker pull private-registry.com/user-name/ubuntu:latest
從這個(gè)私有Registry上拉取鏡像。因?yàn)檫@個(gè)方案需要定期同步Docker Hub鏡像,因此它比較適合于使用的鏡像相對(duì)穩(wěn)定,或者都是私有鏡像的場(chǎng)景。而且用戶需要顯式的映射官方鏡像名稱到私有鏡像名稱,私有Registry更 多被大家應(yīng)用在企業(yè)內(nèi)部場(chǎng)景。私有Registry部署也很方便,可以直接在Docker Hub上下載Registry鏡像,即拉即用,具體部署可以參考官方文檔。
方案二是使用Registry Mirror,它的原理類似于緩存,如果鏡像在Mirror中命中則直接返回給客戶端,否則從存放鏡像的Registry上拉取并自動(dòng)緩存在Mirror 中。最酷的是,是否使用Mirror對(duì)Docker使用者來講是透明的,也就是說在配置Mirror以后,大家可以仍然輸入docker pull ubuntu來拉取Docker Hub鏡像,除了速度變快了,和以前沒有任何區(qū)別。
了以更便捷的方式對(duì)接Docker Hub生態(tài)圈,使用Registry Mirror自然成為我的***。接下來我就和大家一起看看Docker使用Mirror來拉取鏡像的過程。下面的例子,我使用的是由DaoCloud提 供的Registry Mirror服務(wù),在申請(qǐng)開通Mirror服務(wù)后你會(huì)得到一個(gè)Mirror地址,然后我們要做的就是把這個(gè)地址配置在Docker Server啟動(dòng)腳本中,重啟Docker服務(wù)后Mirror配置就生效了(如何獲得Mirror服務(wù)可以參考本篇文章的附錄)
Ubuntu下配置Docker Registry Mirror的命令如下:
- sudo echo “DOCKER_OPTS=\”\$DOCKER_OPTS –registry-mirror=http://your-id.m.daocloud.io -d\”” >> /etc/default/docker
- sudo service docker restart
如果你是用的Boot2Docker,配置命令為:
- # 進(jìn)入Boot2Docker Start Shell,并執(zhí)行
- sudo su
- echo “EXTRA_ARGS=\”–registry-mirror=http://your-id.m.daocloud.io\”” >> /var/lib/boot2docker/profile
- exit
- # 重啟Boot2Docker
配置好Registry Mirror后,就可以拉取Docker鏡像了,經(jīng)我測(cè)試,使用DaoCloud的Mirror后,拉取常見鏡像的速度可以達(dá)到1.5M左右,具體速度在你的網(wǎng)絡(luò)環(huán)境可能會(huì)略有不同。
我們來看看配置了Registry Mirror后,Docker拉取鏡像的過程吧。首先是CLI拉取鏡像命令代碼片段(docker/api/client/command.go中的CmdPull函數(shù))
首先,Docker CLI會(huì)試圖獲得授權(quán),在我們的例子中會(huì)向https://index.docker.io/v1請(qǐng)求認(rèn)證,認(rèn)證完成后,認(rèn)證服務(wù)器會(huì)返回一個(gè)對(duì)應(yīng)的 Token。注意,這里用戶認(rèn)證與配置的Registry Mirror完全無關(guān),這樣我們就不用擔(dān)心使用Mirror的安全問題了。接著Docker CLI會(huì)調(diào)用Docker Server(即Docker daemon程序)的創(chuàng)建鏡像命令,Docker Server隨之會(huì)執(zhí)行具體的拉取鏡像動(dòng)作,代碼片段如下(docker/graph/pull.go的pullRepository函數(shù))
從代碼中可以發(fā)現(xiàn),如果配置了Registry Mirror,Docker Server會(huì)首先從Mirror中拉取鏡像,如果Mirror拉取失敗會(huì)退而求其次從鏡像中指定的Registry拉取。大家又可以松口氣了,就算配置 的Registry Mirror失效,也不會(huì)影響用戶拉取鏡像,只不過速度就。。。
鏡像拉下來后,就可以運(yùn)行容器了
#p#
附錄
下面我簡(jiǎn)單介紹下如何在DaoCloud申請(qǐng)一個(gè)Mirror服務(wù),首先登陸DaoCloud主頁
點(diǎn)擊”立刻注冊(cè)“,簡(jiǎn)單填寫個(gè)人信息后,隨即登陸并自動(dòng)跳轉(zhuǎn)到”控制臺(tái)“,按照提示點(diǎn)擊”啟動(dòng)你的加速器“按鈕。
啟動(dòng)成功后,你就擁有了一個(gè)你專用的Registry Mirror地址了,加速器鏈接就是你要設(shè)置”--registry-mirror
“的地址。目前每個(gè)用戶有10G的加速流量(Tips:如果流量不夠用可以邀請(qǐng)好友獲得獎(jiǎng)勵(lì)流量,邀請(qǐng)?jiān)蕉嗒?jiǎng)勵(lì)越多哦)
***,要感謝國內(nèi)存儲(chǔ)行業(yè)領(lǐng)先企業(yè)七牛云存儲(chǔ)在存儲(chǔ)和CDN方面提供的大力支持,正因?yàn)橛辛讼衿吲_@樣技術(shù)領(lǐng)先又熱心促進(jìn)互聯(lián)網(wǎng)生態(tài)發(fā)展的企業(yè)的積極參與,我們才能給開發(fā)者提供更多高質(zhì)量的服務(wù)。
***,要感謝國內(nèi)存儲(chǔ)行業(yè)領(lǐng)先企業(yè)七牛云存儲(chǔ)在存儲(chǔ)和CDN方面提供的大力支持,正因?yàn)橛辛讼衿吲_@樣技術(shù)領(lǐng)先又熱心促進(jìn)互聯(lián)網(wǎng)生態(tài)發(fā)展的企業(yè)的積極參與,我們才能給開發(fā)者提供更多高質(zhì)量的服務(wù)。
結(jié)語
今天和大家一起聊了聊Docker在拉取鏡像時(shí)如何解析鏡像和執(zhí)行拉取動(dòng)作的,以及如何通過設(shè)置Registry Mirror克服網(wǎng)絡(luò)延時(shí),加速拉取過程。涉及到的代碼只集中在Docker CLI和Docker Server,在很多方面并沒有展開,比如Registry是如何響應(yīng)以及如何和Index Server聯(lián)動(dòng)的,只能留給下次再和大家詳細(xì)探討了。
作者簡(jiǎn)介
孫宏亮,DaoCloud初創(chuàng)團(tuán)隊(duì)成員,軟件工程師,浙江大學(xué)計(jì)算機(jī)科學(xué)專業(yè)應(yīng)屆畢業(yè)研究生。讀研期間活躍在PaaS和Docker開源社區(qū),對(duì) Cloud Foundry有深入研究和豐富實(shí)踐,擅長(zhǎng)底層平臺(tái)代碼分析,對(duì)分布式平臺(tái)的架構(gòu)有一定經(jīng)驗(yàn),撰寫了大量有深度的技術(shù)博客。2014年末以合伙人身份加入 DaoCloud團(tuán)隊(duì),致力于傳播以Docker為主的容器的技術(shù),推動(dòng)互聯(lián)網(wǎng)應(yīng)用的容器化步伐。