docker
Docker會讀取Dcokerfile
的指令自動建立image,Dockerfile
為一文件涵蓋了所有使用者可以建立image的指令集,以下介紹各種可以用在Dcokerfile
的指令。
這份教學是不分大小寫的,但是為了容易辨別以下會使用大寫作為區分。。
Docker會按照順序讀取Dockerfile
裡面的指令,一個Dcokerfile
必須由FROM
開頭,FROM
指令表達了從哪一個母Image為根基,只有ARG
能被寫在FROM
指令前面。
Docker會將#
視作註解符。
FROM
指令會初始化一個build階段並且為接下來的指令設定一個母image,一有效的Dockerfile
會必須是由FROM
指令為開頭,母image可以為任何有效的image。
ARG
是唯一一個指令可以在FROM
前出現的。FROM
在單一Dockerfile
中可以出現好幾次用來建立多個images或是使用其中一個為另一個image的bulid stage。FROM
後加上AS name
,這個name可以被使用在後續的FROM
和COPY --from=<name>
指令上用來標示出是哪個image要被用在建立這個stage上。tag
和digest
也是optionally,省略的話會自動以latest
為預設FROM
指令支援了ARG
宣告的變數。
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
在FROM
前宣告的ARG
是屬於build stage之外的,所以它沒辦法被使用在FROM
後面的任何指令上,為使用第一個FROM
前的ARG
宣告的值,可以使用一個不帶有值的ARG
指令。
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
RUN有兩種形式:
RUN <command>
(shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)RUN ["executable", "param1", "param2"]
(exec form)RUN
指令會在新的layer上針對目前的image執行任何指令並且遞交結果,結果會被用在Dockerfile
的下一步。
RUN
指令的分層以及遞交結果符合了Docker的核心概念就是階段控制是很簡單的且容器可以在images裡面的任何階段被建立,就像是版本控制一樣。
CMD
指令有三種格式
CMD ["executable","param1","param2"]
(exec form, this is the preferred form)CMD ["param1","param2"]
(as default parameters to ENTRYPOINT)CMD command param1 param2
(shell form)Dokcerfile
只能夠有一個CND
指令,如果使用了超過一個的CMD
指令只有最後一個CMD
會有作用。
CMD
最主要的目的就是提供一個預設值給執行中的container,這些預設值可以包含可被執行的,或是省略可執行的,但就要提供一個ENTRYPOINT
指令。如果CMD
是用來提供ENTRYPOINT
預設值參數的話,則兩個指令都要使用JSON array format。
如果有特別在docker run
時特別另外寫參數,則會覆蓋掉CMD
的預設值
別將RUN
和CMD
搞混了,RUN
實際上會執行指令並且commit結果,CMD
並不會在建立階段執行任何東西而是給了image預期的指令。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL
指令為image加入metadata,LABEL
是key-value paie的寫法,為在LABEL
中使用空格,要使用引號或倒斜線,以下一些範例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
官方建議使用LABEL
來做標註image的維護者會是更有彈性的作法。例如使用docker inspect
時,設定以下方式會與MAINTAINER
相呼應:
LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"
EXPOSE <port> [<port>/<protocol>...]
EXPOSE
指令指定的Docker在runtime階段要監聽哪一個網路接口,你可以設定為TCP或是UDP,預設值是TCP如果沒有特別設定的話。
EXPOSE
指令並非真正發布這個port,其真正的作用在於文件上的形式為建立這image和使用並啟動這container的人之間說明是哪一個port會被使用,為了真正在跑container時使用這個port,在docker run
時要使用-p
標籤。
ENV <key>=<value> ...
ENV
指令設定了環境變數<key>
為<value>
的值,這個value會是接下來build stage中指令的環境變數。
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
ENV
指令允許多個<key>=<value> ...
例如:
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
當一個container從一個被建立後的image運行後,使用ENV
建立的環境變數會被保留,可以使用docker inspect
來觀察,並且使用docker run --env <key>=<value>
來變更。
永久性的環境變數可能造成一些壞處,例如設定ENV DEBIAN_FRONTEND=noninteractive
改變了apt-agt
的行為,並有可能混淆image的使用者。
如果一個環境變數是只有在建立階段是被需要的而非在最終的image,考慮將其放在單一指令例如下面:
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
或是使用ARG
,這也不會保存到最後階段的image上
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...
ADD 有兩種寫法
ADD [--chown=<user>:<group>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
ADD
指令會從<src>
複製新的檔案、路徑或是遠程文件並將它們加入到image的檔案系統路徑<dest>
。
多個<src>
是可以被設定的但如果他們是檔案或是路徑,他們的路徑會被當作這個build的內容的來源。
個別<src>
可以是通配符例如:
將所有hom開頭的檔案加入
ADD hom* /mydir/
下面是替換單一字母
ADD hom?.txt /mydir/
<dest>
是一組絕對路徑或是WORKDIR
的相對路徑,就是資源會被複製到的container的地方。
以下例子使用相對路徑,會將"test.txt"複製到<WORKDIR>/relativeDir/
:
ADD test.txt relativeDir/
以下是絕對路徑,會將"test.txt"複製到/absoluteDir/
ADD test.txt /absoluteDir/
COPY
指令會從<src>
複製新的檔案、路徑並將它們加入到image的檔案系統路徑<dest>
。
VOLUME ["/data"]
VOLUME
指令會建立一個映照點(mount point)有自訂的名稱並標註其為存儲本地主機或其他container的外部資料。 其值可以是JSON陣列VOLUME ["/var/log/"]
,或是字串有著多個參數例如,VOLUME /var/log
or VOLUME /var/log /var/db
。