Node.js開發(fā)人員寶典:上手Docker從這里開始
譯文難度等級(jí):初學(xué)者
要求:Mac OS X(本教程假設(shè)你在使用Mac,但你也能找到Windows或Ubuntu的安裝指示,直接跳過“安裝”章節(jié))。
Docker剛過了第二個(gè)生日,但它仍是一項(xiàng)“新興”的強(qiáng)大技術(shù)。與本人交流過的許多開發(fā)人員對(duì)它已有所耳聞,但并沒有實(shí)際用過它。Docker讓你可以做一些確實(shí)很酷的事情,比如可以迅速測(cè)試開發(fā)中的應(yīng)用程序,所在環(huán)境與質(zhì)量保證/測(cè)試/生產(chǎn)環(huán)境一模一樣;或者與其他開發(fā)人員共享該應(yīng)用程序,以便盡快輕松熟悉情況。說到Docker,一個(gè)常打的比方就是它好比是現(xiàn)實(shí)生活中的集裝箱或樂高積木:它提供了一種基本單元,同時(shí)提供了一種不管是什么硬件,讓應(yīng)用程序都易于移植、易于遷移的方法。
我在本教程中將大致介紹一下Docker以及為何想要使用它、如何安裝它,然后我們要著手安裝一個(gè)Node容器,并且在該窗口里面建立一個(gè)Express入門級(jí)應(yīng)用程序。這篇教程內(nèi)容蠻長(zhǎng)!官方的Docker入門指南可以讓你更快地上手,我在這里的目的是,解釋這個(gè)過程中每一步出現(xiàn)的情況。
我們將介紹:
- 引言(Docker的性質(zhì)及為何使用它)
- 安裝•Docker Hub和Docker文件
- Docker Pull:獲取Ubuntu映像
- Docker Run:運(yùn)行我們的Ubuntu映像,及訪問容器
- Docker Commit:安裝node、npm和express,并提交變更內(nèi)容
- Docker Push:推回容器,那樣別人就能使用它
注意:我將以下列格式指代在你自己的終端中執(zhí)行的命令:
- $ command
并以下列格式指代容器里面的命令:
- $ root: command
引言
現(xiàn)在你可能已經(jīng)聽說過Docker。每天總會(huì)有專業(yè)報(bào)章提到它,或者你在推特/IRC上看到別人談?wù)撍?。它的人氣在過去幾年急劇飆升;大多數(shù)云服務(wù)提供商已經(jīng)支持它。如果你對(duì)它感到很好奇,但是還沒有用過它,那么這篇教程蠻適合你。
閑話少說,那么Docker到底是什么東東?這么說吧,Docker可能指幾個(gè)方面:
Docker客戶程序:這是在我們的機(jī)器上運(yùn)行的組件。它是docker二進(jìn)制代碼;只要我們打開終端,輸入$ docker pull或$ docker run,就要與之交互。它連接至處理所有繁重任務(wù)的docker守護(hù)程序,而守護(hù)程序可能在同一個(gè)主機(jī)上(以Linux為例),也可能在遠(yuǎn)地(我們與VirtualBox虛擬機(jī)進(jìn)行交互)。
Docker守護(hù)程序:這是處理諸多繁重任務(wù)的組件,比如構(gòu)建、運(yùn)行和分發(fā)Docker容器。
Docker映像:docker映像好比是我們應(yīng)用程序的藍(lán)圖。繼續(xù)說說上面的集裝箱/樂高積木那個(gè)比方,docker映像是用于實(shí)際構(gòu)建真正實(shí)例的藍(lán)圖。映像可能是Ubuntu之類的操作系統(tǒng),也有可能是你的Web應(yīng)用程序及其所有的必要程序包都已安裝的Ubuntu。
Docker容器:容器是用docker映像構(gòu)建而成的,它們是集裝箱/樂高積木的真正實(shí)例。它們可以啟動(dòng)、運(yùn)行、停止、刪除和移動(dòng)。
Docker Hub(注冊(cè)中心):Docker注冊(cè)中心是一臺(tái)托管的注冊(cè)中心服務(wù)器,可以存放Docker映像。Docker公司提供了一個(gè)公共Docker注冊(cè)中心,名為Docker Hub,我們會(huì)在本教程中用到它,但Docker公司提供了開放源代碼的整個(gè)系統(tǒng),那樣人們可以在自己的服務(wù)器上運(yùn)行,以私密方式存儲(chǔ)映像。
我們已經(jīng)明確了Docker的不同部分,下面介紹你可能想要使用它的幾個(gè)理由:
- 簡(jiǎn)化開發(fā)環(huán)境的配置;
- 在類似質(zhì)量保證/測(cè)試/生產(chǎn)環(huán)境的環(huán)境中,迅速測(cè)試應(yīng)用程序(相比虛擬機(jī),開銷較小);
- 與其他開發(fā)人員共享你的應(yīng)用程序和環(huán)境,這樣便于別人盡快熟悉情況。
- 能夠構(gòu)建不同的容器(這在調(diào)試中極其有用)
安裝
運(yùn)行容器、因而運(yùn)行Docker需要Linux機(jī)器。由于我們使用的是Mac,這就意味著我們需要虛擬機(jī)。為了讓安裝過程來得更容易,我們可以使用Boot2Docker,它可以安裝Boot2Docker管理工具VirtualBox,并在Docker已安裝的情況下在里面安裝虛擬機(jī)。
boot2docker
直接瀏覽到該鏈接,下載最新版本的Boot2Docker,并安裝它(截至本文截稿時(shí)最新版本是Boot2Docker-1.5.0.pkg)。
https://github.com/boot2docker/osx-installer/releases/latest
安裝完畢后,進(jìn)入到你的Applications文件夾,打開Boot2Docker。那會(huì)在VirtualBox里面打開一個(gè)新的終端,運(yùn)行幾個(gè)命令,這些命令的作用基本上就是啟動(dòng)已經(jīng)安裝了Docker的虛擬機(jī),然后設(shè)置幾個(gè)環(huán)境變量,那樣我們就能從終端訪問該虛擬機(jī)。如果你不想總是打開Boot2Docker以便與Docker進(jìn)行交互,只要運(yùn)行下面幾個(gè)命令:
- # 如果你還沒有新的虛擬機(jī),創(chuàng)建一個(gè)
- $ boot2docker init
- # 啟動(dòng)虛擬機(jī)
- $ boot2docker start
- # 設(shè)置必需的環(huán)境變量
- $ $(boot2docker shellinit)
現(xiàn)在輸入:
- $ docker run hello-world
這會(huì)讓Docker從Docker Hub下載hello-world映像,并啟動(dòng)基于它的容器。你的終端應(yīng)該會(huì)給出類似如下的輸出結(jié)果:
- Hello from Docker.
- This message shows that your installation appears to be working correctly.
好了!Docker已安裝完畢。
要是你遇到什么問題,歡迎留言交流,也可以在此(https://docs.docker.com/installation/mac/)參閱Docker的官方安裝指示。
#p#
Docker文件和Docker Hub
在探討下一步操作之前,我認(rèn)為明白我們?cè)趫?zhí)行$ docker run hello-world后發(fā)生的事情很重要,那樣你不僅僅是復(fù)制粘貼接下來的指示。docker run是我們用來啟動(dòng)基于映像的容器的基本命令,同時(shí)將命令傳送給它。在這里,我們說“Docker,啟動(dòng)基于映像hello-world的容器,不需要額外的命令。”然后,它從Docker Hub下載映像,并且啟動(dòng)VirtualBox虛擬機(jī)里面基于該映像的容器。但是hello-world映像來自哪里呢?這時(shí)候,Docker Hub有了用武之地。就像我們之前在引言部分提到的那樣,Docker Hub是公共注冊(cè)中心,含有與Docker一起使用的容器映像,以及由Docker、其他公司和個(gè)人構(gòu)建的容器映像。你在這里可以找到我們剛執(zhí)行的hello-world映像:
Docker Hub Hello-World映像(https://registry.hub.docker.com/u/library/hello-world/)
每個(gè)映像都是使用Docker文件構(gòu)建的。在hello-world映像的描述部分,你能找到Docker文件的鏈接(https://github.com/docker-library/hello-world/blob/master/Dockerfile),該文件只有短短3行:
- FROM scratch
- COPY hello /
- CMD [“/hello”]
Docker文件就是文本文件,含有如何構(gòu)建容器映像方面的Docker指示。映像就好比是機(jī)器快照,而容器好比是機(jī)器的實(shí)際的運(yùn)行實(shí)例。Docker文件總是會(huì)有這種格式:
- INSTRUCTION arguments
所以在我們的hello-world例子中,我們可以看一下含有Docker文件的GitHub軟件庫(kù)的根。該映像是用另一個(gè)名為“scratch”的映像構(gòu)建的(所有的Docker文件都是以FROM指示開頭),然后將hello文件復(fù)制到系統(tǒng)的根,最后運(yùn)行hello。你還能在這里找到hello文件的內(nèi)容(https://github.com/docker-library/hello-world/blob/master/hello.asm),包括我們?cè)诮K端中剛看到的輸出結(jié)果。
Docker Pull:下載Ubuntu映像
我們已知道了安裝的Docker已正確設(shè)置好,不妨開始使用它!下一步是獲得Ubuntu映像。想找到映像,我們可以進(jìn)入到Docker Hub網(wǎng)站(https://hub.docker.com),或者只要在終端中運(yùn)行:
- $ docker search ubuntu
這會(huì)給出名稱中含有Ubuntu的所有映像的列表。我的終端中顯示如下:
輸出結(jié)果按每個(gè)映像軟件庫(kù)中的星號(hào)數(shù)量來排序。你能看到上面有Official(官方)欄和Automated(自動(dòng))欄。
•官方映像是由docker-library項(xiàng)目維護(hù)的映像,并得到Docker團(tuán)隊(duì)的接受。這意味著,它們遵守這里的幾個(gè)準(zhǔn)則(https://docs.docker.com/docker-hub/official_repos/),其中一些位于git軟件庫(kù);對(duì)該軟件庫(kù)至少要有只讀權(quán),以便用戶能查看其內(nèi)容。你可以依賴那些映像,順利使用Docker。另外,與你需要使用USERNAME/IMAGE_NAME來獲取的其他映像相反,這些映像完全只要由IMAGE_NAME(比如Ubuntu)用命令來指代。所有Docker文件都呈現(xiàn)在這種組織體系中(https://github.com/docker-library)。
•自動(dòng)欄是指自動(dòng)構(gòu)建(Automated Build)映像。這完全意味著,映像是通過GitHub或BitBucker軟件庫(kù)里面的Docker文件構(gòu)建的;對(duì)它進(jìn)行更改后,它會(huì)自動(dòng)更新。
不妨下載官方的Ubuntu映像:
- $ docker pull ubuntu
$ docker pull IMAGE_NAME命令是明確下載映像的方式,但如果你使用$ docker run IMAGE_NAME命令,也能下載,就是Docker找不到你所指的那個(gè)映像。
Docker Run:運(yùn)行我們的Ubuntu映像,訪問容器
我們已經(jīng)有了Ubuntu映像(我們的藍(lán)圖)?,F(xiàn)在不妨啟動(dòng)基于該映像的新容器,并將命令傳送給它:
- $ docker run ubuntu /bin/echo ‘Hello world’
這在你的終端中應(yīng)該會(huì)給出消息“Hello World”。我們剛啟動(dòng)了一個(gè)運(yùn)行Ubuntu完全隔離的實(shí)例的容器,并執(zhí)行了命令,這很好,但是其實(shí)沒多大用處。
于是,現(xiàn)在不妨運(yùn)行新的容器以及Ubuntu,并連接到它:
- $ docker run -i -t ubuntu
請(qǐng)注意:run命令很龐大(查看$ docker help run),我們會(huì)在下一篇博文中更深入全面地介紹。
-t旗標(biāo)在我們的新容器里面分配了偽終端(pseudo-tty)或終端,-i旗標(biāo)讓我們可以獲取容器的標(biāo)準(zhǔn)流(STDIN),從而建立交互性連接。如果一切順利,你應(yīng)該可以連接至容器里面的終端,并顯示這樣的結(jié)果:
- $ root@c9989236296d:/#
運(yùn)行l(wèi)s –ls,就會(huì)發(fā)現(xiàn)運(yùn)行中的命令就在Ubuntu系統(tǒng)的根里面。
終端ubuntu
我認(rèn)為,有必要暫停一分鐘,考慮一下我們剛才執(zhí)行的操作。這正是容器的出色方面之一。我們剛下載并啟動(dòng)了運(yùn)行Ubuntu的容器。這一切在短短5分鐘內(nèi)發(fā)生的嗎(取決于你的互聯(lián)網(wǎng)連接速度)?拿這與下載虛擬機(jī)Ubuntu映像、啟動(dòng)新虛擬機(jī)作一下比較。后者可能是不是要花15分鐘至30分鐘?然后,構(gòu)建、停止及重啟新虛擬機(jī),這個(gè)過程要花多久?如果你把這些時(shí)間都算上去,就會(huì)發(fā)現(xiàn)使用容器可以節(jié)省大量時(shí)間!
#p#
Docker Commit:安裝node、npm和express,提交變更內(nèi)容
好了,鑒于我們已在運(yùn)行中的Ubuntu容器里面,不妨安裝運(yùn)行節(jié)點(diǎn)應(yīng)用程序所需要的工具(切記:你只需要執(zhí)行$ root:后面的部分):
- $ root: apt-get update
- $ root: apt-get install nodejs
- $ root: apt-get install nodejs-legacy
- $ root: apt-get install npm
請(qǐng)注意:我們需要安裝nodejs-legacy,才能運(yùn)行express-generator模塊。
運(yùn)行node -v應(yīng)該會(huì)得出輸出結(jié)果:
- $ root: node -v
- v0.10.25
節(jié)點(diǎn)安裝完畢后,我們可以直接從npm安裝express generator模塊:
- $ root: npm install -g express-generator
現(xiàn)在我們已有了容器,而且我們所需的一切都安裝在里面。不妨接下來退出容器:
- $ root: exit
我們退出容器后,Docker會(huì)停止運(yùn)行它。我們可以使用$ docker ps命令列出容器,不妨這么做:
- $ docker ps -a
終端容器
$ docker ps命令默認(rèn)情況下只顯示運(yùn)行中的容器,于是我們傳遞-a旗標(biāo),那樣我們就能查看剛退出的Ubuntu容器。
現(xiàn)在,我們可以使用該容器來構(gòu)建別人可以使用的新映像。為此,我們可以使用commit命令:
- $ docker commit -a "Your Name <youremail@email.com>" -m "node and express" CONTAINER_ID node-express:0.1
commit命令只有幾個(gè)參數(shù)。-a旗標(biāo)設(shè)定作者,你可以使用-m旗標(biāo)設(shè)定消息,最后我們可以引用容器ID和所創(chuàng)建容器的名稱,這里是node-express。我們還可以在映像名稱后面添加:0.1,為映像設(shè)定標(biāo)簽。如果我們運(yùn)行:
- $ docker images
我們應(yīng)該會(huì)看到:
終端容器
太棒了,你剛構(gòu)建了第一個(gè)Docker映像!
現(xiàn)在,不妨為剛創(chuàng)建的映像添加另一個(gè)標(biāo)簽。運(yùn)行:
- $ docker tag node-express:0.1 node-express:latest
給映像標(biāo)記特定的版本是個(gè)好做法,那樣人家知道自己在到底運(yùn)行哪個(gè)映像。添加latest標(biāo)簽大有幫助,那樣別人在下載映像時(shí)就能用名稱來指代你的映像(我們的例子中是node-express),Docker會(huì)自動(dòng)下載latest標(biāo)簽版本。如果你再次運(yùn)行$ docker images,就能看到我們的映像有兩行,但它們都有同一個(gè)ID,這意味著它們并不占用硬盤中的任何額外空間。
現(xiàn)在我們就可以啟動(dòng)想與映像一同使用的多個(gè)容器!不妨刪除舊的容器:
- $ docker ps -a
- $ docker rm YOUR_CONTAINER_ID
不妨運(yùn)行基于新映像的容器,使用-i -t旗標(biāo)連接到它,將主機(jī)(VirtualBox)的端口8080暴露為容器(虛擬機(jī))的端口3000:
- $ docker run -i -t -p 8080:3000 node-express
不妨使用我們已安裝的express-generator,構(gòu)建一個(gè)新的Node.js應(yīng)用程序:
- $ root: express mynodeapp
按終端中的指示操作后,進(jìn)入到應(yīng)用程序文件夾,安裝依賴項(xiàng),啟動(dòng)該應(yīng)用程序:
- $ root: cd mynodeapp
- $ root: npm install
- $ root: npm start
現(xiàn)在,我們已有了一個(gè)在容器里面運(yùn)行的Node.js應(yīng)用程序,暴露端口3000。想查看這個(gè)應(yīng)用程序,我們需要找到Boot2Docker虛擬機(jī)IP地址,為此打開另一個(gè)終端,運(yùn)行:
- $ boot2docker ip
- 192.168.59.103
另外切記:我們實(shí)際上暴露了容器的端口8080,以便訪問端口3000。于是,進(jìn)入到瀏覽器,打開:
- 192.168.59.103:8080
- website express
現(xiàn)在,你可能會(huì)想:光擁有一個(gè)運(yùn)行中的應(yīng)用程序就要費(fèi)這老大的勁!我早已有了開發(fā)環(huán)境,可以在30秒內(nèi)完成這一切!沒錯(cuò),確實(shí)如此,但是在本教程中,我們運(yùn)行的一個(gè)超級(jí)簡(jiǎn)單的應(yīng)用程序根本沒有許多依賴項(xiàng)。你在運(yùn)行依賴項(xiàng)要多得多的實(shí)際項(xiàng)目時(shí),可能需要開發(fā)環(huán)境擁有不同的程序包、Python、Redis、MongoDB、Postgres、Node.jsK io.js等。牽涉太多的方面,結(jié)果會(huì)讓在你的計(jì)算機(jī)中正常運(yùn)行的應(yīng)用程序在另一臺(tái)機(jī)器((或在質(zhì)量保證/測(cè)試/生產(chǎn)環(huán)境)中卻無(wú)法正常運(yùn)行,這就是Docker大受歡迎的主要原因?;氐奖窘坛痰囊圆糠?,通過提供一種獨(dú)立于硬件而執(zhí)行的基本單元,該基本單元還能輕松運(yùn)行、移動(dòng)和共享,Docker絕對(duì)改變了我們開發(fā)、測(cè)試及共享應(yīng)用程序的方式。
#p#
Docker Push:推送容器映像,那樣別人就能使用它
現(xiàn)在不妨共享我們這個(gè)“出色的”Ubuntu映像(已安裝了node、npm和express-generator),那樣別人也能使用它。退出運(yùn)行中的Node應(yīng)用程序和容器:
- # Ctrl+C to stop our node app
- $ root: exit
直接進(jìn)入到Docker Hub:http://hub.docker.com,設(shè)立一個(gè)免費(fèi)帳戶;
之后,回到終端,運(yùn)行:
- $ docker login
鑒于我們已通過命令行接口(CLI)登錄上去,可以將映像推送到Docker Hub。不妨先對(duì)它進(jìn)行更名,并為它添加用戶名,所以就像添加標(biāo)簽:
- $ docker tag node-express your_docker_hub_username/node-express
- $ docker rmi node-express
- $ docker push your_docker_hub_username/node-express
大功告成!現(xiàn)在,擁有Docker的人都可以執(zhí)行:
- $ docker pull your_docker_hub_username/node-express
擁有了與我們之前建立的環(huán)境一模一樣的環(huán)境,而Ubuntu、Node.js、npm和express-generator程序包一應(yīng)俱全。