日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅

發(fā)布時(shí)間:2025/5/22 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

通過 Docker 化一個(gè)博客網(wǎng)站來開啟我們的 Docker 之旅

這篇文章包含 Docker 的基本概念,以及如何通過創(chuàng)建一個(gè)定制的 Dockerfile 來 Docker 化Dockerize一個(gè)應(yīng)用。

Docker 是一個(gè)過去兩年來從某個(gè) idea 中孕育而生的有趣技術(shù),公司組織們用它在世界上每個(gè)角落來部署應(yīng)用。在今天的文章中,我將講述如何通過“Docker 化Dockerize”一個(gè)現(xiàn)有的應(yīng)用,來開始我們的 Docker 之旅。這里提到的應(yīng)用指的就是這個(gè)博客!

什么是 Docker?

當(dāng)我們開始學(xué)習(xí) Docker 基本概念時(shí),讓我們先去搞清楚什么是 Docker 以及它為什么這么流行。Docker 是一個(gè)操作系統(tǒng)容器管理工具,它通過將應(yīng)用打包在操作系統(tǒng)容器中,來方便我們管理和部署應(yīng)用。

容器 vs. 虛擬機(jī)

容器和虛擬機(jī)并不完全相似,它是另外一種提供操作系統(tǒng)虛擬化的方式。它和標(biāo)準(zhǔn)的虛擬機(jī)還是有所不同。

標(biāo)準(zhǔn)的虛擬機(jī)一般會(huì)包括一個(gè)完整的操作系統(tǒng)、操作系統(tǒng)軟件包、最后還有一至兩個(gè)應(yīng)用。這都得益于為虛擬機(jī)提供硬件虛擬化的管理程序。這樣一來,一個(gè)單一的服務(wù)器就可以將許多獨(dú)立的操作系統(tǒng)作為虛擬客戶機(jī)運(yùn)行了。

容器和虛擬機(jī)很相似,它們都支持在單一的服務(wù)器上運(yùn)行多個(gè)操作環(huán)境,只是,在容器中,這些環(huán)境并不是一個(gè)個(gè)完整的操作系統(tǒng)。容器一般只包含必要的操作系統(tǒng)軟件包和一些應(yīng)用。它們通常不會(huì)包含一個(gè)完整的操作系統(tǒng)或者硬件的虛擬化。這也意味著容器比傳統(tǒng)的虛擬機(jī)開銷更少。

容器和虛擬機(jī)常被誤認(rèn)為是兩種對(duì)立的技術(shù)。虛擬機(jī)采用一個(gè)物理服務(wù)器來提供全功能的操作環(huán)境,該環(huán)境會(huì)和其余虛擬機(jī)一起共享這些物理資源。容器一般用來隔離一個(gè)單一主機(jī)上運(yùn)行的應(yīng)用進(jìn)程,以保證隔離后的進(jìn)程之間不能相互影響。事實(shí)上,容器和?BSD Jails以及chroot進(jìn)程的相似度,超過了和完整虛擬機(jī)的相似度。

Docker 在容器之上提供了什么

Docker 本身不是一個(gè)容器運(yùn)行環(huán)境,事實(shí)上,只是一個(gè)與具體實(shí)現(xiàn)無關(guān)的容器技術(shù),Docker 正在努力支持 Solaris Zones[1] 和BSD Jails[2]。Docker 提供了一種管理、打包和部署容器的方式。雖然一定程度上,虛擬機(jī)多多少少擁有這些類似的功能,但虛擬機(jī)并沒有完整擁有絕大多數(shù)的容器功能,即使擁有,這些功能用起來都并沒有 Docker 來的方便或那么完整。

現(xiàn)在,我們應(yīng)該知道 Docker 是什么了,然后,我們將從安裝 Docker,并部署一個(gè)公開的預(yù)構(gòu)建好的容器開始,學(xué)習(xí) Docker 是如何工作的。

從安裝開始

