如果您曾經需要在啟動時在 Docker 容器中運行一個或兩個命令,這個教程適合您。 使用 Dockerfile 的 ENTRYPOINT
和 CMD
指令,您可以運行任意多的啟動命令。
在本教程中,您將學習如何使用 ENTRYPOINT
和 CMD
指令在 Dockerfile 中運行啟動命令,並了解它們之間的區別。
先決條件
由於本教程將進行實際演示,請確保您已經準備好以下內容:
- A Windows 10 PC – Windows 10 v10.0.19042 was used in this tutorial.
- Docker Desktop – 本教程使用 Docker Desktop v3.3.1。
創建 Dockerfile
在您運行 Docker 容器啟動命令之前,您必須首先創建一個 Dockerfile。 Dockerfile 是一個文本文件,包含一系列命令來構建容器、Docker 鏡像,並確定如何創建 Docker 鏡像。
1. 首先,以管理員身份打開 PowerShell。
2. 創建一個新的文件夾來存儲Dockerfile和所有本教程將使用的相關文件,並切換到該目錄。本教程使用~/docker。
3. 現在,使用以下命令創建一個名為Dockerfile的空白文本文件。
或者,如果您使用的是Linux或Mac OS,可以使用以下命令創建一個Dockerfile。
4. 最後,將以下內容添加到Dockerfile中。
您現在已經創建了一個即將成為Dockerfile的文件!
構建Docker映像
現在您已經創建了Dockerfile,您必須構建一個Docker映像以執行Dockerfile ENTRYPOINT和CMD指令中編寫的命令。一種構建映像的方法是使用build
命令。
在~/docker目錄中,運行以下命令。下面的命令通過指定當前工作目錄(.
)在~/docker中的Dockerfile中創建一個名為demo(-t demo
)的Docker映像。

運行Docker容器
在您構建了Docker映像之後,您將需要一個容器來運行Docker映像,該容器將執行來自Dockerfile ENTRYPOINT和CMD指令的命令。
運行Docker容器,調用run
命令以在Docker映像(demo
)上創建可寫容器層。以下示例使用-it
參數與容器進行互動,以查看樣本輸出。

Exec vs. Shell Form
當您開始使用Dockerfile並找出如何運行啟動命令時,可能會遇到兩種不同的定義這些命令的方法。每種方法都會調用命令,但做法略有不同。
當Docker執行命令時,可以直接調用exec
或通過容器的shell(在Linux上為/bin/sh -c
,在Windows上為cmd /S /C
)調用shell
。
您會注意到通過exec
執行的命令具有一條指令,後面是要調用的可執行文件,然後是一個或多個命令行參數,如下所示。
相反,在shell
形式中編寫命令不需要將命令包裝在方括號中,如下所示。
如果您未為
CMD
指定參數,Docker將始終以exec形式執行命令,例如CMD <command>
。
如果您剛開始,區分這兩種命令調用可能不太重要,但隨著您變得更加高級,您很快就會看到每種方法的優勢和劣勢。
運行啟動命令
讓我們現在深入研究這個教程,並透過幾個範例來了解在 Dockerfile 的 ENTRYPOINT
和 CMD 指令中運行啟動命令的方式。
1. 在你偏好的文本編輯器中打開之前創建的 Dockerfile。
2. 將示例 Dockerfile 內容複製並粘貼到你的 Dockerfile 中,如下所示,然後保存。
這個 Dockerfile 使用 ubuntu:20.04
作為基礎映像來創建一個層。 然後它告訴 Docker 使用 exec
和 shell
形式,對 Dockerfile 的 CMD
和 ENTRYPOINT
指令分別傳遞 Hello world
參數。
3. 在 ~/docker 目錄中,運行 docker build
命令來構建新的映像,並將其命名為 demo
。 以下命令 標記 了映像為 demo
,並在當前工作目錄(.
)中尋找 Dockerfile。

4. 現在,運行一個容器使用這個映像,然後運行一個基於之前創建的 Docker 映像的 Docker 容器。 現在你會看到容器返回了從 Dockerfile 中提供的 CMD
指令中得到的 Hello world
。

在 Dockerfile 中使用變量
有时您可能事先不知道要传递给命令的确切命令行参数。您需要在运行时暴露给命令的参数。与静态分配命令参数不同,您可以使用变量捕获并传递这些参数给命令。
您只能在
shell
形式中使用Dockerfile变量。Docker不支持通过exec
形式调用的命令中的变量。
再次在您喜欢的文本编辑器中打开Dockerfile,将其中的所有内容替换为以下一系列命令并保存。
这次您会注意到,Dockerfile使用环境变量,并使用ENV
显示。在下面的示例中,Dockerfile定义了一个名为name
的环境变量,其值为friend
。创建后,可以通过$name
引用此环境变量。
当Docker基于此Dockerfile运行容器时,它将调用echo
命令并传递参数Welcome, friend
。
现在,创建Docker镜像并再次运行容器,可选择提供shellform
的标签名称。您会注意到Docker调用了echo
命令并返回了预期的输出。

结合Dockerfile的ENTRYPOINT和CMD指令
多數情況下,您將在CMD或ENTRYPOINT指令中調用啟動命令。畢竟,您可以使用每種方法調用許多命令。但是,您還可以通過這兩種指令“添加到它”來調用單個命令。
建立在前面的示例之上,也許您有一個Dockerfile,看起來像下面的示例一樣。按原樣,如果您創建一個映像並運行該映像的容器,Docker將調用echo
命令並返回Hello
。
也許您有另一個參數,您想傳遞給echo
命令,但不是立即。也許您想在Dockerfile中進一步執行此操作。通過調用CMD
指令而不使用命令,您可以這樣做。
當您通過
ENTRYPOINT
指令指定要運行的命令,然後是CMD
指令時,Docker自動假設傳遞給CMD
的值是一個參數,而不是一個命令。
現在,添加一個不帶命令的CMD
指令引用,只是一個名為world
的參數,如下所示。
由於其通過逗號分開逐個指定值的“數組樣式”行為,應始終以執行形式編寫組合指令,如所示。
構建映像並從映像運行容器後,您會看到Docker只返回一個含義,而不是兩行輸出(Hello
和world
),這意味著只有一個echo
命令調用。

結論
你現在應該對通過Dockerfile指令CMD
和ENTRYPOINT
運行Docker容器啟動命令有了良好的理解。每個指令都略有不同,但實現了相同的任務,甚至可以一起使用。
你能想到一種情況,你更喜歡使用CMD
而不是ENTRYPOINT
來運行啟動命令嗎?