Docker#3 - Dockerfile 指令解說

前言

當我們採取 docker run 啟動一個容器,若要移轉到另一台機器時,會使用 docker exportdocker import 這兩個指令做匯出、匯入容易,但是喔半遇到龐大的匯出資料或映像的時候,可能會發生不預期的事情發生。

此時利用 Docker 客製化的方式將製作映像的過程都寫在一個檔案上,讓過程可以獨立一點,放到其他機器上時,能夠根據組態建立對應的映像,就會是一個相當不錯的解決方案了。

關於 Dockerfile 檔案

是用來做自動化建構映像的設定檔案,可以知道所有映像檔的組成,檔案小,容易分享,也方便實現映像的移植。這個檔案沒有副檔名,但卻是由每一行指令組成的文字檔案,命令不分大小寫。

基礎指令

# 開頭為註解

1
# test comment

FROM

通常第一行指令行,指定哪一個 image 作為基底來建構,它允許多個 FROM 指令

1
2
3
FROM <images>
FROM ubuntu
FROM ubuntu:16.04

MAINTAINER

此指令用途是提供映像檔的作者資訊

1
2
3
MAINTAINER <name>
MAINTAINER maruko
MAINTAINER maruko xxxxxxx@yourmail.com

控制指令

RUN

執行指定的指令,在建立映像檔過程對於很多個操作,每加一個 RUN 就會在基底的映像檔案加上一層資料層,實際上就是 shell 程式執行的操作

1
2
3
RUN <COMMEND>
RUN command param1 param2 ...
RUN ["executable", "param1", "param2"]

例如

1
RUN mkdir testfolder

那在環境執行上就會是

1
$ /bin/sh -c mkdir testfolder

有些執行 param1 param2 太長的話,可以使用 \ 符號來換行,會比較好閱讀

1
2
3
4
5
6
7
8
RUN mkdir -p /home/demo
RUN ["apt-get", "install", "python3"]
RUN apt-get update && apt-get install -y --force-yes \
autoconf \
file \
g++
apache2 \
php5

WORKDIR

指定工作目錄

1
2
3
4
5
WORKDIR /usr
# 實際上是 /usr/local
WORKDIR local
# 也可以使用環境變數
WORKDIR $BASEDIR/www

如果發現目錄不存在時,會自動建立

ONBUILD

這個指令是作為其他應用程式基底時執行的指令

A-Image

1
2
ONBUILD ADD . /home/tmp
ONBUILD mkdir -p /home/demo/docker

B映像檔是以A映像檔為基底,則A映像檔中的ONBUILD指令就會被觸發

1
2
3
4
# 以A映像檔為基底
FROM A-Image

# 觸發A映像檔ONBUILD的指令,即會自動將 A-Image 去執行上面二個指令行

引入指令

COPY

1
2
COPY [--chown=<user>:<group>] <來源路徑>... <目標路徑>
COPY [--chown=<user>:<group>] ["<來源路徑>",... "<目標路徑>"]

這兩個 ADD, 與 COPY 指令,差別在 COPY 不能識別網路位置

1
COPY package.json /usr/src/app/

來源路徑可以很多個

1
2
COPY hom* /mydir/
COPY hom?.txt /mydir/

ADD

這個與 COPY 指令相同,可以將本地端的檔案或目錄加入到映像檔的指定位置

1
2
ADD [--chown=<user>:<group>] <來源路徑>... <目標路徑>
ADD [--chown=<user>:<group>] ["<來源路徑>",... "<目標路徑>"]

而 ADD 是可以支援網址的,就是可以加入遠端的檔案,如果要加入壓縮檔案 (.gzip/.bzip2, .xz),ADD 是可以直接自動解壓縮,下載後的文件會自動設定為 600,COPY 則不會

執行指令

CMD

設定映像檔啟動為容器的時候要執行的指令,提供了三個格式

1
2
3
4
5
6
# exec 形式
CMD ["executable", "param1", "param2"]
# 參數傳給由 ENTRYPOINT 指令列出的參數
CMD ["param1", "param2"]
# 以 Shell 形式執行,預設是在 /bin/sh -c 執行
CMD command param1 param2

容器只會連結一個應用程式,只能存在一個 CMD 指令!! 若你寫了兩個以上的 CMD 就只會最後一行才會執行。

ENTRYPOINT

這組有點像 CMD 指令,但是不會像 CMD 有覆蓋的問題,使用 entrypoint 一定會被執行

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

這個在 Dockerfile 也只能有一個 ENTRYPOINT ,若指定多個時,只會有最後一個生效

配置指令

EXPOSE

設定容器對外的通訊埠,提供外界使用(從外部存取容器內程式監聽的連接埠),啟動容器時需要透過 -P,否則會自動分派一個通訊部轉發到指定的埠號,格式如下:

1
EXPOSE <port> [<port>...]

ENV

設定環境變數,有兩種格式,覺得第二種比較簡易

1
2
ENV <key> <value>
ENV <key>=<value>

LABEL

主要是映像檔的 metadata 資訊,中繼資料作為標記

1
LABEL <key>=<value> <key>=<value> <key>=<value>

使用方式

1
2
3
LABEL "com.example.vendor"="MARUKO"
LABEL version="1.0"
LABEL owner="marukochan"

但原則上,每一的執行 LABEL 就會多一層映像層,建議只要寫成一條 LABEL 即可

1
LABEL com.example.vendor="MARUKO" version="1.0" owner="marukochan"

USER

指定運行容易的用戶名稱或 UID

1
2
USER <user>[:<group>]
USER <UID>[:<gid>]

使用方式

1
2
3
4
5
6
RUN groupadd -r tester && useradd -r -g tester tester
# 指定用戶名稱
USER tester

# 或使用UID來指定
USER 1000

ARG

建立過程時,需要做一些配置或使用變數,這個只有適用於建置的過程,而 ENV則是配置環境變數,會影響映像檔的編譯

1
2
ARG param1
ARG param2=testvalue

另外千萬別使用ARG 來配置登入密碼、key 資訊,因為只要使用 docker history 就會都看到了。