1. 程式人生 > 其它 >Dockerfile中RUN/CMD/ENTRYPOINT命令區別

Dockerfile中RUN/CMD/ENTRYPOINT命令區別

  Dockerfile中RUN,CMD和ENTRYPOINT都能夠用於執行命令,下面是三者的主要用途:

  • RUN命令:執行命令並建立新的映象層,通常用於安裝軟體包
  • CMD命令:設定容器啟動後預設執行的命令及其引數,但CMD設定的命令能夠被docker run命令後面的命令列引數替換
  • ENTRYPOINT:配置容器啟動時的執行命令(不會被忽略,一定會被執行,即使執行 docker run時指定了其他命令)

一、Shell格式和Exec格式執行命令

  我們可用兩種方式指定 RUN、CMD 和 ENTRYPOINT 要執行的命令:Shell 格式和 Exec 格式。

1、Shell格式:<instruction> <command>。例如:

RUN apt-get install python3  
CMD echo "Hello world"  
ENTRYPOINT echo "Hello world"  

  當指令執行時,shell 格式底層會呼叫 /bin/sh -c <command>

// 例如下面的 Dockerfile 片段:
ENV name Cloud Man  
ENTRYPOINT echo "Hello, $name" 

// 執行 docker run <image> 將輸出:
Hello, Cloud Man 

  注意環境變數name已經被值Cloud Man替換

2、Exec格式:<instruction> ["executable", "param1", "param2", ...]。例如:

RUN ["apt-get", "install", "python3"]  
CMD ["/bin/echo", "Hello world"]  
ENTRYPOINT ["/bin/echo", "Hello world"] 

  當指令執行時,會直接呼叫 <command>,不會被 shell 解析

// 例如下面的 Dockerfile 片段:
ENV name Cloud Man  
ENTRYPOINT ["/bin/echo", "Hello, $name"]

// 執行容器將輸出:
Hello, $name

// 注意環境變數“name”沒有被替換。如果希望使用環境變數,照如下修改
ENV name Cloud Man ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"] // 執行容器將輸出: Hello, Cloud Man

  CMD 和 ENTRYPOINT 推薦使用 Exec 格式,因為指令可讀性更強,更容易理解。RUN 則兩種格式都可以。

二、Run命令

  RUN 指令通常用於安裝應用和軟體包。RUN 在當前映象的頂部執行命令,並通過建立新的映象層。Dockerfile 中常常包含多個 RUN 指令。下面是一個例子:

RUN apt-get update && apt-get install -y \  
 bzr \
 cvs \
 git
  apt-get update 和 apt-get install 被放在一個 RUN 指令中執行,這樣能夠保證每次安裝的是最新的包。如果 apt-get install 在單獨的 RUN 中執行,則會使用 apt-get update 建立的映象層,而這一層可能是很久以前快取的。

三、CMD命令

  CMD 指令允許使用者指定容器的預設執行的命令。此命令會在容器啟動且 docker run 沒有指定其他命令時執行。下面是一個例子:

CMD echo "Hello world"
// 執行容器 docker run -it [image] 將輸出:
Hello world

// 但當後面加上一個命令,比如 docker run -it [image] /bin/bash,CMD 會被忽略掉,命令 bash 將被執行:
root@10a32dc7d3d3:/#
  此命令會在容器啟動且 docker run 沒有指定其他命令時執行。

1、如果 docker run 指定了其他命令,CMD 指定的預設命令將被忽略。

2、如果 Dockerfile 中有多個 CMD 指令,只有最後一個 CMD 有效。

四、ENTRYPOINT命令

  ENTRYPOINT 的 Exec 格式用於設定容器啟動時要執行的命令及其引數,同時可通過CMD命令或者命令列引數提供額外的引數。

  ENTRYPOINT 中的引數始終會被使用,這是與CMD命令不同的一點。下面是一個例子:

ENTRYPOINT ["/bin/echo", "Hello"]  
// 當容器通過 docker run -it [image] 啟動時,輸出為:
Hello

// 而如果通過 docker run -it [image] CloudMan 啟動,則輸出為:
Hello CloudMan
// 將Dockerfile修改為:
ENTRYPOINT ["/bin/echo", "Hello"]  
CMD ["world"]

// 當容器通過 docker run -it [image] 啟動時,輸出為:
Hello world

// 而如果通過 docker run -it [image] CloudMan 啟動,輸出依舊為:
Hello CloudMan

  ENTRYPOINT 中的引數始終會被使用,而 CMD 的額外引數可以在容器啟動時動態替換掉。