Dockerfile中run、cmd和entrypoint之間的區別
- Docker
1.概述
在Dockerfile中,我們經常會遇到諸如run
, cmd,
或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
條目的情況下,僅考慮最後一個條目。
cmd
與entrypoint
之間的交互
我們已經使用cmd
和entrypoint
來定義運行容器時執行的命令。現在讓我們繼續前進,看看如何結合使用cmd
和entrypoint
。
一種這樣的用例是為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 run
或cmd
任何參數。
7.結論
在本文中,我們已經看到了Docker指令之間的差異和相似之處: run
, cmd,
和entrypoint
。我們已經觀察到它們在什麼時候被調用。此外,我們還研究了它們的用途以及它們如何協同工作。