的日常工作中會經(jīng)常進(jìn)行鏡像構(gòu)建操作。構(gòu)建Docker鏡像非常簡單,而且方法也有幾種。
3.3.1. 手工創(chuàng)建
這個方法最簡單直接的方法。其流程是啟動一個容器,在里面進(jìn)行一些列安裝、配置操作,然后運(yùn)行docker commit命令來將容器commit為一個新鏡像。
$ sudo docker run -t -i ubuntu bash root@c4be1df52810:/# apt-get update root@c4be1df52810:/# apt-get -y install redis-server root@c4be1df52810:/# exit
通過下面的命令得到剛才容器的ID號并進(jìn)行commit操作。
$ sudo docker ps -q -l c4be1df52810 $ sudo docker commit -m="manually created image" -a="bin liu" -run='{"CMD":["/usr/bin/redis-server"], "PortSpecs": ["6379"]}' c4be1df52810 liubin/redis:manually Warning: '-run' is deprecated, it will be removed soon. See usage. 744ce29b2fcf0ad7ad8b2a89c874db51376c3fdd65d1f4f0c6f233b72f8c3400
注意上面的警告信息,在docker commit命令指定-run選項(xiàng)已經(jīng)不被推薦了,這里為了說明這個例子而故意使用了這個選項(xiàng)。建議創(chuàng)建鏡像還是使用Dockerfile的方式,即能將創(chuàng)建過程代碼化、透明化,還能進(jìn)行版本化。
再次運(yùn)行docker images命令,就應(yīng)該能看到我們剛才通過docker commit命令創(chuàng)建的鏡像了(鏡像ID為744ce29b2fcf,鏡像名為liubin/redis:manually)。
3.3.2. 使用Dockerfile文件
使用Dockerfile構(gòu)建Docker鏡像
這是一個官方推薦的方法,即將構(gòu)建鏡像的過程代碼化,比如要安裝什么軟件,拷貝什么文件,進(jìn)行什么樣的配置等都用代碼進(jìn)行描述,然后運(yùn)行docker build命令來創(chuàng)建鏡像文件。官方的自動構(gòu)建即是基于保存在GitHub等代碼托管服務(wù)上的Dockerfile進(jìn)行的。Dockerfile即是具體的用于構(gòu)建的配置文件名,也是這類文件的類型名稱。
使用Dockerfile構(gòu)建Docker鏡像非常簡單,我們只需要創(chuàng)建一個名為Dockerfile的文件,并編寫相應(yīng)的安裝、配置腳本就可以了。我們還是以上面安裝Redis服務(wù)為例,看看如何使用Dockerfile構(gòu)建一個鏡像。
首先,創(chuàng)建一個redis文件夾(文件夾名任意,無任何限制),并進(jìn)入該文件夾,然后創(chuàng)建一個Dockerfile文件。這個文件的文件名是固定的,其內(nèi)容如下。
FROM ubuntu MAINTAINER bin liuRUN apt-get update RUN apt-get -y install redis-server EXPOSE 6379 ENTRYPOINT ["/usr/bin/redis-server"]
Dockerfile文件的語法非常簡單,每一行都是一條指令,注釋則以#開頭。每條指令都是“指令名稱 參數(shù)”的形式,指令名稱一般都是大寫。比如FROM指令表明了我們的鏡像的基礎(chǔ)鏡像(嚴(yán)格來說叫父鏡像,我們的所有操作都將以此鏡像為基礎(chǔ)),這里是ubuntu,但實(shí)際上它可以是存在的任何鏡像,比如liubin/ruby。RUN指令則用來在構(gòu)建過程中執(zhí)行各種命令、腳本,比如這里是apt-get命令,你也可以指定一個很復(fù)雜很長的腳本文件路徑。AUFS有42層文件系統(tǒng)的限制注 7,這時候我們可以通過在RUN指令中執(zhí)行多條命令,即cmd1 && cmd2 && cmd3 && ...這種形式就可以可避免該問題了。EXPOSE表示此鏡像將對外提供6379端口的服務(wù)。ENTRYPOINT則指定了啟動該鏡像時的默認(rèn)運(yùn)行程序。
注 7 https://github.com/dotcloud/docker/issues/1171
具體的Dockerfile語法在官方網(wǎng)站注 8有詳細(xì)說明,相信花個10分鐘就能通讀一遍,這里唯一比較容易混淆的就是ENTRYPOINT和CMD指令了,關(guān)于它們的區(qū)別,還是留作每位讀者自己的課題去研究一下吧。
注 8 https://docs.docker.com/reference/builder/
Dockerfile準(zhǔn)備好了之后,運(yùn)行docker build命令即可構(gòu)建鏡像了。
$ sudo docker build -t liubin/redis:dockerfile .
這里-t表示為構(gòu)建好的鏡像設(shè)置一個倉庫名稱和Tag(如果省略Tag的話則默認(rèn)使用latest)。最后的一個.表示Dockerfile文件的所在路徑,由于我們是在同一文件夾下運(yùn)行docker build命令,所以使用了.。
由于篇幅所限,這里我們就省略了docker build命令的輸出。不過如果你親自動手執(zhí)行docker build命令的話,那么從它的輸出應(yīng)該很容易理解,Dockerfile里的每一條指令,都對應(yīng)著構(gòu)建過程中的每一步,而且每一步都會生成一個新的類似容器的哈希值一樣的鏡像層ID。也正是這些層,使得鏡像能共享很多信息,并且能進(jìn)行版本管理、繼承和分支關(guān)系管理等。這除了能節(jié)省大量磁盤空間之外,還能在構(gòu)建鏡像的時候通過使用已經(jīng)構(gòu)建過的層(即緩存)來大大加快了鏡像構(gòu)建的速度。比如在我們在使用Dockerfile進(jìn)行構(gòu)建鏡像時,如果在某一步出錯了,那么實(shí)際上之前步驟的操作已經(jīng)被提交了,修改Dockerfile后再次進(jìn)行構(gòu)建的話,Docker足夠聰明到則會從出錯的地方開始重新構(gòu)建,因?yàn)榍懊娴闹噶顖?zhí)行結(jié)構(gòu)都已經(jīng)被緩存了。
如果你使用docker history命令來查看該鏡像的歷史信息,你會發(fā)現(xiàn)它的輸出和docker build的記錄是相匹配的,每一條Dockerfile中的指令都會創(chuàng)建一個鏡像層。此命令還能查看每個鏡像層所占空間大小,即SIZE列的內(nèi)容。比如本例中MAINTAINER這樣指令,實(shí)際上它只是關(guān)于鏡像的元數(shù)據(jù),并不占用額外的磁盤空間,所以它的層大小為0字節(jié)。而RUN apt-get -y install redis-server創(chuàng)建的層則會在鏡像中增加文件,所以是需要占用磁盤空間的。
自動構(gòu)建(Automated Builds)
Docker Hub的目的之一就是要成為應(yīng)用程序交換的中轉(zhuǎn)站,它還支持自動構(gòu)建功能。自動構(gòu)建的Dockerfile可以托管在GitHub或者Bitbucket上,當(dāng)我們將代碼提交并push到托管倉庫的時候,Docker Hub會自動通過webhook來啟動鏡像構(gòu)建任務(wù)。
配置自動構(gòu)建很簡單,只需要在Docker Hub中綁定GitHub或者Bitbucket賬號就可以了,如何具體操作這里不做詳細(xì)說明了。
3.3.3. 使用Packer
Packer注 10是一個通過配置文件創(chuàng)建一致機(jī)器鏡像(identical machine images)的非常方便的工具。Packer同樣出自Vagrant的作者M(jìn)itchell Hashimoto之手。它支持虛擬機(jī)VirtualBox和VMWare等虛擬機(jī)軟件,以及Amazon EC2、DigitalOcean、GCE以及OpenStack等云平臺,最新版的Packer也增加了對Docker的支持。
Packer的使用也比較簡單,這里我們就舉例說明了,讀者可以自己試一下。
3.4. 發(fā)布鏡像
如果你愿意,還可以將在本地制作鏡像push到Docker Hub上和其他人分享你的工作成果。
首先你要有一個Docker Hub賬號并已經(jīng)為登錄狀態(tài),這樣才能往Docker Hub上push鏡像文件。注冊Docker Hub賬號只能通過網(wǎng)站注冊注 11,這里我們假設(shè)各位讀者已經(jīng)擁有Docker Hub了賬號。
登錄Docker Hub通過docker login命令。
登錄成功后,我們就可以push鏡像了。注意這里我們沒有指定Tag,Docker知道如何去做。
$ sudo docker push liubin/redis
我們前面說過,鏡像文件是分層的,很多鏡像文件可以共用很多層。比如我們這次往服務(wù)器push鏡像的時候,實(shí)際push的只有一層(744ce29b2fcf)而已,這是因?yàn)槲覀兊溺R像文件是基于ubuntu這個base鏡像創(chuàng)建的,而ubuntu鏡像早已經(jīng)在遠(yuǎn)程倉庫中了。
我們在層744ce29b2fcf中對應(yīng)的操作是bash命令,并在容器中安裝了Redis。而這次修改只有不到6M的容量增加,而如果只是修改配置文件的話,那么一次push操作可能只需要耗費(fèi)幾K的網(wǎng)絡(luò)帶寬而已。
4. DockerCon14總結(jié)
首屆Docker大會(DockerCon14)于當(dāng)?shù)貢r間6月9日~6月10日在舊金山舉行。相對于計劃中的500個參會名額,最終有超過900人報名,并提交了超過150個演講申請。
關(guān)于這次Docker大會的更多信息可以參考其官方網(wǎng)站:http://www.dockercon.com/。
4.1. Docker官方發(fā)布的產(chǎn)品和服務(wù)
4.1.1. Docker 1.0的發(fā)布及商業(yè)支持
在這次大會上最重要的事情莫過于Docker 1.0的發(fā)布了。Docker 1.0已經(jīng)可以在Red Hat、Debian、Ubuntu、Fedora、SuSE等主流Linux系統(tǒng)下運(yùn)行,在功能、穩(wěn)定性以及軟件質(zhì)量上都已經(jīng)達(dá)到了企業(yè)使用的標(biāo)準(zhǔn),文檔也更加系統(tǒng)、完善。并且提供了Docker Hub云服務(wù),方便開發(fā)者和企業(yè)進(jìn)行應(yīng)用分發(fā)。最重要的是Docker, Inc.還宣布了對Docker的商業(yè)支持,尤其是對Docker 1.0版本的長期支持。此外,Docker, Inc.還會提供Docker相關(guān)的培訓(xùn)、咨詢等工作。
4.1.2. Docker Engine + Docker Hub
同時從1.0開始,Docker的架構(gòu)也發(fā)生了較大的變化。Docker已經(jīng)從單一的軟件轉(zhuǎn)變?yōu)榱艘粋€構(gòu)建、發(fā)布、運(yùn)行分布式應(yīng)用的平臺。
新的Docker平臺由Docker Engine(運(yùn)行環(huán)境 + 打包工具)、Docker Hub(API + 生態(tài)系統(tǒng))兩部分組成。
Docker引擎
Docker引擎是一組開源軟件,位于Docker平臺的核心位置。它提供了容器運(yùn)行時以及打包、管理等工具。
Docker Hub
Docker Hub是一個云端的分布式應(yīng)用服務(wù),它專注于內(nèi)容、協(xié)作和工作流。
Docker Hub可以看作是原來Docker index服務(wù)的升級版。Docker Hub除了可以托管Docker鏡像之外,還提供了包括更管理、團(tuán)隊協(xié)作、生命周期流程自動化等功能,以及對第三方工具和服務(wù)的集成。
在Docker, Inc.看來,典型的基于Docker Hub的軟件開發(fā)生命周期為:在本地基于Docker引擎開發(fā) -> 打包應(yīng)用程序 -> 將應(yīng)用程序push到Docker Hub -> 從Docker Hub上下載此應(yīng)用鏡像并運(yùn)行。它將鏡像構(gòu)建的任務(wù)交給Dev,將鏡像部署的任務(wù)交給Ops。