Dockerfile中run、cmd和entrypoint之間的區別

1.概述

在Dockerfile中,我們經常會遇到諸如runcmd,entrypoint類的指令。乍一看,它們全部用於指定和運行命令。但是它們之間有什麼區別?它們如何相互影響?

在本教程中,我們將回答這些問題。我們將介紹這些說明中的每一個做什麼以及它們如何工作。我們還將研究它們在構建映像和運行Docker容器中所扮演的角色。

2.設定

首先,讓我們創建一個腳本log-event.sh.它只是在文件中添加一行,然後打印它:

#!/bin/sh



 echo `date` [email protected] >> log.txt;

 cat log.txt;

現在,讓我們創建一個簡單的Dockerfile:

FROM alpine

 ADD log-event.sh /

在不同情況下,通過將行附加到log.txt

3. run命令

當我們構建映像時,將run這意味著傳遞給run的命令將在新層的當前圖像之上執行。然後將結果提交到圖像。讓我們看看它的實際效果。

首先,我們將run指令添加到我們的Dockerfile中:

FROM alpine

 ADD log-event.sh /

 RUN ["/log-event.sh", "image created"]

其次,讓我們用以下內容建立我們的形象:

docker build -t myimage .

現在,我們希望有一個包含log.txt文件image created行。讓我們通過基於圖像運行一個容器來檢查這一點:

docker run myimage cat log.txt

當列出文件的內容時,我們將看到類似以下的輸出:

Fri Sep 18 20:31:12 UTC 2020 image created

如果我們多次運行容器,我們將看到日誌文件中的日期沒有更改。這是有道理的,因為**run步驟是在映像生成時執行的**,而不是在容器運行時執行的。

現在,讓我們再次建立我們的鏡像。我們注意到日誌中的創建時間沒有改變。發生這種情況是因為,如果Dockerfile不變,則Docker會緩存run指令的結果。如果要使緩存無效,則需要將–no-cache選項傳遞給build命令。

4. cmd命令

使用**cmd指令,我們可以指定在容器啟動時執行的默認命令。**讓我們將一個cmd條目添加到我們的Dockerfile中,並查看其工作方式:

...

 RUN ["/log-event.sh", "image created"]

 CMD ["/log-event.sh", "container started"]

構建完映像後,現在讓我們運行它並檢查輸出:

$ docker run myimage

 Fri Sep 18 18:27:49 UTC 2020 image created

 Fri Sep 18 18:34:06 UTC 2020 container started

如果我們多次運行,我們將看到image created的圖像條目保持不變。但是container started每次運行都會啟動條目更新。這顯示了每次容器啟動時cmd

注意,這次我們使用了稍微不同的docker run命令來啟動我們的容器。讓我們看看如果運行與之前相同的命令會發生什麼:

$ docker run myimage cat log.txt

 Fri Sep 18 18:27:49 UTC 2020 image created

這次將忽略Dockerfile中指定cmd那是因為我們為docker run命令指定了參數。

現在讓我們繼續前進,看看如果Dockerfile中cmd讓我們添加一個新條目,該條目將顯示另一條消息:

...

 RUN ["/log-event.sh", "image created"]

 CMD ["/log-event.sh", "container started"]

 CMD ["/log-event.sh", "container running"]

構建映像並再次運行容器後,我們將找到以下輸出:

$ docker run myimage

 Fri Sep 18 18:49:44 UTC 2020 image created

 Fri Sep 18 18:49:58 UTC 2020 container running

如我們所見, container started項不存在,只有container running .這是因為,如果指定了多個cmd,則僅調用最後一個cmd。

5. entrypoint命令

正如我們在上面看到的,如果在啟動容器時傳遞任何參數,則將忽略cmd如果我們想要更大的靈活性怎麼辦?假設我們要自定義附加文本並將其作為參數傳遞給docker run命令。為此,讓我們使用entrypoint.我們將指定在容器啟動時運行的默認命令。而且,我們現在能夠提供額外的參數。

讓我們用entrypoint: cmd

...

 RUN ["/log-event.sh", "image created"]

 ENTRYPOINT ["/log-event.sh"]

現在,通過提供一個自定義文本條目來運行容器:

$ docker run myimage container running now

 Fri Sep 18 20:57:20 UTC 2020 image created

 Fri Sep 18 20:59:51 UTC 2020 container running now

我們可以看到**entrypoint行為與****cmd** .另外,它允許我們自定義在啟動時執行的命令。

cmd一樣,在有多個entrypoint條目的情況下,僅考慮最後一個條目。

cmdentrypoint之間的交互

我們已經使用cmdentrypoint來定義運行容器時執行的命令。現在讓我們繼續前進,看看如何結合使用cmdentrypoint

一種這樣的用例是為entrypoint.讓我們在Dockerfile中的入口點之後cmd entrypoint

...

 RUN ["/log-event.sh", "image created"]

 ENTRYPOINT ["/log-event.sh"]

 CMD ["container started"]

現在,讓我們在不提供任何參數的情況下運行容器,並使用cmd指定的默認值:

$ docker run myimage

 Fri Sep 18 21:26:12 UTC 2020 image created

 Fri Sep 18 21:26:18 UTC 2020 container started

如果選擇這樣做,我們也可以覆蓋它們:

$ docker run myimage custom event

 Fri Sep 18 21:26:12 UTC 2020 image created

 Fri Sep 18 21:27:25 UTC 2020 custom event

需要注意的是entrypoint以外殼形式使用時的不同行為。讓我們更新Dockerfile中entrypoint

...

 RUN ["/log-event.sh", "image created"]

 ENTRYPOINT /log-event.sh

 CMD ["container started"]

在這種情況下,運行容器時,我們將看到Docker如何忽略傳遞給docker runcmd任何參數。

7.結論

在本文中,我們已經看到了Docker指令之間的差異和相似之處: runcmd,entrypoint 。我們已經觀察到它們在什麼時候被調用。此外,我們還研究了它們的用途以及它們如何協同工作。