默認(rèn)情況下,Docker 并不會(huì)自動(dòng)被安裝在您的計(jì)算機(jī)中,所以,第一步就是安裝 Docker 軟件包;我們的教學(xué)機(jī)器系統(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)前是否有容器運(yùn)行,我們可以執(zhí)行docker命令,加上ps選項(xiàng)

  • # docker ps

  • CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  • docker命令中的ps功能類似于 Linux 的ps命令。它將顯示可找到的 Docker 容器及其狀態(tài)。由于我們并沒有啟動(dòng)任何 Docker 容器,所以命令沒有顯示任何正在運(yùn)行的容器。

    部署一個(gè)預(yù)構(gòu)建好的 nginx Docker 容器

    我比較喜歡的 Docker 特性之一就是 Docker 部署預(yù)先構(gòu)建好的容器的方式,就像yum和apt-get部署包一樣。為了更好地解釋,我們來部署一個(gè)運(yùn)行著 nginx web 服務(wù)器的預(yù)構(gòu)建容器。我們可以繼續(xù)使用docker命令,這次選擇run選項(xiàng)。

  • # 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選項(xiàng),用來通知 Docker 去尋找一個(gè)指定的 Docker 鏡像,然后啟動(dòng)運(yùn)行著該鏡像的容器。默認(rèn)情況下,Docker 容器運(yùn)行在前臺(tái),這意味著當(dāng)你運(yùn)行docker run命令的時(shí)候,你的 shell 會(huì)被綁定到容器的控制臺(tái)以及運(yùn)行在容器中的進(jìn)程。為了能在后臺(tái)運(yùn)行該 Docker 容器,我們使用了-d(detach)標(biāo)志。

    再次運(yùn)行docker ps命令,可以看到 nginx 容器正在運(yùn)行。

  • # 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

  • 從上面的輸出信息中,我們可以看到正在運(yùn)行的名為desperate_lalande的容器,它是由nginx:latest image(LCTT 譯注: nginx 最新版本的鏡像)構(gòu)建而來得。

    Docker 鏡像

    鏡像是 Docker 的核心特征之一,類似于虛擬機(jī)鏡像。和虛擬機(jī)鏡像一樣,Docker 鏡像是一個(gè)被保存并打包的容器。當(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 的鏡像。這是因?yàn)楫?dāng)我們執(zhí)行docker run命令時(shí),告訴 Docker 運(yùn)行一個(gè)基于 nginx 鏡像的容器。既然 Docker 要啟動(dòng)一個(gè)基于特定鏡像的容器,那么 Docker 首先需要找到那個(gè)指定鏡像。在檢查遠(yuǎn)程倉庫之前,Docker 首先檢查本地是否存在指定名稱的本地鏡像。

    因?yàn)橄到y(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)容。默認(rèn)情況下,Docker 會(huì)使用 Docker Hub[3] 倉庫,該倉庫由 Docker 公司維護(hù)。

    和 Github 一樣,在 Docker Hub 創(chuàng)建公共倉庫是免費(fèi)的,私人倉庫就需要繳納費(fèi)用了。當(dāng)然,部署你自己的 Docker 倉庫也是可以的,事實(shí)上只需要簡單地運(yùn)行docker run registry命令就行了。但在這篇文章中,我們的重點(diǎn)將不是講解如何部署一個(gè)定制的注冊(cè)服務(wù)。

    關(guān)閉并移除容器

    在我們繼續(xù)構(gòu)建定制容器之前,我們先清理一下 Docker 環(huán)境,我們將關(guān)閉先前的容器,并移除它。

    我們利用docker命令和run選項(xiàng)運(yùn)行一個(gè)容器,所以,為了停止同一個(gè)容器,我們簡單地在執(zhí)行docker命令時(shí),使用kill選項(xiàng),并指定容器名。

  • # docker kill desperate_lalande

  • desperate_lalande

  • 當(dāng)我們?cè)俅螆?zhí)行docker ps,就不再有容器運(yùn)行了

  • # docker ps

  • CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  • 但是,此時(shí),我們這是停止了容器;雖然它不再運(yùn)行,但仍然存在。默認(rèn)情況下,docker ps只會(huì)顯示正在運(yùn)行的容器,如果我們附加-a(all) 標(biāo)識(shí),它會(huì)顯示所有運(yùn)行和未運(yùn)行的容器。

  • # 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

  • 為了能完整地移除容器,我們?cè)谟胐ocker命令時(shí),附加rm選項(xiàng)。

  • # 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 譯注:鏡像緩存)。如果我們重新運(yùn)行docker run -d nginx,Docker 就無需再次拉取 nginx 鏡像即可啟動(dòng)容器。這是因?yàn)槲覀儽镜叵到y(tǒng)中已經(jīng)保存了一個(gè)副本。

    為了列出系統(tǒng)中所有的本地鏡像,我們運(yùn)行docker命令,附加images選項(xiàng)。

  • # docker images

  • REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE

  • nginx latest 9fab4090484a 5 days ago 132.8 MB

  • 構(gòu)建我們自己的鏡像

    截至目前,我們已經(jīng)使用了一些基礎(chǔ)的 Docker 命令來啟動(dòng)、停止和移除一個(gè)預(yù)構(gòu)建好的普通鏡像。為了“Docker 化(Dockerize)”這篇博客,我們需要構(gòu)建我們自己的鏡像,也就是創(chuàng)建一個(gè)?Dockerfile

    在大多數(shù)虛擬機(jī)環(huán)境中,如果你想創(chuàng)建一個(gè)機(jī)器鏡像,首先,你需要建立一個(gè)新的虛擬機(jī)、安裝操作系統(tǒng)、安裝應(yīng)用,最后將其轉(zhuǎn)換為一個(gè)模板或者鏡像。但在 Docker 中,所有這些步驟都可以通過 Dockerfile 實(shí)現(xiàn)全自動(dòng)。Dockerfile 是向 Docker 提供構(gòu)建指令去構(gòu)建定制鏡像的方式。在這一章節(jié),我們將編寫能用來部署這個(gè)博客的定制 Dockerfile。

    理解應(yīng)用

    我們開始構(gòu)建 Dockerfile 之前,第一步要搞明白,我們需要哪些東西來部署這個(gè)博客。

    這個(gè)博客本質(zhì)上是由一個(gè)靜態(tài)站點(diǎn)生成器生成的靜態(tài) HTML 頁面,這個(gè)生成器是我編寫的,名為?hamerkop。這個(gè)生成器很簡單,它所做的就是生成該博客站點(diǎn)。所有的代碼和源文件都被我放在了一個(gè)公共的Github 倉庫[4]。為了部署這篇博客,我們要先從 Github 倉庫把這些內(nèi)容拉取下來,然后安裝Python和一些Python模塊,最后執(zhí)行hamerkop應(yīng)用。我們還需要安裝nginx,來運(yùn)行生成后的內(nèi)容。

    截止目前,這些還是一個(gè)簡單的 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 - 繼承一個(gè) Docker 鏡像

    第一條 Dockerfile 指令是FROM指令。這將指定一個(gè)現(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)容。

    運(yùn)行一次測試構(gòu)建

    因?yàn)槲覀兝^承了?nginxDocker鏡像,我們現(xiàn)在的 Dockerfile 也就包括了用來構(gòu)建nginx鏡像的Dockerfile[6] 中所有指令。這意味著,此時(shí)我們可以從該 Dockerfile 中構(gòu)建出一個(gè) Docker 鏡像,然后以該鏡像運(yùn)行一個(gè)容器。雖然,最終的鏡像和nginx鏡像本質(zhì)上是一樣的,但是我們這次是通過構(gòu)建 Dockerfile 的形式,然后我們將講解 Docker 構(gòu)建鏡像的過程。

    想要從 Dockerfile 構(gòu)建鏡像,我們只需要在運(yùn)行?docker命令的時(shí)候,加上build選項(xiàng)。

  • # 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)識(shí)給鏡像添加“blog”的標(biāo)簽。實(shí)質(zhì)上我們就是在給鏡像命名,如果我們不指定標(biāo)簽,就只能通過 Docker 分配的Image ID來訪問鏡像了。本例中,從 Docker 構(gòu)建成功的信息可以看出,Image ID值為60a44f78d194。

    除了-t標(biāo)識(shí)外,我還指定了目錄/root/blog。該目錄被稱作“構(gòu)建目錄”,它將包含 Dockerfile,以及其它需要構(gòu)建該容器的文件。

    現(xiàn)在我們構(gòu)建成功了,下面我們開始定制該鏡像。

    使用 RUN 來執(zhí)行 apt-get

    用來生成 HTML 頁面的靜態(tài)站點(diǎn)生成器是用?Python語言編寫的,所以,在 Dockerfile 中需要做的第一件定制任務(wù)是安裝 Python。我們將使用 Apt 軟件包管理器來安裝 Python 軟件包,這意味著在 Dockerfile 中我們要指定運(yùn)行apt-get update和apt-get install python-dev;為了完成這一點(diǎn),我們可以使用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)建鏡像的時(shí)候,要去執(zhí)行指定的apt-get命令。比較有趣的是,這些命令只會(huì)在該容器的上下文中執(zhí)行。這意味著,即使在容器中安裝了python-dev和python-pip,但主機(jī)本身并沒有安裝這些。說的更簡單點(diǎn),pip命令將只在容器中執(zhí)行,出了容器,pip命令不存在。

    還有一點(diǎn)比較重要的是,Docker 構(gòu)建過程中不接受用戶輸入。這說明任何被RUN指令執(zhí)行的命令必須在沒有用戶輸入的時(shí)候完成。由于很多應(yīng)用在安裝的過程中需要用戶的輸入信息,所以這增加了一點(diǎn)難度。不過我們例子中,RUN命令執(zhí)行的命令都不需要用戶輸入。

    安裝 Python 模塊

    Python安裝完畢后,我們現(xiàn)在需要安裝 Python 模塊。如果在 Docker 外做這些事,我們通常使用pip命令,然后參考我的博客 Git 倉庫中名叫requirements.txt的文件。在之前的步驟中,我們已經(jīng)使用git命令成功地將 Github 倉庫“克隆”到了/root/blog目錄;這個(gè)目錄碰巧也是我們創(chuàng)建Dockerfile的目錄。這很重要,因?yàn)檫@意味著 Docker 在構(gòu)建過程中可以訪問這個(gè) 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中,我們?cè)黾恿?條指令。第一條指令使用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)建定制鏡像時(shí),COPY是條重要的指令。如果在 Dockerfile 中不指定拷貝文件,Docker 鏡像將不會(huì)包含requirements.txt 這個(gè)文件。在 Docker 容器中,所有東西都是隔離的,除非在 Dockerfile 中指定執(zhí)行,否則容器中不會(huì)包括所需的依賴。

    重新運(yùn)行構(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)建成功了,我們還可以看到另外一個(gè)有趣的信息---> Using cache。這條信息告訴我們,Docker 在構(gòu)建該鏡像時(shí)使用了它的構(gòu)建緩存。

    Docker 構(gòu)建緩存

    當(dāng) Docker 構(gòu)建鏡像時(shí),它不僅僅構(gòu)建一個(gè)單獨(dú)的鏡像;事實(shí)上,在構(gòu)建過程中,它會(huì)構(gòu)建許多鏡像。從上面的輸出信息可以看出,在每一“步”執(zhí)行后,Docker 都在創(chuàng)建新的鏡像。

  • Step 5 : COPY requirements.txt /build/

  • ---> cef11c3fb97c

  • 上面片段的最后一行可以看出,Docker 在告訴我們它在創(chuàng)建一個(gè)新鏡像,因?yàn)樗蛴×?span style="border:0px;font-style:inherit;font-variant:inherit;font-weight:700;line-height:inherit;vertical-align:baseline;">Image ID:cef11c3fb97c。這種方式有用之處在于,Docker能在隨后構(gòu)建這個(gè)blog鏡像時(shí)將這些鏡像作為緩存使用。這很有用處,因?yàn)檫@樣, Docker 就能加速同一個(gè)容器中新構(gòu)建任務(wù)的構(gòu)建流程。從上面的例子中,我們可以看出,Docker 沒有重新安裝python-dev和python-pip包,Docker 則使用了緩存鏡像。但是由于 Docker 并沒有找到執(zhí)行mkdir命令的構(gòu)建緩存,隨后的步驟就被一一執(zhí)行了。

    Docker 構(gòu)建緩存一定程度上是福音,但有時(shí)也是噩夢(mèng)。這是因?yàn)闆Q定使用緩存或者重新運(yùn)行指令的因素很少。比如,如果requirements.txt文件發(fā)生了修改,Docker 會(huì)在構(gòu)建時(shí)檢測到該變化,然后 Docker 會(huì)重新執(zhí)行該執(zhí)行那個(gè)點(diǎn)往后的所有指令。這得益于 Docker 能查看requirements.txt的文件內(nèi)容。但是,apt-get命令的執(zhí)行就是另一回事了。如果提供 Python 軟件包的Apt倉庫包含了一個(gè)更新的 python-pip 包;Docker 不會(huì)檢測到這個(gè)變化,轉(zhuǎn)而去使用構(gòu)建緩存。這會(huì)導(dǎo)致之前舊版本的包將被安裝。雖然對(duì)python-pip來說,這不是主要的問題,但對(duì)使用了存在某個(gè)致命攻擊缺陷的軟件包緩存來說,這是個(gè)大問題。

    出于這個(gè)原因,拋棄 Docker 緩存,定期地重新構(gòu)建鏡像是有好處的。這時(shí),當(dāng)我們執(zhí)行 Docker 構(gòu)建時(shí),我簡單地指定--no-cache=True即可。

    部署博客的剩余部分

    Python 軟件包和模塊安裝后,接下來我們將拷貝需要用到的應(yīng)用文件,然后運(yùn)行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)建指令,我們?cè)俅芜\(yùn)行另一次構(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

  • 運(yùn)行定制的容器

    成功的一次構(gòu)建后,我們現(xiàn)在就可以通過運(yùn)行docker命令和run選項(xiàng)來運(yùn)行我們定制的容器,和之前我們啟動(dòng) nginx 容器一樣。

  • # docker run -d -p 80:80 --name=blog blog

  • 5f6c7a2217dcdc0da8af05225c4d1294e3e6bb28a41ea898a1c63fb821989ba1

  • 我們這次又使用了-d(detach)標(biāo)識(shí)來讓Docker在后臺(tái)運(yùn)行。但是,我們也可以看到兩個(gè)新標(biāo)識(shí)。第一個(gè)新標(biāo)識(shí)是--name,這用來給容器指定一個(gè)用戶名稱。之前的例子,我們沒有指定名稱,因?yàn)?Docker 隨機(jī)幫我們生成了一個(gè)。第二個(gè)新標(biāo)識(shí)是-p,這個(gè)標(biāo)識(shí)允許用戶從主機(jī)映射一個(gè)端口到容器中的一個(gè)端口。

    之前我們使用的基礎(chǔ)?nginx鏡像分配了80端口給 HTTP 服務(wù)。默認(rèn)情況下,容器內(nèi)的端口通道并沒有綁定到主機(jī)系統(tǒng)。為了讓外部系統(tǒng)能訪問容器內(nèi)部端口,我們必須使用-p標(biāo)識(shí)將主機(jī)端口映射到容器內(nèi)部端口。上面的命令,我們通過-p 8080:80語法將主機(jī)80端口映射到容器內(nèi)部的80端口。

    經(jīng)過上面的命令,我們的容器看起來成功啟動(dòng)了,我們可以通過執(zhí)行docker ps核實(shí)。

  • # 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é)

    截止目前,我們擁有了一個(gè)運(yùn)行中的定制 Docker 容器。雖然在這篇文章中,我們只接觸了一些 Dockerfile 指令用法,但是我們還是要學(xué)習(xí)所有的指令。我們可以檢查 Docker's reference page[7] 來獲取所有的 Dockerfile 指令用法,那里對(duì)指令的用法說明得很詳細(xì)。

    另一個(gè)比較好的資源是 Dockerfile Best Practices page[8],它有許多構(gòu)建定制 Dockerfile 的最佳練習(xí)。有些技巧非常有用,比如戰(zhàn)略性地組織好 Dockerfile 中的命令。上面的例子中,我們將articles目錄的COPY指令作為 Dockerfile 中最后的COPY指令。這是因?yàn)閍rticles目錄會(huì)經(jīng)常變動(dòng)。所以,將那些經(jīng)常變化的指令盡可能地放在最后面的位置,來最優(yōu)化那些可以被緩存的步驟。

    轉(zhuǎn)載于:https://my.oschina.net/zhanghaiyang/blog/725744

    總結(jié)

    以上是生活随笔為你收集整理的Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。