這些docker指令看起來很類似,容易讓剛開始使用docker的開發人員形成混淆。在這篇文章中,我將解釋CMD、RUN和ENTRYPOINT之間的區別。python
當Docker運行一個容器時,它會在其中運行一個鏡像。此鏡像一般經過執行Docker指令構建,該指令在現有鏡像或OS分佈之上添加層。OS分佈是初始圖像,每一個添加的層都會建立一個新鏡像。git
全部三個指令(RUN,CMD和ENTRYPOINT)均可以用shell形式或exec形式指定。讓咱們首先熟悉這些形式,由於形式一般比指令自己更容易引發混淆。docker
<instruction> <command>
複製代碼
Examples:shell
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
複製代碼
當以shell形式執行指令時,它會調用/bin/sh -c 並進行正常的shell處理。例如,Dockerfile中的如下代碼段bash
ENV name John Dow
ENTRYPOINT echo "Hello, $name"
複製代碼
當容器運行docker run -it 時將輸出ui
Hello, John Dow
複製代碼
注意:變量名稱將替換爲其值。spa
這是CMD和ENTRYPOINT指令的首選形式。命令行
<instruction> ["executable", "param1", "param2", ...]
複製代碼
Examples:版本控制
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
複製代碼
當以exec形式執行指令時,它直接調用可執行文件,而且不會發生shell處理。例如,Dockerfile中的如下代碼段code
ENV name John Dow
ENTRYPOINT ["/bin/echo", "Hello, $name"]
複製代碼
當容器運行docker run -it 時將輸出
Hello, $name
複製代碼
注意:變量名稱未替換。
若是你須要運行bash(或任何其餘解釋器如sh),使用exec形式與/bin/bash做爲可執行文件。在這種狀況下,將進行正常的shell處理。例如,Dockerfile中的如下代碼段
ENV name John Dow
ENTRYPOINT ["/bin/bash", "-c", "echo Hello, $name"]
複製代碼
當容器運行docker run -it 時將輸出
Hello, John Dow
複製代碼
RUN指令容許您安裝應用程序和程序包。它在當前鏡像之上執行任何命令,並經過提交結果來建立新層。一般,您會在Dockerfile中找到多個RUN指令。
RUN有兩種形式
RUN指令的一個很好的例子是安裝多個版本控制系統包:
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
複製代碼
注意:apt-get update和apt-get install在單個RUN指令中執行。這樣作是爲了確保安裝最新的軟件包。若是apt-get install位於分開的RUN指令中,那麼它將重用apt-get update添加的層,這多是好久之前建立的。建議多個指令用&&隔開在一個run中執行。
CMD指令容許您設置默認命令,該命令僅在您運行容器不指定命令時候運行。若是Docker容器使用命令運行,則將忽略默認命令。若是Dockerfile具備多個CMD指令,則忽略除最後一個CMD指令以外的全部指令。
CMD有三種形式:
第一和第三種形式在Shell和Exec部分進行了解釋。第二種exec形式和ENTRYPOINT指令一塊兒使用。若是容器在沒有命令行參數的狀況下運行,它將設置將在ENTRYPOINT參數以後添加的默認參數。參見ENTRYPOINT。
咱們來看看CMD指令是如何工做的。Dockerfile中的如下片斷
CMD echo "Hello world"
複製代碼
當容器運行docker run -it 時將輸出
Hello world
複製代碼
可是當容器使用命令運行時,例如, docker run -it /bin/bash,忽略CMD並改成運行bash指令:
root@7de4bed89922:/#
複製代碼
ENTRYPOINT指令容許您配置將做爲可執行文件運行的容器。它看起來相似於CMD,由於它還容許您使用參數指定命令。區別在於當Docker容器使用命令行參數運行時,ENTRYPOINT命令不會忽略參數。(有一種方法能夠忽略ENTTRYPOINT,但你不太可能這樣作。)
ENTRYPOINT 有兩種形式:
選擇ENTRYPOINT形式時要很是當心,由於不一樣形式執行結果會有很大差別。
ENTRYPOINT的Exec形式容許您設置命令和參數,而後使用任一形式的CMD來設置更可能更改的其餘參數。使用ENTRYPOINT參數,而能夠經過Docker容器運行時提供的命令行參數覆蓋CMD。例如,Dockerfile中的如下代碼段
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
複製代碼
當容器運行docker run -it 時將輸出
Hello world
複製代碼
可是當容器運行docker run -it John時,將輸出
Hello John
複製代碼
Shell形式的ENTRYPOINT忽略任何CMD或docker運行命令行參數。
使用RUN指令經過在初始鏡像上添加層來構建鏡像。
在構建可執行的Docker鏡像時,首選ENTRYPOINT的CMD形式。另外若是須要提供額外的默認參數,能夠在docker容器運行時從命令行覆蓋,請使用CMD。
若是須要提供默認命令和/或在docker容器運行時能夠從命令行覆蓋的參數,請選擇CMD。