Docker 是 2014 年最為火爆的技術(shù)之一,幾乎所有的程序員都聽說過它。Docker 是一種“輕量級”容器技術(shù),它幾乎動搖了傳統(tǒng)虛擬化技術(shù)的地位,現(xiàn)在國內(nèi)外已經(jīng)有越來越多的公司開始逐步使用 Docker 來替換現(xiàn)有的虛擬化平臺了。作為一名 Java 程序員,我們是時(shí)候一起把 Docker 學(xué)起來了!
本文會對虛擬化技術(shù)與 Docker 容器技術(shù)做一個(gè)對比,然后引出一些 Docker 的名詞術(shù)語,比如:容器、鏡像等,隨后將使用 Docker 搭建一個(gè) Java Web 運(yùn)行環(huán)境,最后將對本文做一個(gè)總結(jié)。
我們先來回顧一下傳統(tǒng)虛擬化技術(shù)的體系架構(gòu):
可見,我們在宿主機(jī)的操作系統(tǒng)上,可安裝了多個(gè)虛擬機(jī),而在每個(gè)虛擬機(jī)中,通過虛擬化技術(shù),實(shí)現(xiàn)了一個(gè)虛擬操作系統(tǒng),隨后,就可以在該虛擬操作系統(tǒng)上,安裝自己所需的應(yīng)用程序了。這一切看似非常簡單,但其中的技術(shù)細(xì)節(jié)是相當(dāng)高深莫測的,大神級人物都不一定說得清楚。
凡是使用過虛擬機(jī)的同學(xué),應(yīng)該都知道,啟動虛擬機(jī)就像啟動一臺計(jì)算機(jī),初始化過程是相當(dāng)慢的,我們需要等很久,才能看到登錄界面。一旦虛擬機(jī)啟動以后,就可以與宿主機(jī)建立網(wǎng)絡(luò)連接,確保虛擬機(jī)與宿主機(jī)之間是互聯(lián)互通的。不同的虛擬機(jī)之間卻是相互隔離的,也就是說,彼此并不知道對方的存在,但每個(gè)虛擬機(jī)占用的都是宿主機(jī)的硬件與網(wǎng)絡(luò)資源。
我們再來對比一下 Docker 技術(shù)的體系架構(gòu)吧:
可見,在宿主機(jī)的操作系統(tǒng)上,有一個(gè) Docker 服務(wù)在運(yùn)行(或者稱為“Docker 引擎”),在此服務(wù)上,我們可開啟多個(gè) Docker 容器,而每個(gè) Docker 容器中可運(yùn)行自己所需的應(yīng)用程序,Docker 容器之間也是相互隔離的,同樣地,都是占用的宿主機(jī)的硬件與網(wǎng)絡(luò)資源。
Docker 容器相對于虛擬機(jī)而言,除了在技術(shù)實(shí)現(xiàn)上完全不一樣以外,啟動速度較虛擬機(jī)而言有本質(zhì)的飛躍,啟動一個(gè)容器只在眨眼瞬間。不管是虛擬機(jī)還是 Docker 容器,它們都是為了隔離應(yīng)用程序的運(yùn)行環(huán)境,節(jié)省我們的硬件資源,為我們開發(fā)人員提供福利。
我們再來看看 Docker 的 Logo 吧:
很明顯,這是一只鯨魚,它托著許多集裝箱。我們可以把宿主機(jī)可當(dāng)做這只鯨魚,把相互隔離的容器可看成集裝箱,每個(gè)集裝箱中都包含自己的應(yīng)用程序。這 Logo 簡直的太形象了!
需要強(qiáng)調(diào)的是,筆者并非否定虛擬化技術(shù),而是想通過本文讓更多的讀者了解如何使用 Docker 技術(shù),讓大家知道除了虛擬化技術(shù)以外,還有另一種替代技術(shù),也能讓應(yīng)用程序隔離起來。
下面,我們將結(jié)合一個(gè) Java Web 應(yīng)用的部署過程,來描述如何“烹飪”Docker 這份美味佳肴。您準(zhǔn)備好了嗎?我們現(xiàn)在就開始!
首先,您要準(zhǔn)備一個(gè) CentOS 的操作系統(tǒng),虛擬機(jī)也行??傊?,可以通過 Linux 客戶端工具訪問到 CentOS 操作系統(tǒng)就行。
需要說明的是,Ubuntu 或其它 Linux 操作系統(tǒng)也能玩 Docker,只不過本文選擇了以 CentOS 為例,僅此而已。
CentOS 具體要求如下:
通過以下命令查看您的 CentOS 內(nèi)核:
uname -r
如果執(zhí)行以上命令后,輸出的內(nèi)核版本號低于 3.8,請參考下面的方法來來升級您的 Linux 內(nèi)核。
對于 CentOS 6.5 而言,內(nèi)核版本默認(rèn)是 2.6。首先,可通過以下命令安裝最新內(nèi)核:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.orgrpm -ivh http://www.elrepo.org/elrepo-release-6-5.el6.elrepo.noarch.rpmyum -y --enablerepo=elrepo-kernel install kernel-lt
隨后,編輯以下配置文件:
vi /etc/grub.conf
將default=1
修改為default=0
。
最后,通過reboot
命令重啟操作系統(tǒng)。
重啟后如果不出意外的話,再次查看內(nèi)核,您的 CentOS 內(nèi)核將會顯示為 3.10。
如果到這里,您和我們所期望的結(jié)果是一致的。恭喜您!下面我們就一起來安裝 Docker 了。
只需通過以下命令即可安裝 Docker 軟件:
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpmyum -y install docker-io
可使用以下命令,查看 Docker 是否安裝成功:
docker version
若輸出了 Docker 的版本號,則說明安裝成功了,可通過以下命令啟動 Docker 服務(wù):
service docker start
一旦 Docker 服務(wù)啟動完畢,我們下面就可以開始使用 Docker 了。
就像曾經(jīng)安裝軟件一樣,我們首先需要有一張刻錄了該軟件的光盤,如果您使用的是虛擬光驅(qū),那么就需要運(yùn)行一種名為“鏡像”的文件,通過它來安裝軟件。在 Docker 的世界里,也有一個(gè)名為“鏡像”的東西,已經(jīng)安裝我們所需的操作系統(tǒng),我們一般成為“Docker 鏡像”,本文簡稱“鏡像”。
那么問題來了,我們從哪里下載鏡像呢?
Docker 官網(wǎng) 確實(shí)已經(jīng)提供了所有的鏡像下載地址,可惜在國內(nèi)卻是無法訪問的。幸好國內(nèi)好心人提供了一個(gè) Docker 中文網(wǎng),在該網(wǎng)站上可以下載我們所需的 Docker 鏡像。
我們不妨還是以 CentOS 為例,通過以下步驟,下載一個(gè) CentOS 的鏡像。
首先,訪問 Docker 中文網(wǎng),在首頁中搜索名為“centos”的鏡像,在搜索的結(jié)果中,有一個(gè)“官方鏡像”,它就是我們所需的。
然后,進(jìn)入 CentOS 官方鏡像頁面,在“Pull this repository”輸入框中,有一段命令,把它復(fù)制下來,在自己的命令行上運(yùn)行該命令,隨后將立即下載該鏡像。
最后,使用以下命令查看本地所有的鏡像:
docker images
當(dāng)下載完成后,您應(yīng)該會看到:
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEdocker.cn/docker/centos centos6 25c5298b1a36 7 weeks ago 215.8 MB
如果看到以上輸出,說明您可以使用“docker.cn/docker/centos”這個(gè)鏡像了,或?qū)⑵浞Q為倉庫(Repository),該鏡像有一個(gè)名為“centos6”的標(biāo)簽(Tag),此外還有一個(gè)名為“25c5298b1a36 ”的鏡像 ID(可能您所看到的鏡像 ID 與此處的不一致,那是正?,F(xiàn)象,因?yàn)檫@個(gè)數(shù)字是隨機(jī)生成的)。此外,我們可以看到該鏡像只有 215.8 MB,非常小巧,而不像虛擬機(jī)的鏡像文件那樣龐大。
現(xiàn)在鏡像已經(jīng)有了,我們下面就需要使用該鏡像,來啟動容器。
容器是在鏡像的基礎(chǔ)上來運(yùn)行的,一旦容器啟動了,我們就可以登錄到容器中,安裝自己所需的軟件或應(yīng)用程序。既然鏡像已經(jīng)下載到本地,那么如何才能啟動容器呢?
只需使用以下命令即可啟動容器:
docker run -i -t -v /root/software/:/mnt/software/ 25c5298b1a36 /bin/bash
這條命令比較長,我們稍微分解一下,其實(shí)包含以下三個(gè)部分:
docker run <相關(guān)參數(shù)> <鏡像 ID> <初始命令>
其中,相關(guān)參數(shù)包括:
-i
:表示以“交互模式”運(yùn)行容器-t
:表示容器啟動后會進(jìn)入其命令行-v
:表示需要將本地哪個(gè)目錄掛載到容器中,格式:-v <宿主機(jī)目錄>:<容器目錄>假設(shè)我們的所有安裝程序都放在了宿主機(jī)的/root/software/
目錄下,現(xiàn)在需要將其掛載到容器的/mnt/software/
目錄下。
需要說明的是,不一定要使用“鏡像 ID”,也可以使用“倉庫名:標(biāo)簽名”,例如:docker.cn/docker/centos:centos6。
初始命令表示一旦容器啟動,需要運(yùn)行的命令,此時(shí)使用“/bin/bash”,表示什么也不做,只需進(jìn)入命令行即可。
為了搭建 Java Web 運(yùn)行環(huán)境,我們需要安裝 JDK 與 Tomcat,下面的過程均在容器內(nèi)部進(jìn)行。我們不妨選擇/opt/
目錄作為安裝目錄,首先需要通過cd /opt/
命令進(jìn)入該目錄。
首先,解壓 JDK 程序包:
tar -zxf /mnt/software/jdk-7u67-linux-x64.tar.gz -C .
然后,重命名 JDK 目錄:
mv jdk1.7.0_67/ jdk/
首先,解壓 Tomcat 程序包:
tar -zxf /mnt/software/apache-tomcat-7.0.55.tar.gz -C .
然后,重命名 Tomcat 目錄:
mv apache-tomcat-7.0.55/ tomcat/
首先,編輯.bashrc
文件
vi ~/.bashrc
然后,在該文件末尾添加如下配置:
export JAVA_HOME=/opt/jdkexport PATH=$PATH:$JAVA_HOME
最后,需要使用source
命令,讓環(huán)境變量生效:
source ~/.bashrc
我們需要編寫一個(gè)運(yùn)行腳本,當(dāng)啟動容器時(shí),運(yùn)行該腳本,啟動 Tomcat,具體過程如下:
首先,創(chuàng)建運(yùn)行腳本:
vi /root/run.sh
然后,編輯腳本內(nèi)容如下:
#!/bin/bashsource ~/.bashrcsh /opt/tomcat/bin/catalina.sh run
注意:這里必須先加載環(huán)境變量,然后使用 Tomcat 的運(yùn)行腳本來啟動 Tomcat 服務(wù)。
最后,為運(yùn)行腳本添加執(zhí)行權(quán)限:
chmod u+x /root/run.sh
當(dāng)以上步驟全部完成后,可使用exit
命令,退出容器。
隨后,可使用如下命令查看正在運(yùn)行的容器:
docker ps
此時(shí),您應(yīng)該看不到任何正在運(yùn)行的程序,因?yàn)閯偛乓呀?jīng)使用exit
命令退出的容器,此時(shí)容器處于停止?fàn)顟B(tài),可使用如下命令查看所有容器:
docker ps -a
輸出如下內(nèi)容:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES57c312bbaad1 docker.cn/docker/centos:centos6 "/bin/bash" 27 minutes ago Exited (0) 19 seconds ago naughty_goldstine
記住以上CONTAINER ID
(容器 ID),隨后我們將通過該容器,創(chuàng)建一個(gè)可運(yùn)行 Java Web 的鏡像。
使用以下命令,根據(jù)某個(gè)“容器 ID”來創(chuàng)建一個(gè)新的“鏡像”:
docker commit 57c312bbaad1 huangyong/javaweb:0.1
該容器的 ID 是“57c312bbaad1”,所創(chuàng)建的鏡像名是“huangyong/javaweb:0.1”,隨后可使用鏡像來啟動 Java Web 容器。
有必要首先使用docker images
命令,查看當(dāng)前所有的鏡像:
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEhuangyong/javaweb 0.1 fc826a4706af 38 seconds ago 562.8 MBdocker.cn/docker/centos centos6 25c5298b1a36 7 weeks ago 215.8 MB
可見,此時(shí)已經(jīng)看到了最新創(chuàng)建的鏡像“huangyong/javaweb:0.1”,其鏡像 ID 是“fc826a4706af”。正如上面所描述的那樣,我們可以通過“鏡像名”或“鏡像 ID”來啟動容器,與上次啟動容器不同的是,我們現(xiàn)在不再進(jìn)入容器的命令行,而是直接啟動容器內(nèi)部的 Tomcat 服務(wù)。此時(shí),需要使用以下命令:
docker run -d -p 58080:8080 --name javaweb huangyong/javaweb:0.1 /root/run.sh
稍作解釋:
-d
:表示以“守護(hù)模式”執(zhí)行/root/run.sh
腳本,此時(shí) Tomcat 控制臺不會出現(xiàn)在輸出終端上。-p
:表示宿主機(jī)與容器的端口映射,此時(shí)將容器內(nèi)部的 8080 端口映射為宿主機(jī)的 58080 端口,這樣就向外界暴露了 58080 端口,可通過 Docker 網(wǎng)橋來訪問容器內(nèi)部的 8080 端口了。--name
:表示容器名稱,用一個(gè)有意義的名稱命名即可。關(guān)于 Docker 網(wǎng)橋的內(nèi)容,需要補(bǔ)充說明一下。實(shí)際上 Docker 在宿主機(jī)與容器之間,搭建了一座網(wǎng)絡(luò)通信的橋梁,我們可通過宿主機(jī) IP 地址與端口號來映射容器內(nèi)部的 IP 地址與端口號,
在一系列參數(shù)后面的是“鏡像名”或“鏡像 ID”,怎么方便就怎么來。最后是“初始命令”,它是上面編寫的運(yùn)行腳本,里面封裝了加載環(huán)境變量并啟動 Tomcat 服務(wù)的命令。
當(dāng)運(yùn)行以上命令后,會立即輸出一長串“容器 ID”,我們可通過docker ps
命令來查看當(dāng)前正在運(yùn)行的容器。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES82f47923f926 huangyong/javaweb:0.1 "/root/run.sh" 4 seconds ago Up 3 seconds 0.0.0.0:58080->8080/tcp javaweb
在瀏覽器中,輸入以下地址,即可訪問 Tomcat 首頁:
http://192.168.65.132:58080/
注意:這里使用的是宿主機(jī)的 IP 地址,與對外暴露的端口號 58080,它映射容器內(nèi)部的端口號 8080。
通過本文,我們了解了 Docker 是什么?它與虛擬機(jī)的差別在哪里?以及如何安裝 Docker?如何下載 Docker 鏡像?如何運(yùn)行 Docker 容器?如何在容器內(nèi)安裝應(yīng)用程序?如何在容器上創(chuàng)建鏡像?如何以服務(wù)的方式啟動容器?這一切看似簡單,但操作也是相當(dāng)繁瑣的,不過熟能生巧,需要我們不斷地操練。
除了這種手工生成 Docker 鏡像的方式以外,還有一種更像是寫代碼一樣,可以自動地創(chuàng)建 Docker 鏡像的方式。只需要我們編寫一個(gè) Dockerfile 文件,隨后使用docker build
命令即可完成以上所有的手工操作。