Linux中國

通過 Docker 化一個博客網站來開啟我們的 Docker 之旅

這篇文章包含 Docker 的基本概念,以及如何通過創建一個定製的 Dockerfile 來 Docker 化 Dockerize 一個應用。

Docker 是一個過去兩年來從某個 idea 中孕育而生的有趣技術,公司組織們用它在世界上每個角落來部署應用。在今天的文章中,我將講述如何通過「 Docker 化 Dockerize 」一個現有的應用,來開始我們的 Docker 之旅。這裡提到的應用指的就是這個博客!

什麼是 Docker?

當我們開始學習 Docker 基本概念時,讓我們先去搞清楚什麼是 Docker 以及它為什麼這麼流行。Docker 是一個操作系統容器管理工具,它通過將應用打包在操作系統容器中,來方便我們管理和部署應用。

容器 vs. 虛擬機

容器和虛擬機並不完全相似,它是另外一種提供操作系統虛擬化的方式。它和標準的虛擬機還是有所不同。

標準的虛擬機一般會包括一個完整的操作系統、操作系統軟體包、最後還有一至兩個應用。這都得益於為虛擬機提供硬體虛擬化的管理程序。這樣一來,一個單一的伺服器就可以將許多獨立的操作系統作為虛擬客戶機運行了。

容器和虛擬機很相似,它們都支持在單一的伺服器上運行多個操作環境,只是,在容器中,這些環境並不是一個個完整的操作系統。容器一般只包含必要的操作系統軟體包和一些應用。它們通常不會包含一個完整的操作系統或者硬體的虛擬化。這也意味著容器比傳統的虛擬機開銷更少。

容器和虛擬機常被誤認為是兩種對立的技術。虛擬機採用一個物理伺服器來提供全功能的操作環境,該環境會和其餘虛擬機一起共享這些物理資源。容器一般用來隔離一個單一主機上運行的應用進程,以保證隔離後的進程之間不能相互影響。事實上,容器和 BSD Jails 以及 chroot 進程的相似度,超過了和完整虛擬機的相似度。

Docker 在容器之上提供了什麼

Docker 本身不是一個容器運行環境,事實上,只是一個與具體實現無關的容器技術,Docker 正在努力支持 Solaris ZonesBSD Jails。Docker 提供了一種管理、打包和部署容器的方式。雖然一定程度上,虛擬機多多少少擁有這些類似的功能,但虛擬機並沒有完整擁有絕大多數的容器功能,即使擁有,這些功能用起來都並沒有 Docker 來的方便或那麼完整。

現在,我們應該知道 Docker 是什麼了,然後,我們將從安裝 Docker,並部署一個公開的預構建好的容器開始,學習 Docker 是如何工作的。

從安裝開始

默認情況下,Docker 並不會自動被安裝在您的計算機中,所以,第一步就是安裝 Docker 軟體包;我們的教學機器系統是 Ubuntu 14.0.4,所以,我們將使用 Apt 軟體包管理器,來執行安裝操作。

# 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

為了檢查當前是否有容器運行,我們可以執行docker命令,加上ps選項

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

docker命令中的ps功能類似於 Linux 的ps命令。它將顯示可找到的 Docker 容器及其狀態。由於我們並沒有啟動任何 Docker 容器,所以命令沒有顯示任何正在運行的容器。

部署一個預構建好的 nginx Docker 容器

我比較喜歡的 Docker 特性之一就是 Docker 部署預先構建好的容器的方式,就像yumapt-get部署包一樣。為了更好地解釋,我們來部署一個運行著 nginx web 伺服器的預構建容器。我們可以繼續使用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 容器運行在前台,這意味著當你運行docker run命令的時候,你的 shell 會被綁定到容器的控制台以及運行在容器中的進程。為了能在後台運行該 Docker 容器,我們使用了-d (detach)標誌。

再次運行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 最新版本的鏡像)構建而來得。

Docker 鏡像

鏡像是 Docker 的核心特徵之一,類似於虛擬機鏡像。和虛擬機鏡像一樣,Docker 鏡像是一個被保存並打包的容器。當然,Docker 不只是創建鏡像,它還可以通過 Docker 倉庫發布這些鏡像,Docker 倉庫和軟體包倉庫的概念差不多,它讓 Docker 能夠模仿yum部署軟體包的方式來部署鏡像。為了更好地理解這是怎麼工作的,我們來回顧docker run執行後的輸出。

