Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
通過 Docker 化一個博客網(wǎng)站來開啟我們的 Docker 之旅
這篇文章包含 Docker 的基本概念,以及如何通過創(chuàng)建一個定制的 Dockerfile 來 Docker 化Dockerize一個應(yīng)用。
Docker 是一個過去兩年來從某個 idea 中孕育而生的有趣技術(shù),公司組織們用它在世界上每個角落來部署應(yīng)用。在今天的文章中,我將講述如何通過“Docker 化Dockerize”一個現(xiàn)有的應(yīng)用,來開始我們的 Docker 之旅。這里提到的應(yīng)用指的就是這個博客!
什么是 Docker?
當(dāng)我們開始學(xué)習(xí) Docker 基本概念時,讓我們先去搞清楚什么是 Docker 以及它為什么這么流行。Docker 是一個操作系統(tǒng)容器管理工具,它通過將應(yīng)用打包在操作系統(tǒng)容器中,來方便我們管理和部署應(yīng)用。
容器 vs. 虛擬機
容器和虛擬機并不完全相似,它是另外一種提供操作系統(tǒng)虛擬化的方式。它和標(biāo)準(zhǔn)的虛擬機還是有所不同。
標(biāo)準(zhǔn)的虛擬機一般會包括一個完整的操作系統(tǒng)、操作系統(tǒng)軟件包、最后還有一至兩個應(yīng)用。這都得益于為虛擬機提供硬件虛擬化的管理程序。這樣一來,一個單一的服務(wù)器就可以將許多獨立的操作系統(tǒng)作為虛擬客戶機運行了。
容器和虛擬機很相似,它們都支持在單一的服務(wù)器上運行多個操作環(huán)境,只是,在容器中,這些環(huán)境并不是一個個完整的操作系統(tǒng)。容器一般只包含必要的操作系統(tǒng)軟件包和一些應(yīng)用。它們通常不會包含一個完整的操作系統(tǒng)或者硬件的虛擬化。這也意味著容器比傳統(tǒng)的虛擬機開銷更少。
容器和虛擬機常被誤認為是兩種對立的技術(shù)。虛擬機采用一個物理服務(wù)器來提供全功能的操作環(huán)境,該環(huán)境會和其余虛擬機一起共享這些物理資源。容器一般用來隔離一個單一主機上運行的應(yīng)用進程,以保證隔離后的進程之間不能相互影響。事實上,容器和?BSD Jails以及chroot進程的相似度,超過了和完整虛擬機的相似度。
Docker 在容器之上提供了什么
Docker 本身不是一個容器運行環(huán)境,事實上,只是一個與具體實現(xiàn)無關(guān)的容器技術(shù),Docker 正在努力支持 Solaris Zones[1] 和BSD Jails[2]。Docker 提供了一種管理、打包和部署容器的方式。雖然一定程度上,虛擬機多多少少擁有這些類似的功能,但虛擬機并沒有完整擁有絕大多數(shù)的容器功能,即使擁有,這些功能用起來都并沒有 Docker 來的方便或那么完整。
現(xiàn)在,我們應(yīng)該知道 Docker 是什么了,然后,我們將從安裝 Docker,并部署一個公開的預(yù)構(gòu)建好的容器開始,學(xué)習(xí) Docker 是如何工作的。
從安裝開始
默認情況下,Docker 并不會自動被安裝在您的計算機中,所以,第一步就是安裝 Docker 軟件包;我們的教學(xué)機器系統(tǒng)是 Ubuntu 14.0.4,所以,我們將使用 Apt 軟件包管理器,來執(zhí)行安裝操作。
# apt-get install docker.io
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
aufs-tools cgroup-lite git git-man liberror-perl
Suggested packages:
btrfs-tools debootstrap lxc rinse git-daemon-run git-daemon-sysvinit git-doc
git-el git-email git-gui gitk gitweb git-arch git-bzr git-cvs git-mediawiki
git-svn
The following NEW packages will be installed:
aufs-tools cgroup-lite docker.io git git-man liberror-perl
0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
Need to get 7,553 kB of archives.
After this operation, 46.6 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
為了檢查當(dāng)前是否有容器運行,我們可以執(zhí)行docker命令,加上ps選項
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker命令中的ps功能類似于 Linux 的ps命令。它將顯示可找到的 Docker 容器及其狀態(tài)。由于我們并沒有啟動任何 Docker 容器,所以命令沒有顯示任何正在運行的容器。
部署一個預(yù)構(gòu)建好的 nginx Docker 容器
我比較喜歡的 Docker 特性之一就是 Docker 部署預(yù)先構(gòu)建好的容器的方式,就像yum和apt-get部署包一樣。為了更好地解釋,我們來部署一個運行著 nginx web 服務(wù)器的預(yù)構(gòu)建容器。我們可以繼續(xù)使用docker命令,這次選擇run選項。
# docker run -d nginx
Unable to find image 'nginx' locally
Pulling repository nginx
5c82215b03d1: Download complete
e2a4fb18da48: Download complete
58016a5acc80: Download complete
657abfa43d82: Download complete
dcb2fe003d16: Download complete
c79a417d7c6f: Download complete
abb90243122c: Download complete
d6137c9e2964: Download complete
85e566ddc7ef: Download complete
69f100eb42b5: Download complete
cd720b803060: Download complete
7cc81e9a118a: Download complete
docker命令的run選項,用來通知 Docker 去尋找一個指定的 Docker 鏡像,然后啟動運行著該鏡像的容器。默認情況下,Docker 容器運行在前臺,這意味著當(dāng)你運行docker run命令的時候,你的 shell 會被綁定到容器的控制臺以及運行在容器中的進程。為了能在后臺運行該 Docker 容器,我們使用了-d(detach)標(biāo)志。
再次運行docker ps命令,可以看到 nginx 容器正在運行。
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6d31ab01fc9 nginx:latest nginx -g 'daemon off 4 seconds ago Up 3 seconds 443/tcp, 80/tcp desperate_lalande
從上面的輸出信息中,我們可以看到正在運行的名為desperate_lalande的容器,它是由nginx:latest image(LCTT 譯注: nginx 最新版本的鏡像)構(gòu)建而來得。
Docker 鏡像
鏡像是 Docker 的核心特征之一,類似于虛擬機鏡像。和虛擬機鏡像一樣,Docker 鏡像是一個被保存并打包的容器。當(dāng)然,Docker 不只是創(chuàng)建鏡像,它還可以通過 Docker 倉庫發(fā)布這些鏡像,Docker 倉庫和軟件包倉庫的概念差不多,它讓 Docker 能夠模仿yum部署軟件包的方式來部署鏡像。為了更好地理解這是怎么工作的,我們來回顧docker run執(zhí)行后的輸出。
# docker run -d nginx
Unable to find image 'nginx' locally
我們可以看到第一條信息是,Docker 不能在本地找到名叫 nginx 的鏡像。這是因為當(dāng)我們執(zhí)行docker run命令時,告訴 Docker 運行一個基于 nginx 鏡像的容器。既然 Docker 要啟動一個基于特定鏡像的容器,那么 Docker 首先需要找到那個指定鏡像。在檢查遠程倉庫之前,Docker 首先檢查本地是否存在指定名稱的本地鏡像。
因為系統(tǒng)是嶄新的,不存在 nginx 鏡像,Docker 將選擇從 Docker 倉庫下載之。
Pulling repository nginx
5c82215b03d1: Download complete
e2a4fb18da48: Download complete
58016a5acc80: Download complete
657abfa43d82: Download complete
dcb2fe003d16: Download complete
c79a417d7c6f: Download complete
abb90243122c: Download complete
d6137c9e2964: Download complete
85e566ddc7ef: Download complete
69f100eb42b5: Download complete
cd720b803060: Download complete
7cc81e9a118a: Download complete
這就是第二部分輸出信息顯示給我們的內(nèi)容。默認情況下,Docker 會使用 Docker Hub[3] 倉庫,該倉庫由 Docker 公司維護。
和 Github 一樣,在 Docker Hub 創(chuàng)建公共倉庫是免費的,私人倉庫就需要繳納費用了。當(dāng)然,部署你自己的 Docker 倉庫也是可以的,事實上只需要簡單地運行docker run registry命令就行了。但在這篇文章中,我們的重點將不是講解如何部署一個定制的注冊服務(wù)。
關(guān)閉并移除容器
在我們繼續(xù)構(gòu)建定制容器之前,我們先清理一下 Docker 環(huán)境,我們將關(guān)閉先前的容器,并移除它。
我們利用docker命令和run選項運行一個容器,所以,為了停止同一個容器,我們簡單地在執(zhí)行docker命令時,使用kill選項,并指定容器名。
# docker kill desperate_lalande
desperate_lalande
當(dāng)我們再次執(zhí)行docker ps,就不再有容器運行了
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
但是,此時,我們這是停止了容器;雖然它不再運行,但仍然存在。默認情況下,docker ps只會顯示正在運行的容器,如果我們附加-a(all) 標(biāo)識,它會顯示所有運行和未運行的容器。
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6d31ab01fc9 5c82215b03d1 nginx -g 'daemon off 4 weeks ago Exited (-1) About a minute ago desperate_lalande
為了能完整地移除容器,我們在用docker命令時,附加rm選項。
# docker rm desperate_lalande
desperate_lalande
雖然容器被移除了;但是我們?nèi)該碛锌捎玫?span style="border:0px;font-style:inherit;font-variant:inherit;font-weight:700;line-height:inherit;vertical-align:baseline;">nginx鏡像(LCTT 譯注:鏡像緩存)。如果我們重新運行docker run -d nginx,Docker 就無需再次拉取 nginx 鏡像即可啟動容器。這是因為我們本地系統(tǒng)中已經(jīng)保存了一個副本。
為了列出系統(tǒng)中所有的本地鏡像,我們運行docker命令,附加images選項。
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
nginx latest 9fab4090484a 5 days ago 132.8 MB
構(gòu)建我們自己的鏡像
截至目前,我們已經(jīng)使用了一些基礎(chǔ)的 Docker 命令來啟動、停止和移除一個預(yù)構(gòu)建好的普通鏡像。為了“Docker 化(Dockerize)”這篇博客,我們需要構(gòu)建我們自己的鏡像,也就是創(chuàng)建一個?Dockerfile。
在大多數(shù)虛擬機環(huán)境中,如果你想創(chuàng)建一個機器鏡像,首先,你需要建立一個新的虛擬機、安裝操作系統(tǒng)、安裝應(yīng)用,最后將其轉(zhuǎn)換為一個模板或者鏡像。但在 Docker 中,所有這些步驟都可以通過 Dockerfile 實現(xiàn)全自動。Dockerfile 是向 Docker 提供構(gòu)建指令去構(gòu)建定制鏡像的方式。在這一章節(jié),我們將編寫能用來部署這個博客的定制 Dockerfile。
理解應(yīng)用
我們開始構(gòu)建 Dockerfile 之前,第一步要搞明白,我們需要哪些東西來部署這個博客。
這個博客本質(zhì)上是由一個靜態(tài)站點生成器生成的靜態(tài) HTML 頁面,這個生成器是我編寫的,名為?hamerkop。這個生成器很簡單,它所做的就是生成該博客站點。所有的代碼和源文件都被我放在了一個公共的Github 倉庫[4]。為了部署這篇博客,我們要先從 Github 倉庫把這些內(nèi)容拉取下來,然后安裝Python和一些Python模塊,最后執(zhí)行hamerkop應(yīng)用。我們還需要安裝nginx,來運行生成后的內(nèi)容。
截止目前,這些還是一個簡單的 Dockerfile,但它卻給我們展示了相當(dāng)多的 Dockerfile 語法[5])。我們需要克隆 Github 倉庫,然后使用你最喜歡的編輯器編寫 Dockerfile,我選擇vi。
# git clone https://github.com/madflojo/blog.git
Cloning into 'blog'...
remote: Counting objects: 622, done.
remote: Total 622 (delta 0), reused 0 (delta 0), pack-reused 622
Receiving objects: 100% (622/622), 14.80 MiB | 1.06 MiB/s, done.
Resolving deltas: 100% (242/242), done.
Checking connectivity... done.
# cd blog/
# vi Dockerfile
FROM - 繼承一個 Docker 鏡像
第一條 Dockerfile 指令是FROM指令。這將指定一個現(xiàn)存的鏡像作為我們的基礎(chǔ)鏡像。這也從根本上給我們提供了繼承其他 Docker 鏡像的途徑。在本例中,我們還是從剛剛我們使用的nginx開始,如果我們想從頭開始,我們可以通過指定ubuntu:latest來使用UbuntuDocker 鏡像。
## Dockerfile that generates an instance of http://bencane.com
FROM nginx:latest
MAINTAINER Benjamin Cane <ben@bencane.com>
除了FROM指令,我還使用了MAINTAINER,它用來顯示 Dockerfile 的作者。
Docker 支持使用#作為注釋,我將經(jīng)常使用該語法,來解釋 Dockerfile 的部分內(nèi)容。
運行一次測試構(gòu)建
因為我們繼承了?nginxDocker鏡像,我們現(xiàn)在的 Dockerfile 也就包括了用來構(gòu)建nginx鏡像的Dockerfile[6] 中所有指令。這意味著,此時我們可以從該 Dockerfile 中構(gòu)建出一個 Docker 鏡像,然后以該鏡像運行一個容器。雖然,最終的鏡像和nginx鏡像本質(zhì)上是一樣的,但是我們這次是通過構(gòu)建 Dockerfile 的形式,然后我們將講解 Docker 構(gòu)建鏡像的過程。
想要從 Dockerfile 構(gòu)建鏡像,我們只需要在運行?docker命令的時候,加上build選項。
# docker build -t blog /root/blog
Sending build context to Docker daemon 23.6 MB
Sending build context to Docker daemon
Step 0 : FROM nginx:latest
---> 9fab4090484a
Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>
---> Running in c97f36450343
---> 60a44f78d194
Removing intermediate container c97f36450343
Successfully built 60a44f78d194
上面的例子,我們使用了-t(tag)標(biāo)識給鏡像添加“blog”的標(biāo)簽。實質(zhì)上我們就是在給鏡像命名,如果我們不指定標(biāo)簽,就只能通過 Docker 分配的Image ID來訪問鏡像了。本例中,從 Docker 構(gòu)建成功的信息可以看出,Image ID值為60a44f78d194。
除了-t標(biāo)識外,我還指定了目錄/root/blog。該目錄被稱作“構(gòu)建目錄”,它將包含 Dockerfile,以及其它需要構(gòu)建該容器的文件。
現(xiàn)在我們構(gòu)建成功了,下面我們開始定制該鏡像。
使用 RUN 來執(zhí)行 apt-get
用來生成 HTML 頁面的靜態(tài)站點生成器是用?Python語言編寫的,所以,在 Dockerfile 中需要做的第一件定制任務(wù)是安裝 Python。我們將使用 Apt 軟件包管理器來安裝 Python 軟件包,這意味著在 Dockerfile 中我們要指定運行apt-get update和apt-get install python-dev;為了完成這一點,我們可以使用RUN指令。
## Dockerfile that generates an instance of http://bencane.com
FROM nginx:latest
MAINTAINER Benjamin Cane <ben@bencane.com>
## Install python and pip
RUN apt-get update
RUN apt-get install -y python-dev python-pip
如上所示,我們只是簡單地告知 Docker 構(gòu)建鏡像的時候,要去執(zhí)行指定的apt-get命令。比較有趣的是,這些命令只會在該容器的上下文中執(zhí)行。這意味著,即使在容器中安裝了python-dev和python-pip,但主機本身并沒有安裝這些。說的更簡單點,pip命令將只在容器中執(zhí)行,出了容器,pip命令不存在。
還有一點比較重要的是,Docker 構(gòu)建過程中不接受用戶輸入。這說明任何被RUN指令執(zhí)行的命令必須在沒有用戶輸入的時候完成。由于很多應(yīng)用在安裝的過程中需要用戶的輸入信息,所以這增加了一點難度。不過我們例子中,RUN命令執(zhí)行的命令都不需要用戶輸入。
安裝 Python 模塊
Python安裝完畢后,我們現(xiàn)在需要安裝 Python 模塊。如果在 Docker 外做這些事,我們通常使用pip命令,然后參考我的博客 Git 倉庫中名叫requirements.txt的文件。在之前的步驟中,我們已經(jīng)使用git命令成功地將 Github 倉庫“克隆”到了/root/blog目錄;這個目錄碰巧也是我們創(chuàng)建Dockerfile的目錄。這很重要,因為這意味著 Docker 在構(gòu)建過程中可以訪問這個 Git 倉庫中的內(nèi)容。
當(dāng)我們執(zhí)行構(gòu)建后,Docker 將構(gòu)建的上下文環(huán)境設(shè)置為指定的“構(gòu)建目錄”。這意味著目錄中的所有文件都可以在構(gòu)建過程中被使用,目錄之外的文件(構(gòu)建環(huán)境之外)是不能訪問的。
為了能安裝所需的 Python 模塊,我們需要將requirements.txt從構(gòu)建目錄拷貝到容器中。我們可以在Dockerfile中使用COPY指令完成這一需求。
## Dockerfile that generates an instance of http://bencane.com
FROM nginx:latest
MAINTAINER Benjamin Cane <ben@bencane.com>
## Install python and pip
RUN apt-get update
RUN apt-get install -y python-dev python-pip
## Create a directory for required files
RUN mkdir -p /build/
## Add requirements file and run pip
COPY requirements.txt /build/
RUN pip install -r /build/requirements.txt
在Dockerfile中,我們增加了3條指令。第一條指令使用RUN在容器中創(chuàng)建了/build/目錄。該目錄用來拷貝生成靜態(tài) HTML 頁面所需的一切應(yīng)用文件。第二條指令是COPY指令,它將requirements.txt從“構(gòu)建目錄”(/root/blog)拷貝到容器中的/build/目錄。第三條使用RUN指令來執(zhí)行pip命令;安裝requirements.txt文件中指定的所有模塊。
當(dāng)構(gòu)建定制鏡像時,COPY是條重要的指令。如果在 Dockerfile 中不指定拷貝文件,Docker 鏡像將不會包含requirements.txt 這個文件。在 Docker 容器中,所有東西都是隔離的,除非在 Dockerfile 中指定執(zhí)行,否則容器中不會包括所需的依賴。
重新運行構(gòu)建
現(xiàn)在,我們讓 Docker 執(zhí)行了一些定制任務(wù),現(xiàn)在我們嘗試另一次 blog 鏡像的構(gòu)建。
# docker build -t blog /root/blog
Sending build context to Docker daemon 19.52 MB
Sending build context to Docker daemon
Step 0 : FROM nginx:latest
---> 9fab4090484a
Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>
---> Using cache
---> 8e0f1899d1eb
Step 2 : RUN apt-get update
---> Using cache
---> 78b36ef1a1a2
Step 3 : RUN apt-get install -y python-dev python-pip
---> Using cache
---> ef4f9382658a
Step 4 : RUN mkdir -p /build/
---> Running in bde05cf1e8fe
---> f4b66e09fa61
Removing intermediate container bde05cf1e8fe
Step 5 : COPY requirements.txt /build/
---> cef11c3fb97c
Removing intermediate container 9aa8ff43f4b0
Step 6 : RUN pip install -r /build/requirements.txt
---> Running in c50b15ddd8b1
Downloading/unpacking jinja2 (from -r /build/requirements.txt (line 1))
Downloading/unpacking PyYaml (from -r /build/requirements.txt (line 2))
<truncated to reduce noise>
Successfully installed jinja2 PyYaml mistune markdown MarkupSafe
Cleaning up...
---> abab55c20962
Removing intermediate container c50b15ddd8b1
Successfully built abab55c20962
上述輸出所示,我們可以看到構(gòu)建成功了,我們還可以看到另外一個有趣的信息---> Using cache。這條信息告訴我們,Docker 在構(gòu)建該鏡像時使用了它的構(gòu)建緩存。
Docker 構(gòu)建緩存
當(dāng) Docker 構(gòu)建鏡像時,它不僅僅構(gòu)建一個單獨的鏡像;事實上,在構(gòu)建過程中,它會構(gòu)建許多鏡像。從上面的輸出信息可以看出,在每一“步”執(zhí)行后,Docker 都在創(chuàng)建新的鏡像。
Step 5 : COPY requirements.txt /build/
---> cef11c3fb97c
上面片段的最后一行可以看出,Docker 在告訴我們它在創(chuàng)建一個新鏡像,因為它打印了Image ID:cef11c3fb97c。這種方式有用之處在于,Docker能在隨后構(gòu)建這個blog鏡像時將這些鏡像作為緩存使用。這很有用處,因為這樣, Docker 就能加速同一個容器中新構(gòu)建任務(wù)的構(gòu)建流程。從上面的例子中,我們可以看出,Docker 沒有重新安裝python-dev和python-pip包,Docker 則使用了緩存鏡像。但是由于 Docker 并沒有找到執(zhí)行mkdir命令的構(gòu)建緩存,隨后的步驟就被一一執(zhí)行了。
Docker 構(gòu)建緩存一定程度上是福音,但有時也是噩夢。這是因為決定使用緩存或者重新運行指令的因素很少。比如,如果requirements.txt文件發(fā)生了修改,Docker 會在構(gòu)建時檢測到該變化,然后 Docker 會重新執(zhí)行該執(zhí)行那個點往后的所有指令。這得益于 Docker 能查看requirements.txt的文件內(nèi)容。但是,apt-get命令的執(zhí)行就是另一回事了。如果提供 Python 軟件包的Apt倉庫包含了一個更新的 python-pip 包;Docker 不會檢測到這個變化,轉(zhuǎn)而去使用構(gòu)建緩存。這會導(dǎo)致之前舊版本的包將被安裝。雖然對python-pip來說,這不是主要的問題,但對使用了存在某個致命攻擊缺陷的軟件包緩存來說,這是個大問題。
出于這個原因,拋棄 Docker 緩存,定期地重新構(gòu)建鏡像是有好處的。這時,當(dāng)我們執(zhí)行 Docker 構(gòu)建時,我簡單地指定--no-cache=True即可。
部署博客的剩余部分
Python 軟件包和模塊安裝后,接下來我們將拷貝需要用到的應(yīng)用文件,然后運行hamerkop應(yīng)用。我們只需要使用更多的COPY和RUN指令就可完成。
## Dockerfile that generates an instance of http://bencane.com
FROM nginx:latest
MAINTAINER Benjamin Cane <ben@bencane.com>
## Install python and pip
RUN apt-get update
RUN apt-get install -y python-dev python-pip
## Create a directory for required files
RUN mkdir -p /build/
## Add requirements file and run pip
COPY requirements.txt /build/
RUN pip install -r /build/requirements.txt
## Add blog code nd required files
COPY static /build/static
COPY templates /build/templates
COPY hamerkop /build/
COPY config.yml /build/
COPY articles /build/articles
## Run Generator
RUN /build/hamerkop -c /build/config.yml
現(xiàn)在我們已經(jīng)寫出了剩余的構(gòu)建指令,我們再次運行另一次構(gòu)建,并確保鏡像構(gòu)建成功。
# docker build -t blog /root/blog/
Sending build context to Docker daemon 19.52 MB
Sending build context to Docker daemon
Step 0 : FROM nginx:latest
---> 9fab4090484a
Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>
---> Using cache
---> 8e0f1899d1eb
Step 2 : RUN apt-get update
---> Using cache
---> 78b36ef1a1a2
Step 3 : RUN apt-get install -y python-dev python-pip
---> Using cache
---> ef4f9382658a
Step 4 : RUN mkdir -p /build/
---> Using cache
---> f4b66e09fa61
Step 5 : COPY requirements.txt /build/
---> Using cache
---> cef11c3fb97c
Step 6 : RUN pip install -r /build/requirements.txt
---> Using cache
---> abab55c20962
Step 7 : COPY static /build/static
---> 15cb91531038
Removing intermediate container d478b42b7906
Step 8 : COPY templates /build/templates
---> ecded5d1a52e
Removing intermediate container ac2390607e9f
Step 9 : COPY hamerkop /build/
---> 59efd1ca1771
Removing intermediate container b5fbf7e817b7
Step 10 : COPY config.yml /build/
---> bfa3db6c05b7
Removing intermediate container 1aebef300933
Step 11 : COPY articles /build/articles
---> 6b61cc9dde27
Removing intermediate container be78d0eb1213
Step 12 : RUN /build/hamerkop -c /build/config.yml
---> Running in fbc0b5e574c5
Successfully created file /usr/share/nginx/html//2011/06/25/checking-the-number-of-lwp-threads-in-linux
Successfully created file /usr/share/nginx/html//2011/06/checking-the-number-of-lwp-threads-in-linux
<truncated to reduce noise>
Successfully created file /usr/share/nginx/html//archive.html
Successfully created file /usr/share/nginx/html//sitemap.xml
---> 3b25263113e1
Removing intermediate container fbc0b5e574c5
Successfully built 3b25263113e1
運行定制的容器
成功的一次構(gòu)建后,我們現(xiàn)在就可以通過運行docker命令和run選項來運行我們定制的容器,和之前我們啟動 nginx 容器一樣。
# docker run -d -p 80:80 --name=blog blog
5f6c7a2217dcdc0da8af05225c4d1294e3e6bb28a41ea898a1c63fb821989ba1
我們這次又使用了-d(detach)標(biāo)識來讓Docker在后臺運行。但是,我們也可以看到兩個新標(biāo)識。第一個新標(biāo)識是--name,這用來給容器指定一個用戶名稱。之前的例子,我們沒有指定名稱,因為 Docker 隨機幫我們生成了一個。第二個新標(biāo)識是-p,這個標(biāo)識允許用戶從主機映射一個端口到容器中的一個端口。
之前我們使用的基礎(chǔ)?nginx鏡像分配了80端口給 HTTP 服務(wù)。默認情況下,容器內(nèi)的端口通道并沒有綁定到主機系統(tǒng)。為了讓外部系統(tǒng)能訪問容器內(nèi)部端口,我們必須使用-p標(biāo)識將主機端口映射到容器內(nèi)部端口。上面的命令,我們通過-p 8080:80語法將主機80端口映射到容器內(nèi)部的80端口。
經(jīng)過上面的命令,我們的容器看起來成功啟動了,我們可以通過執(zhí)行docker ps核實。
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d264c7ef92bd blog:latest nginx -g 'daemon off 3 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:80->80/tcp blog
總結(jié)
截止目前,我們擁有了一個運行中的定制 Docker 容器。雖然在這篇文章中,我們只接觸了一些 Dockerfile 指令用法,但是我們還是要學(xué)習(xí)所有的指令。我們可以檢查 Docker's reference page[7] 來獲取所有的 Dockerfile 指令用法,那里對指令的用法說明得很詳細。
另一個比較好的資源是 Dockerfile Best Practices page[8],它有許多構(gòu)建定制 Dockerfile 的最佳練習(xí)。有些技巧非常有用,比如戰(zhàn)略性地組織好 Dockerfile 中的命令。上面的例子中,我們將articles目錄的COPY指令作為 Dockerfile 中最后的COPY指令。這是因為articles目錄會經(jīng)常變動。所以,將那些經(jīng)常變化的指令盡可能地放在最后面的位置,來最優(yōu)化那些可以被緩存的步驟。
轉(zhuǎn)載于:https://my.oschina.net/zhanghaiyang/blog/725744
總結(jié)
以上是生活随笔為你收集整理的Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux基础(6)-shell编程
- 下一篇: Mysql增删改