Dockerfile 指令詳解
在上一節的 Dockerfile 例子中,我們用到了幾個指令,比如:FROM, MAINTAINER,RUN,EXPOSE等等,Dockerfile 構建映象需要用到的指令當然不止這些,下面是我們將介紹常用的構建指令 。
1. FROM:指明當前的映象基於哪個映象構建
用法:
FROM <基礎映象:版本>
示例:
FROM alpine:latest
寫上這一行指令後,我們的 Dockerfile 就可以構建映象了,構建出的映象就是未做任何修改、沒有執行任何命令的 alpine:latest
。
在 Docker 官方倉庫裡有很多高質量的服務映象如 redis、mongo、mysql、httpd、php、tomcat 等;也有一些方便開發、構建、執行各種語言應用的映象,如 node、openjdk、python、ruby、golang 等。我們可以在其中尋找一個最符合我們最終目標的映象為基礎映象進行定製。如果沒有找到對應服務的映象,官方映象中還提供了一些更為基礎的作業系統映象,如 ubuntu、debian、centos、fedora、alpine 等,這些作業系統的軟體庫為我們提供了更廣闊的擴充套件空間。儘可能使用當前官方倉庫作為構建映象的基礎。
2. LABEL: 標記映象資訊
給映象新增標籤來標記映象資訊,每個標籤一行。
用法:
LABEL <標籤>=<描述>
示例:
LABEL MYLABEL="First Test"
3. MAINTAINER:指定映象的作者資訊,包含映象的所有者和聯絡人資訊
用法:
MAINTAINER <NAME>
示例:
MAINTAINER [email protected]
這是一種語義化的表達方式,也可以用LABEL來標記
LABEL maintainer="[email protected]"
4. RUN : 執行命令
用法:
RUN <命令>
示例:
RUN echo 'text' > test.txt
為了保持 Dockerfile 檔案的可讀性,以及可維護性,建議將長的或複雜的RUN
指令用反斜槓\
分割成多行。
例如:
RUN apt update && apt install -y \
vim \
emacs
這裡需要注意一個關於軟體源更新安裝軟體的問題。
如果我們需要更新軟體源並安裝軟體源中的軟體vim,在Linux環境中我們一般會執行這個的命令:
apt update
apt install -y vim
如果需要在映象中安裝軟體,我們會想當然地在 Dockerfile 寫成這樣
RUN apt update
RUN apt install -y vim
Dockerfile 構建一次之後,apt update
構建的映象層就會快取到本地,無論後面這個 Dockerfile 如何更新 apt install
的內容,apt update
映象快取也不會更新,這會導致安裝的始終是第一次 Dockerfile構建時獲取的軟體源版本,除非你手動刪除這些快取映象層。
解決的方法很簡單,用 RUN apt-get update && apt-get install -y
可以確保 Dockerfiles
每次安裝的都是包的最新的版本。
5. CMD:指定容器的預設執行的命令。
建議用法:
CMD ["可執行命令", "引數1", "引數2"...]
示例:
CMD ["echo" "hello"]
docker run 沒有指定其他命令時,CMD 指令會在容器執行。Dockerfile 中 CMD 只能有一個,如果寫了多個 CMD,則以最後一個為準。
Tips:ENTRYPOINT 與 CMD 類似,但不會被
docker run
指定的命令覆蓋。
6. EXPOSE:指定容器將要監聽的埠
用法:
EXPOSE 埠號
示例:
EXPOSE 8080
啟動容器時,如果我們使用自動對映 -P
或 --net=host
宿主機網路模式,容器中 EXPOSE
標記暴露的埠與宿主機網路會自動建立關聯。
如果沒有指定 EXPOSE
,使用 -p
手動指定埠對映引數也可以訪問到容器內提供服務的埠。
EXPOSE
顯式地標明映象開放埠,一定程度上提供了操作的便利,也提高了 Dockerfile 的可讀性和可維護性。
7. ENV:定義環境變數
用法:
ENV 環境變數名 環境變數值
示例:
ENV PATH /usr/local/nginx/bin:$PATH
Tips:
- 通過 ENV 定義的環境變數,可以被後面的所有指令中使用,但是不能被 CMD 指令使用。
- 通過 ENV 定義的環境變數,會永久的儲存到該映象建立的任何容器中,我們可以在 docker run 命令中通過 -e 標記來傳遞環境變數,啟動的容器將會使用我們指定的變數值。
- ARG 指令與 ENV 作用基本一致,區別在於它僅在構建過程中使用,不會保留到容器中。
8. COPY: 將宿主機檔案拷貝到映象中
用法:
COPY <宿主機檔案路徑> <映象檔案路徑>
示例:
COPY app.py /web/
除了指定完整的檔名外,COPY 命令還支援 Go 風格的萬用字元,比如:
# * 是任意字元的佔位符,匹配檔案 test11 test22
COPY test* /tmp
# ? 是單個字元的佔位符,匹配檔案 test1.txt test2.txt
COPY test?.txt /tmp
對於目錄而言,COPY 只複製目錄中的內容而不包含目錄自身。 如下目錄結構:
testdir/
├── file1
└── file2
COPY testdir /tmp
映象的 /tmp 目錄下,將得到這樣的檔案結構:
tmp/
├── file1
└── file2
如果要帶目錄拷貝到映象中,需要使用:
COPY testdir /tmp/testdir
ADD
和COPY
用法類似,一般優先使用 COPY。COPY 只支援簡單將本地檔案拷貝到容器中,而 ADD 還有從壓縮包中提取檔案的功能,如:
# 宿主機壓縮包test.tar 解壓到 映象/tmp中
ADD test.tar /tmp
9. VOLUME:指定目錄為資料卷儲存方式
為了防止執行時使用者忘記將需要儲存資料的目錄掛載為卷,我們可以事先指定某些目錄掛載為匿名卷,這樣在執行時如果使用者不指定掛載,其應用也不會向容器儲存層寫入大量資料。
用法:
VOLUME ["<路徑1>", "<路徑2>"...]
示例:
VOLUME ["/data"]
這裡的 /data
目錄就會在執行時自動掛載為匿名卷,容器執行時使用 -v mydata:/data
可以覆蓋這個掛載設定。
10. USER:指定執行容器時的使用者名稱或 UID
用法:
USER <user>[:<group>]
或
USER <UID>[:<GID>]
示例:
USER www
當容器中執行的服務不需要管理員許可權時,可以先建立一個特定的使用者和使用者組,為它分配必要的許可權,然後通過該命令,使用 USER 切換到這個使用者。
Tips:
- 使用USER指定使用者時,可以使用使用者名稱、UID或GID,或是兩者的組合。
- 使用USER指定使用者後,Dockerfile中其後的命令RUN、CMD、ENTRYPOINT都將使用該使用者。
我們可以在docker run
中使用-u
引數指定使用者執行命令,來替代預設設定,如果為了精確控制使用者的id,也可以傳入uid。
docker run -i -t -u 1001 busybox sh
11. WORKDIR: 切換到映象中的指定路徑
在WORKDIR
中需要使用絕對路徑,如果映象中對應的路徑不存在,會自動建立此目錄。
我們使用 WORKDIR 來替代 RUN cd <path> && <do something>
的這類切換目錄進行操作的指令。
WORKDIR指令對ADD COPY等指令也生效,如下操作會將宿主機的test.txt 檔案複製到 映象的/tmp/test.txt。
WORKDIR /tmp
COPY test.txt .
12. ONBUILD:引用後構建指令
用法:
ONBUILD <其他指令>
示例:
ONBUILD COPY . /tmp/
ONBUILD
是一個特殊的指令,它後面跟的是其它指令,比如 RUN, COPY 等。
FROM alpine:latest
ONBUILD RUN mkdir /app
ONBUILD COPY . /app/
CMD [ "echo", "hello" ]
使用上面 Dockerfile 在構建基礎映象的時候,這兩行 ONBUILD 並不會被執行。它的效果等價於:
FROM alpine:latest
CMD [ "echo", "hello" ]
構建出來的映象作為基礎映象,在其他 Dockerfile 的 FROM
指令中被引用,去構建新映象的時候,ONBUILD 後的指令會執行。
13. 小結
本節介紹了我們使用 Dockerfile 構建映象的過程中經常會用到的指令,這些指令大多簡單易懂的。但本節中也提到,其中有些指令的用法比較特殊,在某些看似“理所當然”的使用方法下,可能會出現"bug",請大家一定要留意。後面也有實戰章節,幫助大家加深理解。