# docker run -d nginx
Unable to find image 'nginx' locally

我們可以看到第一條信息是,Docker 不能在本地找到名叫 nginx 的鏡像。這是因為當我們執行docker run命令時,告訴 Docker 運行一個基於 nginx 鏡像的容器。既然 Docker 要啟動一個基於特定鏡像的容器,那麼 Docker 首先需要找到那個指定鏡像。在檢查遠程倉庫之前,Docker 首先檢查本地是否存在指定名稱的本地鏡像。

因為系統是嶄新的,不存在 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 

這就是第二部分輸出信息顯示給我們的內容。默認情況下,Docker 會使用 Docker Hub 倉庫,該倉庫由 Docker 公司維護。

和 Github 一樣,在 Docker Hub 創建公共倉庫是免費的,私人倉庫就需要繳納費用了。當然,部署你自己的 Docker 倉庫也是可以的,事實上只需要簡單地運行docker run registry命令就行了。但在這篇文章中,我們的重點將不是講解如何部署一個定製的註冊服務。

關閉並移除容器

在我們繼續構建定製容器之前,我們先清理一下 Docker 環境,我們將關閉先前的容器,並移除它。

我們利用docker命令和run選項運行一個容器,所以,為了停止同一個容器,我們簡單地在執行docker命令時,使用kill選項,並指定容器名。

# docker kill desperate_lalande
desperate_lalande

當我們再次執行docker ps,就不再有容器運行了

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

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

# 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

雖然容器被移除了;但是我們仍擁有可用的nginx鏡像(LCTT 譯註:鏡像緩存)。如果我們重新運行docker run -d nginx,Docker 就無需再次拉取 nginx 鏡像即可啟動容器。這是因為我們本地系統中已經保存了一個副本。

為了列出系統中所有的本地鏡像,我們運行docker命令,附加images選項。

# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
nginx               latest              9fab4090484a        5 days ago          132.8 MB

構建我們自己的鏡像

截至目前,我們已經使用了一些基礎的 Docker 命令來啟動、停止和移除一個預構建好的普通鏡像。為了「Docker 化(Dockerize)」這篇博客,我們需要構建我們自己的鏡像,也就是創建一個 Dockerfile

在大多數虛擬機環境中,如果你想創建一個機器鏡像,首先,你需要建立一個新的虛擬機、安裝操作系統、安裝應用,最後將其轉換為一個模板或者鏡像。但在 Docker 中,所有這些步驟都可以通過 Dockerfile 實現全自動。Dockerfile 是向 Docker 提供構建指令去構建定製鏡像的方式。在這一章節,我們將編寫能用來部署這個博客的定製 Dockerfile。

理解應用

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

這個博客本質上是由一個靜態站點生成器生成的靜態 HTML 頁面,這個生成器是我編寫的,名為 hamerkop。這個生成器很簡單,它所做的就是生成該博客站點。所有的代碼和源文件都被我放在了一個公共的 Github 倉庫。為了部署這篇博客,我們要先從 Github 倉庫把這些內容拉取下來,然後安裝 Python 和一些 Python 模塊,最後執行hamerkop應用。我們還需要安裝 nginx,來運行生成後的內容。

截止目前,這些還是一個簡單的 Dockerfile,但它卻給我們展示了相當多的 Dockerfile 語法。我們需要克隆 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指令。這將指定一個現存的鏡像作為我們的基礎鏡像。這也從根本上給我們提供了繼承其他 Docker 鏡像的途徑。在本例中,我們還是從剛剛我們使用的 nginx 開始,如果我們想從頭開始,我們可以通過指定ubuntu:latest來使用 Ubuntu Docker 鏡像。

## Dockerfile that generates an instance of http://bencane.com

FROM nginx:latest
MAINTAINER Benjamin Cane <ben@bencane.com>

除了FROM指令,我還使用了MAINTAINER,它用來顯示 Dockerfile 的作者。

Docker 支持使用#作為注釋,我將經常使用該語法,來解釋 Dockerfile 的部分內容。

運行一次測試構建

