1. 程式人生 > >3-3.5.1 docker build 用法

3-3.5.1 docker build 用法

在包含Dockerfile 檔案的目錄下執行:

docker build -t nginx:v3 .

即是建立了映象。

docker build  命令進行映象構建。其格式為:

docker build [選項] <上下文路徑/URL/->


映象構建上下文(Context)

如果注意,會看到  docker build  命令最後有一個  .  。 .  表示當前目錄,而Dockerfile  就在當前目錄,因此不少初學者以為這個路徑是在指定Dockerfile  所在路徑,這麼理解其實是不準確的。如果對應上面的命令格式,你可能會發現,這是在指定上下文路徑。那麼什麼是上下文呢?

首先我們要理解  docker build  的工作原理。Docker 在執行時分為 Docker 引擎(也就是服務端守護程序)和客戶端工具。Docker 的引擎提供了一組 REST API,被稱為 Docker Remote API,而如  docker  命令這樣的客戶端工具,則是通過這組 API 與 Docker 引擎互動,從而完成各種功能。因此,雖然表面上我們好像是在本機執行各種  docker  功能,但實際上,一切都是使用的遠端呼叫形式在服務端(Docker 引擎)完成。也因為這種 C/S 設計,讓我們操作遠端伺服器的 Docker 引擎變得輕而易舉。

當我們進行映象構建的時候,並非所有定製都會通過  RUN  指令完成,經常會需要將一些本地檔案複製進映象,比如通過  COPY  指令、 ADD  指令等。而  docker build  命令構建映象,其實並非在本地構建,而是在服務端,也就是 Docker 引擎
中構建的。那麼在這種客戶端/服務端的架構中,如何才能讓服務端獲得本地檔案呢?

這就引入了上下文的概念。當構建的時候,使用者會指定構建映象上下文的路徑, docker build  命令得知這個路徑後,會將路徑下的所有內容打包,然後上傳給 Docker 引擎。這樣 Docker 引擎收到這個上下文包後,展開就會獲得構建映象所需的一切檔案。如果在  Dockerfile  中這麼寫:

COPY ./package.json /app/

這並不是要複製執行  docker build  命令所在的目錄下的  package.json  ,也不是複製  Dockerfile  所在目錄下的  package.json  ,而是複製 上下文(context) 目錄下的  package.json  。

因此, COPY  這類指令中的原始檔的路徑都是相對路徑。這也是初學者經常會問的為什麼  COPY ../package.json /app  或者  COPY /opt/xxxx /app  無法工作的原因,因為這些路徑已經超出了上下文的範圍,Docker 引擎無法獲得這些位置的檔案。如果真的需要那些檔案,應該將它們複製到上下文目錄中去。

現在就可以理解剛才的命令  docker build -t nginx:v3 .  中的這個  .  ,實際上是在指定上下文的目錄, docker build  命令會將該目錄下的內容打包交給Docker 引擎以幫助構建映象。

如果觀察  docker build  輸出,我們其實已經看到了這個傳送上下文的過程:

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...

理解構建上下文對於映象構建是很重要的,避免犯一些不應該的錯誤。比如有些初學者在發現  COPY /opt/xxxx /app  不工作後,於是乾脆將  Dockerfile  放到了硬碟根目錄去構建,結果發現  docker build  執行後,在傳送一個幾十 GB 的東西,極為緩慢而且很容易構建失敗。那是因為這種做法是在讓  docker build 打包整個硬碟,這顯然是使用錯誤。

一般來說,應該會將  Dockerfile  置於一個空目錄下,或者專案根目錄下。如果該目錄下沒有所需檔案,那麼應該把所需檔案複製一份過來。如果目錄下有些東西確實不希望構建時傳給 Docker 引擎,那麼可以用  .gitignore  一樣的語法寫一個  .dockerignore  ,該檔案是用於剔除不需要作為上下文傳遞給 Docker 引擎的。

那麼為什麼會有人誤以為  .  是指定  Dockerfile  所在目錄呢?這是因為在預設情況下,如果不額外指定  Dockerfile  的話,會將上下文目錄下的名為Dockerfile  的檔案作為 Dockerfile。

這只是預設行為,實際上  Dockerfile  的檔名並不要求必須為Dockerfile  ,而且並不要求必須位於上下文目錄中,比如可以用  -f ../Dockerfile.php  引數指定某個檔案作為  Dockerfile  。

當然,一般大家習慣性的會使用預設的檔名  Dockerfile  ,以及會將其置於映象構建上下文目錄中。


其它  docker build  的用法


直接用 Git repo 進行構建


或許你已經注意到了, docker build  還支援從 URL 構建,比如可以直接從 Git repo 中構建:

$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.
14
docker build https://github.com/twang2218/gitlab-ce-zh.git\#:8.14
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM gitlab/gitlab-ce:8.14.0-ce.0
8.14.0-ce.0: Pulling from gitlab/gitlab-ce
aed15891ba52: Already exists
773ae8583d14: Already exists
...

這行命令指定了構建所需的 Git repo,並且指定預設的  master  分支,構建目錄為  /8.14/  ,然後 Docker 就會自己去  git clone  這個專案、切換到指定分支、並進入到指定目錄後開始構建。

用給定的 tar 壓縮包構建

$ docker build http://server/context.tar.gz

如果所給出的 URL 不是個 Git repo,而是個  tar  壓縮包,那麼 Docker 引擎會下載這個包,並自動解壓縮,以其作為上下文,開始構建。

從標準輸入中讀取 Dockerfile 進行構建

docker build - < Dockerfile

cat Dockerfile | docker build -

如果標準輸入傳入的是文字檔案,則將其視為  Dockerfile  ,並開始構建。這種形式由於直接從標準輸入中讀取 Dockerfile 的內容,它沒有上下文,因此不可以像其他方法那樣可以將本地檔案  COPY  進映象之類的事情。

從標準輸入中讀取上下文壓縮包進行構建

$ docker build - < context.tar.gz

如果發現標準輸入的檔案格式是  gzip  、 bzip2  以及  xz  的話,將會使其為上下文壓縮包,直接將其展開,將裡面視為上下文,並開始構建。