Dockerfile

ouer1994發表於2019-08-20

掘金小冊 開發者必備的 Docker 實踐指南

Dockerfile

1. Dockerfile 檔案

我們可以將 Dockerfile 理解為一個由上往下執行指令的指令碼檔案。當我們呼叫構建命令讓 Docker 透過我們給出的 Dockerfile 構建映象時,Docker 會逐一按順序解析 Dockerfile 中的指令,並根據它們不同的含義執行不同的操作。

2. Dockerfile 指令

2.1 FROM: 指定基礎映象

在 Dockerfile 中可以多次出現 FROM 指令,當 FROM 第二次或者之後出現時,表示在此刻構建時,要將當前指出映象的內容合併到此刻構建映象的內容裡。

FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]

2.2 RUN: 用於向控制檯傳送命令

RUN <command>
RUN ["executable", "param1", "param2"]

RUN 指令是支援 \ 換行的,如果單行的長度過長,建議對內容進行切割,方便閱讀。

2.3 ENTRYPOINT 和 CMD: 指定基於映象啟動的容器 啟動時 啟動 1 號程式的命令

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

ENTRYPOINT 和 CMD 設計的目的是不同。ENTRYPOINT 指令主要用於對容器進行一些初始化,而 CMD 指令則用於真正定義容器中主程式的啟動命令

當 ENTRYPOINT 與 CMD 同時給出時,CMD 中的內容會作為 ENTRYPOINT 定義命令的引數,最終執行容器啟動的還是 ENTRYPOINT 中給出的命令。

2.4 EXPOSE: 指定容器要暴露埠

EXPOSE <port> [<port>/<protocol>...]

2.5 VOLUME: 定義容器的資料卷

2.6 COPY 和 ADD: 從宿主檔案系統複製,新增檔案到映象

COPY [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

對比 COPY 與 ADD,兩者的區別主要在於 ADD 能夠支援使用網路端的 URL 地址作為 src 源,並且在原始檔被識別為壓縮包時,自動進行解壓,而 COPY 沒有這兩個能力。

3 構建映象

sudo docker build -t XXX:TAG -f .../Dockerfile 基礎檔案目錄

基礎檔案目錄:
    Dockerfile 所在的檔案目錄
    Dockerfile 檔案中 COPY, ADD 命令的檔案路徑也是基於此資料夾

4 Dockerfile 使用技巧

4.1 構建中使用變數

在 Dockerfile 裡,我們可以用 ARG 指令來建立一個引數變數,我們可以在構建時透過構建指令傳入這個引數變數,並且在 Dockerfile 裡使用它。

ARG PHP_VERSION

FROM php:${PHP_VERSION}-fpm

# 構建映象
sudo docker build --build-arg PHP_VERSION=7.2 --build-arg XXX=111 ./workspace

4.2 環境變數

ARG MYSQL_VERSION=latest
FROM mysql:${MYSQL_VERSION}

LABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>"

#####################################
# Set Timezone
#####################################

ARG TZ=UTC
ENV TZ ${TZ}
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && chown -R mysql:root /var/lib/mysql/

# ...

EXPOSE 3306

# 1. 使用: -e 或 ---env 在容器啟動時指定
sudo docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# 2. 在 Dockerfile 中指定環境變數

環境變數的使用方法與引數變數一樣,也都是能夠直接替換指令引數中的內容。
與引數變數只能影響構建過程不同,環境變數不僅能夠影響構建,還能夠影響基於此映象建立的容器。環境變數設定的實質,其實就是定義作業系統環境變數,所以在執行的容器裡,一樣擁有這些變數,而容器中執行的程式也能夠得到這些變數的值。

另一個不同點是,環境變數的值不是在構建指令中傳入的,而是在 Dockerfile 中編寫的。

ENV 指令所定義的變數,永遠會覆蓋 ARG 所定義的變數,即使它們定時的順序是相反的。

4.3 構建快取

Docker 在映象構建的過程中,還支援一種快取策略來提高映象的構建速度。

由於映象是多個指令所建立的映象層組合而得,那麼如果我們判斷新編譯的映象層與已經存在的映象層未發生變化,那麼我們完全可以直接利用之前構建的結果,而不需要再執行這條構建指令,這就是映象構建快取的原理。

那麼 Docker 是如何判斷映象層與之前的映象間不存在變化的呢?這主要參考兩個維度,第一是所基於的映象層是否一樣,第二是用於生成映象層的指令的內容是否一樣。

基於這個原則,我們在條件允許的前提下,更建議將不容易發生變化的搭建過程放到 Dockerfile 的前部,充分利用構建快取提高映象構建的速度。另外,指令的合併也不宜過度,而是將易變和不易變的過程拆分,分別放到不同的指令裡。

在另外一些時候,我們可能不希望 Docker 在構建映象時使用構建快取,這時我們可以透過 --no-cache選項來禁用它。

sudo docker build --no-cache ./webapp
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章