Docker Build Context

建立一個新的 Docker Image 不只需要準備一份 Dockerfile,還需要準備一個 Build Context 給它,放的是一些編譯映像檔所需的檔案或目錄,如此 Dockerfile 才能去 COPY 或 ADD 這些資料到映像檔裡面。Build Context 可以是一個指定的目錄或是 URL,下方是一個常見的編譯指令,最後面那個點的功能就是將 Build Context 設在當前目錄。

$ docker build -t test:1.0 .

當然這是一個理想的狀態,很多時候會遇到一些限制,像是編譯所需的檔案在上層目錄或是其他非常遙遠的地方,那該怎麼辦呢?來看看下面在 Dockerfile 裡面的嘗試。

FROM ubuntu:18.04
RUN apt-get -y update
COPY ../test/test.sh /usr/local/bin/test.sh

若事情有這麼簡單就好了,編譯出錯,錯誤訊息如下:

官方文件有提到 ADD 或 COPY 時不允許使用 ../ 這類型的語法,因為指定的資源必須在 Build Context 目錄底下。看來在 Dockerfile 裡面行不通,那就改用其他方法吧!

docker build -f

既然 Build Context 的指定方式限制太多,那就反過來指定 Dockerfile 的路徑吧!到 test 目錄底下,透過 -f (--file string) 來指定 Dockerfile 的路徑,這樣就可以將 test 目錄作為 Build Context,然後使用其他目錄的 Dockerfile,範例如下:

context/Dockerfile
............
COPY test.sh /usr/local/bin/test.sh

編譯指令
$ docker build -t test:1.0 -f ../context/Dockerfile .

當然也可以指定當下目錄的 Dockerfile,然後指定 test 目錄作為 Build Context,像是這樣:

$ docker build -t test:1.0 -f ./Dockerfile ../test

這裡要小心的是你不能只用 docker build ../test 這樣的方式,因為這會造成 Build Context 跑到 test 目錄去,若 test 目錄有一份 Dockerfile,那建立出來的映像檔就是依據 test/Dockerfile 而非原本你想使用的 Dockerfile 喔!

docker-compose

如果你剛好正在使用 docker-compose,會稍微輕鬆一些,因為它本身就提供了指定 Context 和 Dockerfile 的標籤,因此只要妥善利用就能達到我們的目標,範例如下:

context/docker-compose.yml
version: '3'
services:
  test:
    build:
      context: ../test
      dockerfile: ../context/Dockerfile
    image: test:1.0

編譯指令

$ docker-compose build

感覺沒有比較好XD,如果覺得這樣看起來凌亂,是可以將 Build Context 範圍設大一點,像是這樣:

build:
      context: ../
      dockerfile: context/Dockerfile

不是很建議,Build Context 太大會讓編譯一開始傳送 Context 到 Docker Daemon 時花費太多時間。再者,docker-compose 本來就不是為了處理 Build Context 而被設計出來東西,因此這個當作練習就好。

留言

這個網誌中的熱門文章

程式語言常用之符號與詞彙 - 中英文對照

Repo 實用指令

什麼是 Bootloader?