GitHub Page:https://blog.cloudli.top/posts/Dockerfile-指令詳解/java
FROM
命令指定基礎鏡像。在構建鏡像時,基礎鏡像必須指定,所以在 Dockerfile
中 FROM
是必備指令且必須是第一條指令。node
在 Docker Hub 上有不少經常使用的高質量官方鏡像,有一些是應用和服務類的鏡像,如 nginx、mysql、redis 等;也有一些是用於運行各類語言應用的鏡像,如 openjdk、python、node 等。python
若是找不到應用的官方鏡像,能夠基於操做系統鏡像構建一個。Docker Hub 上提供了不少操做系統鏡像。mysql
FROM ubuntu ...
RUN
指令是用來執行命令行命令的。RUN
指令的格式有兩種:nginx
shell 格式:RUN <命令>
,就像直接在命令行中輸入命令同樣。redis
RUN java -jar app.jar
exec 格式:RUN ["可執行文件", "參數1", "參數2"]
。sql
RUN ["java", "-jar", "app.jar"]
在 Dockerfile
中,每個指令都會在鏡像上創建一層,因此對於多個命令行,不要寫多個 RUN
指令。docker
對於多個命令,可使用這樣的寫法:shell
FROM ubuntu RUN apt-get update \ && apt-get install -y redis
對於多個命令,使用 &&
鏈接起來,只用一個 RUN
指令執行,這樣就只會構建一層。數據庫
COPY
指令用來將宿主的文件目錄複製到鏡像中。有兩種格式:
COPY [--chown=<user>:<group>] <源路徑>... <目標路徑>
COPY app.jar /usr/src/
COPY [--chown=<user>:<group>] ["源路徑1", ... "目標路徑"]
COPY ["app.jar", "config.yml", "/usr/src"]
對於多個路徑參數,最後一個爲目標路徑,其餘都是源路徑。目標路徑
能夠是絕對路徑,也能夠是相對於工做目錄的路徑(工做目錄能夠用 WORKDIR
來指定)。目標路徑若是不存在,在複製文件前會先建立。
CMD
是容器啓動命令,它指定了容器啓動後要執行的程序。與 RUN
指令類似有兩種形式:
shell 格式:CMD <命令>
CMD echo 'Hello, world!''
exec 格式:CMD ["可執行文件", "參數1", "參數2", ...]
CMD [ "sh", "-c", "echo 'Hello, world!'" ]
還有一種參數列表格式:CMD ["參數1", "參數2", ...]
。在指定了 ENTRYPOINT
指令後,能夠用 CMD
指定參數。
在使用 CMD
時,程序必須之前臺運行,Docker 不是虛擬機,容器沒有後臺服務的概念。若是使用 CMD
運行一個後臺程序,那麼容器在命令執行完就會退出。
CMD java -jar app.jar &
以上命令讓 app.jar 在後臺運行,容器啓動後就會馬上退出。Docker 容器與守護線程很類似,當全部前臺程序退出後,容器就會退出。
CMD
指定的命令能夠在運行時替換,跟在鏡像名稱後面的參數將替換鏡像中的 CMD
。
docker run app echo $HOME
以上命令運行容器時使用 echo $HOME
替換掉鏡像中的啓動命令。
ENTRYPOINT
的格式與 CMD
同樣有兩種格式。
它和 CMD
同樣都是指定容器啓動的程序和參數,但稍有區別。當指定了 ENTRYPOINT
後,CMD
的內容將做爲參數加到 ENTRYPOINT
後面。
也就是變成了:
<ENTRYPOINT> "<CMD>"
ENTRYPOINT
可讓鏡像像命令同樣使用,當僅僅使用 CMD
時,run
命令中鏡像名後面的參數會替換 CMD
的內容。使用 ENTRYPOINT
後,這些參數將附加到原來命令的後面。
FROM alpine ENTRYPOINT [ "ls" ]
使用以上 Dockerfile
構建的鏡像運行容器:
docker run app -al
-al
參數將附加到 ENTRYPOINT
指定的命令後面,當容器啓動時執行的是 ls -al
。
ENV
指令用來設置環境變量,格式有兩種:
ENV <key> <value
ENV <key1>=<value1> <key2>=<value2>
環境變量在後面的其它指令中能夠經過 $key
來使用:
FROM ubuntu ENV VERSION="8-jre" RUN apt-get update \ && apt-get install -y openjdk-$VERSION ...
ARG
指令指定構建參數,與 ENV
效果同樣,都是設置環境變量。不一樣的是,ARG
設置的構建參數,在容器運行時不存在。
格式:ARG <key>[=<默認值>]
,能夠指定默認值,也能夠不指定。
FROM alpine ARG NAME="Hello, Docker!" RUN echo $NAME CMD echo $NAME
對於以上 Dockerfile
,在構建時能夠看到輸出,可是在運行容器時沒有輸出。
ARG
設置的參數能夠在構建命令中指定:docker build --build-arg <key>=<value>
。
VOLUME
指令用來定義匿名卷。
VOLUME <路徑>
VOLUME ["路徑1", "路徑2", ...]
對於數據庫類須要保持數據的應用,其文件應該保存於卷(volume)中,在 Dockerfile
中,能夠事先將指定的目錄掛載爲匿名卷。
VOLUME /data
這裏 /data
目錄在容器運行時自動掛載爲匿名卷,任何寫入 /data
中的數據都不會記錄到容器的存儲層。在運行時能夠覆蓋這個掛載設置:
docker run -v dbdir:/data
以上命令將 dbdir
目錄掛載到了 /data
,替換了 Dockerfile
中的掛載配置。
EXPOSE
指令指定容器運行時暴露的端口。格式:EXPOSE <端口1> [<端口2> ...]
。
FROM ubuntu EXPOSE 8080 RUN apt-get update \ && apt-get install -y tomcat8 ...
以上 Dockerfile
安裝了 tomcat 應用,在運行容器時會暴露 8080 端口。
EXPOSE
只是指定了容器暴露的端口,並不會在宿主機進行端口映射。在使用 docker run -P
時,會自動隨機映射 EXPOSE
指定的端口,也可使用 -p
指定端口:docker run -p <宿主端口>:<容器端口>
。
WORKDIR
指令指定工做目錄,即指定當前目錄,相似於 cd
命令,之後各層的當前目錄都是 WORKDIR
指定的目錄。若是目錄不存在,會自動建立。格式:WORKDIR <目錄路徑>
。
不能把 Dockerfile
當成 Shell 腳原本寫:
RUN cd /src/app RUN java -jar app.jar
以上操做中第二行的工做目錄並非 /src/app
,兩個指令不在同一層,第一個 RUN
指令的 cd
操做和第二個沒有任何關係。所以要切換目錄,應該使用 WORKDIR
來指定。
USER
指令指定當前用戶。與 WORKDIR
類似,會影響之後的層。USER
改變執行 RUN
、CMD
和 ENTRYPOINT
的用戶。格式:USER <用戶名>[:<用戶組>]
。
USER
指定的用戶和組必須是事先建立好的,不然沒法切換。
# 添加用戶 RUN groupadd -r redis \ && useradd -r -g redis redis USER redis ENTRYPOINT ["reids-server"]
ONBUILD
指令後面跟的是其它指令,它在當前鏡像構建時不會被執行,只有以當前鏡像爲基礎鏡像去構建下一級鏡像時纔會被執行。格式:ONBUILD <其它指令>
。
FROM openjdk:8-jre-alpine WORKDIR /app ONBUILD COPY ./app.jar /app ...
這個 Dockerfile
在構建時不會執行 ONBUILD
。
FROM my-jre ...
假設以前構建的鏡像名是 my-jre,以上 Dockerfile
構建鏡像時,原來的 ONBUILD
將執行。