Dockerfile 的使用
Docker build命令和鏡像構建過程
docker build
命令使用的時候其參數有3種類型來表示構建context的3種來源:PATH
, -
和 URL
。更多>>
這里的構建context是指傳入docker build
命令的所有文件。
一般情況下,將本地主機的一個包含Dockerfile的目錄中的所有內容作為context。context通過docker build
命令傳入到Docker daemon后,便開始按照Dockerfile中的內容構建鏡像。
除了FROM
指令,其它每一條指令都會在上一條指令所生成的鏡像的基礎上執行,執行完后會生成一個新的鏡像層,新的鏡像層覆蓋在原來的鏡像之上從而形成了新鏡像。Dockerfile所生成的最終鏡像就是在基礎鏡像上面疊加一層層的鏡像層組建的。
為了提高鏡像構建的速度,Docker daemon會緩存構建過程中的中間鏡像。當從一個已經在緩存中的基礎鏡像開始構建新鏡像時,會像Dockerfile中的下一條指令和基礎鏡像的所有子鏡像做比較,如果有一個子鏡像是由相同命令生成的,則命中緩存,直接使用該鏡像,而不用再生成一個新的鏡像。
但是COPY
和ADD
命令與其它命令稍有不同,其他指令只對比生成鏡像的指令字符串是否相同;COPY
和ADD
還要對比容器中的文件內容和所添加的文件內容是否相同。此外,鏡像構建過程中,一旦緩存失效,則后續的指令都將生成新的鏡像,而不再使用緩存。
Dockerfile指令
- FROM
格式:
FROM <image>
FROM <image>:<tag>
FROM
指令為后面的指令提供基礎鏡像,因些一個有效的Dockerfile必須以FROM
作為第一條非注釋指令。
- ENV
格式:
ENV <key> <value>
ENV <key>=<value>
ENV
用于聲名明境變量。并且在Dockerfile中ENV指令聲明環境可以被后面的特定指令(ENV
,ADD
,COPY
,WORKDIR
,EXPOSE
,VOLUME
,USER
)解釋使用。
使用格式:
$variable_name
${variable_name}
- COPY
格式:
COPY <src> <dest>
<src>所指定的源可以有多個,但必須在context中,即必須是context根目錄的相對路徑。不能使用形如COPY ../something /something
這樣的指令。此外,<src>可以使用通配符指向所有匹配通配符的文件或目錄,如,COPY hom* /mydir/
。
<dest>可以是文件或目錄,但必須是目標鏡像中的絕對路徑或者相對于WORKDIR
的相對路徑。
- ADD
格式:
ADD <src> <dest>
ADD
和COPY
在功能上很相似,但ADD
還支持其他功能。<src>可以是一個指向一個網絡文件的URL,此時若<dest>指向一個目錄,則URL必須是完全路徑,這樣可以獲得該網絡文件名filename,該文件會被復制添加到<dest>/<filename>。例如,ADD http://example.com/foobar /
會創建文件/foobar。
一般推薦使用COPY
,因為COPY
只支持本地文件,相比ADD
而言,它更透明。
- RUN
格式:
RUN <command> // shell格式
RUN ["executable", "param1", "param2"] // exec格式,推薦格式
RUN
指令會在前一條命令創建出的鏡像的基礎上創建一個容器,并在容器中運行命令,在命令結束運行后提交容器為新鏡像。
當使用shell格式時,命令通過/bin/sh -c
運行;
當使用exec格式時,命令是直接運行的,容器不調用shell程序,即容器中沒有shell程序。exec格式中的參數會當成JSON數組被Docker解析,故必須使用雙引號而不能使用單引號。因為exec格式不會在shell中執行,所以環境變量的參數不會被替換。
- CMD
格式:
CMD <command> // shell格式
CMD ["executable", "param1", "param2"] // exec格式,推薦格式
CMD ["param1", "param2"] // 為ENTRYPOINT指令提供參數
CMD
提供運行的默認值,默認值可以是一些參數,或指令。一個Dockerfile中只有最后一條CMD
指令有效。而且CMD
指令需要要ENTRYPOINT
指令配合使用。
與RUN
指令不周的是:
RUN
指令在構建鏡像時執行命令,并生成的鏡像;
CMD
指令在構建鏡像時并不執行任何命令,而是在容器啟動時默認將CMD指令作為第一條執行的命令。如果用戶在命令行界面運行docker run
命令時指定了命令參數,則會覆蓋CMD
指令中的命令。
- ENTRYPOINT
格式:
ENTRYPOINT <command> // shell格式
ENTRYPOINT ["executable", "param1", "param2"] // exec格式,推薦格式
ENTRYPOINT
指令和CMD
指令類似,都可以讓容器在每次啟動時執行相同的命令。但它們之間又有不同。一個Dockerfile中只有最后一條ENTRYPOINT
指令有效。
當使用sheel格式時,ENTRYPOINT
指令會忽略任何CMD
指令和docker run
命令的參數,并且運行在bin/sh -c
中。這意味著ENTRYPOINT
指令進程為bin/sh -c
的子進程,進程在容器中的PID將不是1,且不能接受Unix信號。即當使用docker stop <container>命令時,命令進程接受不到SIGTERM信號。
我們推薦使用exec格式,使用此格式時,docker run
傳入的命令參數會覆蓋CMD
指令的內容,并且添加到ENTRYPOINT
指令的參數中。
從ENTRYPOINT
的使用中可以看出,CMD
可以是參數,也可以是指令,而ENTRYPOINT
只能是命令;另外,docker run
提供的運行命令參數可以覆蓋CMD
,但是不能覆蓋ENTRYPOINT
。
Dockerfile 使用心得
- 使用標簽
給鏡像打標簽,易讀的鏡像標簽可以幫助了解鏡像的功能,如:
docker build -t "mydockerimage:1.0" .
- 謹慎選擇基礎鏡像
busybox < debian < centos < ubuntu
- 充分利用緩存
為了有效地利用緩存,需要保證指令的連續性,盡量將所有Dockerfile文件中相同的部分都放在前面,而將不同的部分放在后面。
- CMD和ENTRYPOINT
CMD
和ENTRYPOINT
指令指定了容器運行的命令,推薦二者結合使用。使用exec格式的ENTRYPOINT
指令設置固定的默認命令和參數,然后使用CMD
指令設置可變的參數。
- 不要在Dockerfile中做端口映射
Docker的兩個核心概念是可重復性和可移植性,鏡像應該可以在任何主機上運行多次。使用Dockerfile的EXPOSE
指令,雖然可以將容器端口映射到主機端口上,但會破壞Docker的可移植性,且這樣的鏡像在一臺主機上只能啟動一個容器。所以端口映射就在docker run
命令中用-p參數指定。
# 不要在Dockerfile中做如下映射
EXPOSE 80:8080
# 僅僅暴露80端口,需要另做映射
EXPOSE 80