這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Docker可以通過從Dockerfile包含所有命令的文字檔中讀取指令,自動構建鏡像。
每個需要使用Docker的項目都應該有一個Dockerfile,這個檔案描述了我們需要的鏡像環境。
Dockerfile指令
FROM
有效Dockerfile必須從FROM開始,鏡像可以是任何有效鏡像。
官方建議,如果只需要一個linux基礎鏡像,建議使用Debian鏡像,控制的很小。
FROM <image> [AS <name>]或FROM <image>[:<tag>] [AS <name>]或FROM <image>[@<digest>] [AS <name>]
LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
該LABEL指令將中繼資料添加到映像。A LABEL是一個索引值對。要在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."
映像可以有多個標籤。要指定多個標籤,Docker建議LABEL在可能的情況下將標籤組合到單個指令中。每個LABEL指令產生一個新的層
LABEL multi.label1="value1" multi.label2="value2" other="value3"或LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3"
要查看映像的標籤,請使用docker inspect命令。
$ docker inspect Ubuntu
RUN
如果你需要RUN多個命令,建議使用多行寫出來,使用( \ )分隔多行
RUN有兩種形式
- RUN <command> shell形式,命令在shell中運行,預設為/bin/sh
- RUN ["executable", "param1", "param2"]
該RUN指令在當前鏡像的頂部的新層中執行任何命令,病提交結果,結果提交的映像當被使用者下一步Dockerfile
可以使用命令更改shell中的預設的SHELL.
在shell表單中,可以使用 \ 講一條指令繼續下一行
例如:
RUN /bin/bash -c 'source $HOME/.bashrc; \echo $HOME'
相當於:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
註:如果你想使用其他shell比如bash,請使用在所需的shell傳遞參數,RUN ["/bin/bash", "-c", "echo hello"]
apt-get
如果你的基礎鏡像使用的是Debian,那你一定會經常使用apt-get命令安裝軟體
一般來說,我們最好不要使用apt-get upgrade或者apt-get dist-upgrade,使用上述命令會造成許多非必須包被安裝,這是不必要的。如果知道要更新當前基礎鏡像中中的某一個軟體,比如nginx,請使用apt-get install -y nginx來進行安裝更新
通常我們會如下使用他:
RUN apt-get update && apt-get install -y \ package-bar \ package-baz \ package-foo
先執行apt-get update是為了確保不被緩衝所幹擾,保證安裝的軟體是比較新的版本。
以下是一個使用RUN和apt-get的一個例子:
RUN apt-get update && apt-get install -y \ aufs-tools \ automake \ build-essential \ curl \ dpkg-sig \ libcap-dev \ libsqlite3-dev \ mercurial \ reprepro \ ruby1.9.1 \ ruby1.9.1-dev \ s3cmd=1.1.* \ && rm -rf /var/lib/apt/lists/*
最後刪除/var/lib/apt/lists/是為了清理緩衝從而減少鏡像大小,Debian和Ubuntu都會在最後自動調用apt-get clean*來清理,不需要顯示調用
CMD
該指令有三種形式:
- CMD ["executable","param1","param2"],這是首先方式
- CMD ["param1","param2"],作為ENTRYPOINT的預設參數
- CMD command param1 param2 外殼形式
當以shell或者exec格式使用是,該CMD指令設定運行鏡像時要執行的命令
如果你使用shell的形式CMD,那麼<command>將執行 /bin/sh -c:
FROM ubuntuCMD echo "This is a test." | wc -
如果您想在 <command> 沒有shell 的情況下運行,那麼您必須將該命令表達為JSON數組,並提供可執行檔的完整路徑。 此數組形式是首選格式CMD。任何其他參數必須單獨表示為數組中的字串:
FROM ubuntuCMD ["/usr/bin/wc","--help"]
CMD指令應用與運行鏡像中所包含的軟體,及其參數。CMD應該以CMD [“executable”, “param1”, “param2”…]表示。
在很多時候,CMD給出的是一個互動式shell,比如bash,Python等,比如CMD ["perl", "-de0"],CMD ["python"],或 CMD [“php”, “-a”]。
EXPOSE
該指令指示容器講監聽連結的連接埠,類似於,將容器中的某一個連接埠暴露出去,從而在外部存取綁定該連接埠。在容器內部,應該使用應用的傳統通用連接埠。
EXPOSE <port> [<port>...]
該EXPOSE指令通知Docker容器在運行時監聽指定的網路連接埠。EXPOSE不使主機的連接埠可以訪問。為此,您必須使用該-p標誌來發布一系列連接埠,或者使用該-P標誌來發布所有暴露的連接埠。您可以公開一個連接埠號碼,並在外部發布另一個連接埠號碼
ENV
ENV <key> <value>ENV <key>=<value> ...
註:
- 該ENV指令將環境變數<key>設定為該值 <value>。該值將處於所有“後代” Dockerfile命令的環境中
- 該ENV指令有兩種形式。第一個表單ENV <key> <value>將會將一個變數設定為一個值。第一個空格後的整個字串將被視為<value>- 包括空格和引號等字元。
- 第二種形式ENV <key>=<value> ...允許一次設定多個變數。請注意,第二種形式在文法中使用等號(=),而第一種形式則不使用等號。像命令列解析一樣,引號和反斜線可用於在值中包含空格。
例如:
ENV myName John DoeENV myDog Rex The DogENV myCat fluffy和ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy
上述兩種方法所產生的結果是一樣的,推薦使用第一種方式。
使用ENV來更新容器中的環境變數PATH,例如:ENV PATH /usr/local/nginx/bin:$PATH將確保CMD [“nginx”]工作正常。
ENV指令用於提供特定服務所需要的環境變數
ENV指令還可以用來設定常用的版本號碼,使其更方便維護,例子如下:
ENV PG_MAJOR 9.3ENV PG_VERSION 9.3.4RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
ADD or COPY
上述兩個指令的功能上是類似的,都是複製檔案到容器中。
COPY只支援講本地檔案複製到容器中
ADD不但支援講本地檔案複製到容器中,還支援本地提取檔案和遠程url下載
所以ADD最適合的恰當的使用就是講壓縮檔提取到容器中。如ADD rootfs.tar.xz /
COPY可以多次使用,例如下列例子可以使RUN快取無效判定的數量減少:
COPY requirements.txt /tmp/RUN pip install --requirement /tmp/requirements.txtCOPY . /tmp/
ADD不鼓勵使用遠程url並提取包。應該使用wget或者curl替代。可以在解壓完成之後刪除不需要的壓縮包。
以下做法是正確的範例:
RUN mkdir -p /usr/src/things \ && curl -SL http://example.com/big.tar.xz \ | tar -xJC /usr/src/things \ && make -C /usr/src/things all
對於不需要提取檔案的操作,我們應該均使用COPY來進行檔案複製操作。
ADD
該指令有兩種方式
- ADD <src>...<dest>
- ["<src>",... "<dest>"]
該ADD指令將複製新檔案,目錄或遠程檔案URL <src> ,並將其添加到路徑中映像的檔案系統<dest>。
<src>可以指定多個資源,但如果它們是檔案或目錄,則它們必須相對於正在構建的來源目錄(構建的上下文)。
每個<src>可能包含萬用字元,並使用Go的filepath.Match規則進行匹配 。例如
ADD hom* /mydir/ # adds all files starting with "hom"ADD hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"
<dest>是一個絕對路徑,或相對於一個路徑WORKDIR,到其中的源將在目標容器內進行複製
ADD test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/ADD test /absoluteDir/ # adds "test" to /absoluteDir/
當添加包含特殊字元(如[ 和])的檔案或目錄時,需要按照Golang規則轉義這些路徑,以防止它們被視為匹配模式。例如,要添加一個名為的檔案arr[0].txt,請使用以下命令:
ADD arr[[]0].txt /mydir/ # copy a file named "arr[0].txt" to /mydir/
COPY
同樣COPY也有兩種形式:
- COPY <src>... <dest>
- COPY ["<src>",... "<dest>"] (此表單是包含空格的路徑所必需的)
該COPY指令將複製新檔案或目錄<src ,並將其添加到該路徑上容器的檔案系統<dest>。
其他內容參見ADD部分
ENTRYPOINT
該指令也有兩種形式:
- ENTRYPOINT ["executable", "param1", "param2"] (首選)
- ENTRYPOINT command param1 param2 (外殼形式)
ENTRYPOINT允許你配置作為可執行檔啟動並執行容器
例如,以下將使用預設內容啟動nginx,在連接埠80上偵聽:
docker run -i -t --rm -p 80:80 nginx
執行from ENTRYPOINT例子
您可以使用exec形式ENTRYPOINT設定相當穩定的預設命令和參數,然後使用任何一種形式CMD來設定更有可能更改的其他預設值。
FROM ubuntuENTRYPOINT ["top", "-b"]CMD ["-c"]
運行容器時,您可以看到這top是唯一的過程:
$ docker run -it --rm --name test top -Htop - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05Threads: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 stKiB Mem: 2056668 total, 1616832 used, 439836 free, 99352 buffersKiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top
執行外殼形式的 ENTRYPOINT例子
您可以指定一個純粹的字串,ENTRYPOINT並在其中執行/bin/sh -c。此表單將使用shell處理來替換shell環境變數,並將忽略任何CMD或docker run命令列參數。為了確保能夠正確地docker stop發出任何長時間啟動並執行ENTRYPOINT可執行檔,您需要記住啟動它exec:
FROM ubuntuENTRYPOINT exec top -b
運行此鏡像時,您將看到單個PID 1過程:
$ docker run -it --rm --name test topMem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cachedCPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirqLoad average: 0.08 0.03 0.05 2/98 6 PID PPID USER STAT VSZ %VSZ %CPU COMMAND 1 0 root R 3164 0% 0% top -b
該指令最恰當的使用者是社會鏡像的主要命令,允許該鏡像像該命令一樣運行,然後使用CMD作為預設標誌
ENTRYPOINT ["s3cmd"]CMD ["--help"]
我們可以輸入以下命令來顯示命令的協助
$ docker run s3cmd
使用正確的參數執行該命令:
$ docker run s3cmd ls s3://mybucket
VOLUME
該指令用於公開暴露容器所建立的任何資料存放區地區,配置隱藏檔或者檔案夾。使用VOLUME指令配置任何可變的或是使用者可維護的部分。
VOLUME ["/data"]
該VOLUME指令將建立具有指定名稱的安裝點,並將其標記為從本機主機或其他容器儲存外部安裝的卷。該值可以是JSON數組,VOLUME ["/var/log/"]或具有多個參數的純字串,例如VOLUME /var/log或VOLUME /var/log /var/db
USER
該指令用於配置運行服務的使用者,一般使用者將普通使用者更改我root使用者,解決許可權不足的問題
USER <user>[:<group>] orUSER <UID>[:<GID>]
該USER指令設定使用者名稱(或UID)和可選的使用者組(或GID)在運行映像時使用RUN
注:當使用者沒有主組時,將使用該root組運行映像
WORKDIR
WORKDIR /path/to/workdir
該指令用於配置工作目錄,其參數應該使用絕對目錄。該命令其實也就是RUN cd … && do-something的變體。使其更清楚
該WORKDIR指令可以在一次使用多次Dockerfile。如果提供了相對路徑,它將相對於上一條WORKDIR指令的路徑 。例如:
WORKDIR /aWORKDIR bWORKDIR cRUN pwd
最終pwd命令的輸出Dockerfile就是這樣 /a/b/c。
ARG
ARG <name>[=<default value>]
該ARG指令定義了使用者可以docker build使用該--build-arg <varname>=<value> 標誌使用命令在構建時傳遞給構建器的變數。如果使用者指定了在Dockerfile中未定義的構建參數,則構建會輸出警告[Warning] One or more build-args [foo] were not consumed.
Docker檔案可以包括一個或多個ARG指令。例如,以下是一個有效Docker檔案
FROM busyboxARG user1ARG buildno...
ARG預設值
ARG指令可以可選地包括一個預設值
FROM busyboxARG user1=someuserARG buildno=1...
如果ARG指令具有預設值,並且如果在構建時沒有傳遞任何值,則構建器將使用預設值。
ONBUILD
該指令在當前Dockerfile構建完成後執行。ONBUILD在匯出FROM當前映像的任何子映像中執行。將該ONBUILD命令視為父母Dockerfile給予孩子的指示Dockerfile。
註:
- ddocker Version: 17.05.0-ce
- docker-machine version 0.12.2, build 9371605
- 上述環境在ubuntu16.04 lts中搭建測試成功
- 上述文字皆為個人看法,如有錯誤或建議請及時聯絡我