因為我們繼承了 nginx Docker鏡像,我們現在的 Dockerfile 也就包括了用來構建 nginx 鏡像的 Dockerfile 中所有指令。這意味著,此時我們可以從該 Dockerfile 中構建出一個 Docker 鏡像,然後以該鏡像運行一個容器。雖然,最終的鏡像和 nginx 鏡像本質上是一樣的,但是我們這次是通過構建 Dockerfile 的形式,然後我們將講解 Docker 構建鏡像的過程。

想要從 Dockerfile 構建鏡像,我們只需要在運行 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)標識給鏡像添加「blog」的標籤。實質上我們就是在給鏡像命名,如果我們不指定標籤,就只能通過 Docker 分配的 Image ID 來訪問鏡像了。本例中,從 Docker 構建成功的信息可以看出,Image ID值為 60a44f78d194

除了-t標識外,我還指定了目錄/root/blog。該目錄被稱作「構建目錄」,它將包含 Dockerfile,以及其它需要構建該容器的文件。

現在我們構建成功了,下面我們開始定製該鏡像。

使用 RUN 來執行 apt-get

用來生成 HTML 頁面的靜態站點生成器是用 Python 語言編寫的,所以,在 Dockerfile 中需要做的第一件定製任務是安裝 Python。我們將使用 Apt 軟體包管理器來安裝 Python 軟體包,這意味著在 Dockerfile 中我們要指定運行apt-get updateapt-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 構建鏡像的時候,要去執行指定的apt-get命令。比較有趣的是,這些命令只會在該容器的上下文中執行。這意味著,即使在容器中安裝了python-devpython-pip,但主機本身並沒有安裝這些。說的更簡單點,pip命令將只在容器中執行,出了容器,pip命令不存在。

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

安裝 Python 模塊

Python 安裝完畢後,我們現在需要安裝 Python 模塊。如果在 Docker 外做這些事,我們通常使用pip命令,然後參考我的博客 Git 倉庫中名叫requirements.txt的文件。在之前的步驟中,我們已經使用git命令成功地將 Github 倉庫「克隆」到了/root/blog目錄;這個目錄碰巧也是我們創建Dockerfile的目錄。這很重要,因為這意味著 Docker 在構建過程中可以訪問這個 Git 倉庫中的內容。

當我們執行構建後,Docker 將構建的上下文環境設置為指定的「構建目錄」。這意味著目錄中的所有文件都可以在構建過程中被使用,目錄之外的文件(構建環境之外)是不能訪問的。

為了能安裝所需的 Python 模塊,我們需要將requirements.txt從構建目錄拷貝到容器中。我們可以在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在容器中創建了/build/目錄。該目錄用來拷貝生成靜態 HTML 頁面所需的一切應用文件。第二條指令是COPY指令,它將requirements.txt從「構建目錄」(/root/blog)拷貝到容器中的/build/目錄。第三條使用RUN指令來執行pip命令;安裝requirements.txt文件中指定的所有模塊。

當構建定製鏡像時,COPY是條重要的指令。如果在 Dockerfile 中不指定拷貝文件,Docker 鏡像將不會包含requirements.txt 這個文件。在 Docker 容器中,所有東西都是隔離的,除非在 Dockerfile 中指定執行,否則容器中不會包括所需的依賴。

重新運行構建

現在,我們讓 Docker 執行了一些定製任務,現在我們嘗試另一次 blog 鏡像的構建。

# 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

上述輸出所示,我們可以看到構建成功了,我們還可以看到另外一個有趣的信息---> Using cache。這條信息告訴我們,Docker 在構建該鏡像時使用了它的構建緩存。

Docker 構建緩存

當 Docker 構建鏡像時,它不僅僅構建一個單獨的鏡像;事實上,在構建過程中,它會構建許多鏡像。從上面的輸出信息可以看出,在每一「步」執行後,Docker 都在創建新的鏡像。

 Step 5 : COPY requirements.txt /build/
  ---> cef11c3fb97c

上面片段的最後一行可以看出,Docker 在告訴我們它在創建一個新鏡像,因為它列印了Image ID : cef11c3fb97c。這種方式有用之處在於,Docker能在隨後構建這個 blog 鏡像時將這些鏡像作為緩存使用。這很有用處,因為這樣, Docker 就能加速同一個容器中新構建任務的構建流程。從上面的例子中,我們可以看出,Docker 沒有重新安裝python-devpython-pip包,Docker 則使用了緩存鏡像。但是由於 Docker 並沒有找到執行mkdir命令的構建緩存,隨後的步驟就被一一執行了。

