tags: docker

Dockerfile

Docker會讀取Dcokerfile的指令自動建立image,Dockerfile為一文件涵蓋了所有使用者可以建立image的指令集,以下介紹各種可以用在Dcokerfile的指令。

Format

這份教學是不分大小寫的,但是為了容易辨別以下會使用大寫作為區分。。
Docker會按照順序讀取Dockerfile裡面的指令,一個Dcokerfile必須由FROM開頭,FROM指令表達了從哪一個母Image為根基,只有ARG能被寫在FROM指令前面。
Docker會將#視作註解符。

FROM

FROM指令會初始化一個build階段並且為接下來的指令設定一個母image,一有效的Dockerfile會必須是由FROM指令為開頭,母image可以為任何有效的image。

  • ARG是唯一一個指令可以在FROM前出現的。
  • FROM在單一Dockerfile中可以出現好幾次用來建立多個images或是使用其中一個為另一個image的bulid stage。
  • Optionally可以在FROM後加上AS name,這個name可以被使用在後續的FROMCOPY --from=<name>指令上用來標示出是哪個image要被用在建立這個stage上。
  • tagdigest也是optionally,省略的話會自動以latest為預設

Understand how ARG and FROM interact

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有兩種形式:

  • 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指令有三種格式

  • 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的預設值

別將RUNCMD搞混了,RUN實際上會執行指令並且commit結果,CMD並不會在建立階段執行任何東西而是給了image預期的指令。

LABEL

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."

MAINTAINER(棄用)

官方建議使用LABEL來做標註image的維護者會是更有彈性的作法。例如使用docker inspect時,設定以下方式會與MAINTAINER相呼應:

LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"

EXPOSE

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

EXPOSE指令指定的Docker在runtime階段要監聽哪一個網路接口,你可以設定為TCP或是UDP,預設值是TCP如果沒有特別設定的話。
EXPOSE指令並非真正發布這個port,其真正的作用在於文件上的形式為建立這image和使用並啟動這container的人之間說明是哪一個port會被使用,為了真正在跑container時使用這個port,在docker run時要使用-p標籤。

ENV

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 有兩種寫法

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

COPY 指令會從<src>複製新的檔案、路徑並將它們加入到image的檔案系統路徑<dest>

VOLUME

VOLUME ["/data"]

VOLUME指令會建立一個映照點(mount point)有自訂的名稱並標註其為存儲本地主機或其他container的外部資料。 其值可以是JSON陣列VOLUME ["/var/log/"],或是字串有著多個參數例如,VOLUME /var/log or VOLUME /var/log /var/db