Docker 構建緩存一定程度上是福音,但有時也是噩夢。這是因為決定使用緩存或者重新運行指令的因素很少。比如,如果requirements.txt文件發生了修改,Docker 會在構建時檢測到該變化,然後 Docker 會重新執行該執行那個點往後的所有指令。這得益於 Docker 能查看requirements.txt的文件內容。但是,apt-get命令的執行就是另一回事了。如果提供 Python 軟體包的 Apt 倉庫包含了一個更新的 python-pip 包;Docker 不會檢測到這個變化,轉而去使用構建緩存。這會導致之前舊版本的包將被安裝。雖然對python-pip來說,這不是主要的問題,但對使用了存在某個致命攻擊缺陷的軟體包緩存來說,這是個大問題。

出於這個原因,拋棄 Docker 緩存,定期地重新構建鏡像是有好處的。這時,當我們執行 Docker 構建時,我簡單地指定--no-cache=True即可。

部署博客的剩餘部分

Python 軟體包和模塊安裝後,接下來我們將拷貝需要用到的應用文件,然後運行hamerkop應用。我們只需要使用更多的COPYRUN指令就可完成。

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

現在我們已經寫出了剩餘的構建指令,我們再次運行另一次構建,並確保鏡像構建成功。

# 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

運行定製的容器

成功的一次構建後,我們現在就可以通過運行docker命令和run選項來運行我們定製的容器,和之前我們啟動 nginx 容器一樣。

# docker run -d -p 80:80 --name=blog blog
5f6c7a2217dcdc0da8af05225c4d1294e3e6bb28a41ea898a1c63fb821989ba1

我們這次又使用了-d (detach)標識來讓Docker在後台運行。但是,我們也可以看到兩個新標識。第一個新標識是--name,這用來給容器指定一個用戶名稱。之前的例子,我們沒有指定名稱,因為 Docker 隨機幫我們生成了一個。第二個新標識是-p,這個標識允許用戶從主機映射一個埠到容器中的一個埠。

之前我們使用的基礎 nginx 鏡像分配了80埠給 HTTP 服務。默認情況下,容器內的埠通道並沒有綁定到主機系統。為了讓外部系統能訪問容器內部埠,我們必須使用-p標識將主機埠映射到容器內部埠。上面的命令,我們通過-p 80:80語法將主機80埠映射到容器內部的80埠。

經過上面的命令,我們的容器看起來成功啟動了,我們可以通過執行docker ps核實。

# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                         NAMES
d264c7ef92bd        blog:latest         nginx -g &apos;daemon off   3 seconds ago       Up 3 seconds        443/tcp, 0.0.0.0:80->80/tcp   blog  

總結

截止目前,我們擁有了一個運行中的定製 Docker 容器。雖然在這篇文章中,我們只接觸了一些 Dockerfile 指令用法,但是我們還是要學習所有的指令。我們可以檢查 Docker's reference page 來獲取所有的 Dockerfile 指令用法,那裡對指令的用法說明得很詳細。

另一個比較好的資源是 Dockerfile Best Practices page,它有許多構建定製 Dockerfile 的最佳練習。有些技巧非常有用,比如戰略性地組織好 Dockerfile 中的命令。上面的例子中,我們將articles目錄的COPY指令作為 Dockerfile 中最後的COPY指令。這是因為articles目錄會經常變動。所以,將那些經常變化的指令儘可能地放在最後面的位置,來最優化那些可以被緩存的步驟。

通過這篇文章,我們涉及了如何運行一個預構建的容器,以及如何構建,然後部署定製容器。雖然關於 Docker 你還有許多需要繼續學習的地方,但我想這篇文章給了你如何繼續開始的好建議。當然,如果你認為還有一些需要繼續補充的內容,在下面評論即可。

via: http://bencane.com/2015/12/01/getting-started-with-docker-by-dockerizing-this-blog/

作者:Benjamin Cane 譯者:su-kaiyao 校對:wxy

本文由 LCTT 原創翻譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國