dockerfile中CMD和ENTRYPOINT指令使用及說明
1、exec和shell兩種風(fēng)格
無論是CMD還是ENTRYPOINT指令,都支持exec和shell兩種風(fēng)格:
語法 | 示例 | 解析方式 | |
Exec 形式 | JSON 數(shù)組 | CMD ["sleep", "60"] | 直接執(zhí)行二進(jìn)制程序,docker實(shí)際運(yùn)行execve("sleep", ["sleep", "60"]) |
Shell 形式 | 字符串 | CMD sleep 60 | 通過 shell 執(zhí)行命令,相當(dāng)于 /bin/sh -c "sleep 60" |
說明:execve時Linux內(nèi)核的一個系統(tǒng)調(diào)用,作用事用于一個新程序替換當(dāng)前進(jìn)程(把新程序加載到當(dāng)前進(jìn)程的內(nèi)存空間,當(dāng)前的進(jìn)程會被丟棄)
注意:生產(chǎn)環(huán)境中推薦使用Exec形式,更安全、可控。
1)shell風(fēng)格和exec風(fēng)格解析方式:
shell風(fēng)格是通過shell執(zhí)行的命令,
CMD sleep 60 #Docker實(shí)際運(yùn)行時會變成 /bin/sh -c "sleep 60"
也就是說,它先啟動一個 Shell 進(jìn)程(/bin/sh),再讓這個 shell 去執(zhí)行 sleep 60。所以:
• 容器的 PID 1 進(jìn)程 實(shí)際是 /bin/sh,不是 sleep
• Shell 風(fēng)格中,可以解釋變量、重定向符、管道符等(比如 CMD echo $PATH > /tmp/p)
而對于exec風(fēng)格是直接執(zhí)行命令,
CMD ["sleep", "60"]
#DOcker不會提懂/bin/sh,而是直接執(zhí)行命令
execve("sleep", ["sleep", "60"])所以,
- 容器內(nèi)的 PID 1 就是 sleep 進(jìn)程;
- 命令參數(shù)直接傳遞給進(jìn)程;
- 不支持 shell 特性(如 $VAR、|、> 等);
- 啟動更快、行為更一致。
2)環(huán)境變量展開:(CDM和ENTRYPOINT是一樣的)
FROM busybox ENV NAME=KnowLiu # shell 形式 CMD echo "Hello $NAME" #運(yùn)行 docker run myimage # 輸出:Hello KnowLiu #------------- FROM busybox ENV NAME=KnowLiu CMD ["echo", "Hello $NAME"] #運(yùn)行 docker run myimage # 輸出:Hello $NAME
結(jié)論:
- Shell 形式支持變量展開;
- Exec 形式不支持(因?yàn)闆]經(jīng)過 shell)。
3)信號轉(zhuǎn)發(fā):(CDM和ENTRYPOINT是一樣的)
FROM busybox CMD ["sleep", "1000"] #運(yùn)行,然后停止容器會立即停止 docker run --name test mini docker stop test #----------- FROM busybox CMD sleep 1000 #運(yùn)行,然后停止容器,容器停止會超時 docker run --name test mini docker stop test
說明:由于/bin/sh是1號進(jìn)程,SIGTERM 發(fā)給 shell,而 shell 默認(rèn)不會轉(zhuǎn)發(fā)信號,導(dǎo)致 sleep 不退出 → 容器停止會超時。
4)參數(shù)傳遞:
#docker file FROM alpine:3.20 ENTRYPOINT ["echo", "hahaha!"] #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hahaha! docker run my-test hi 輸出 hahaha! hi docker run my-test echo hi 輸出 hahaha! echo hi #------------------------ #docker file FROM alpine:3.20 ENTRYPOINT echo hahaha #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hahaha docker run my-test hi 輸出 hahaha docker run my-test echo hi 輸出 hahaha
可以看到,ENTRYPOINT指令的exec風(fēng)格支持傳遞參數(shù),shell風(fēng)格不支持!關(guān)于命令覆蓋,見下面!
5)總結(jié)二者的區(qū)別:
特性 | Exec 形式 | Shell 形式 |
寫法 | CMD ["cmd", "arg1", "arg2"] ENTRYPOINT ["cmd", "arg1", "arg2"] | CMD cmd arg1 arg2 ENTRYPOINT cmd arg1 arg2 |
是否通過 /bin/sh | ? 否 | ? 是 |
是否支持環(huán)境變量展開 | ? 否 | ? 是 |
是否支持管道、重定向等 | ? 否 | ? 是 |
信號傳遞(SIGTERM 等) | ? 正常 | ?? 可能被攔截 |
運(yùn)行時參數(shù)(docker run 參數(shù)) | ? 支持,僅針對對ENTRYPOINT指令,CMD指令是命令覆蓋 | ? 否,僅針對對ENTRYPOINT指令,CMD指令是命令覆蓋 |
PID 1 是誰 | 應(yīng)用進(jìn)程 | /bin/sh |
推薦場景 | 長期運(yùn)行的服務(wù)、生產(chǎn)環(huán)境 | 臨時命令、調(diào)試腳本 |
性能 | 更快、更干凈 | 稍慢 |
2、CMD、ENTRYPOINT指令
1)基本:
二者都是用來提供容器啟動時的命令,都支持exec和shell兩種書寫風(fēng)格:
- CMD提供的是默認(rèn)命令,所以支持命令的覆蓋;此外,還可以作為為 ENTRYPOINT 指令提供默認(rèn)參數(shù)(ENTRYPOINT+CMD組合方式,并且使用exec風(fēng)格)
- ENTRYPOINT是固定的命令,不支持命令覆蓋,可以進(jìn)行參數(shù)的傳遞。
ENTRYPOINT雖然默認(rèn)不能命令的覆蓋,但是可以通過--entrypoint參數(shù)來實(shí)現(xiàn):
docker run --entrypoint <新命令> <鏡像名> [參數(shù)...]
看個例子
#dockerfile FROM alpine:3.20 ENTRYPOINT ["echo", "hahaha!"] #構(gòu)建 docker build -t mytest #運(yùn)行 docker run mytest #輸出 hahaha! docker run --entrypoint ls mytest /usr 輸出 bin lib local sbin share
注意:在dockerfile中如果有多個CMD、ENTRYPOING指令,那么最后一個會覆蓋前面的。
2)一句話區(qū)分CMD和ENTRYPOINT:
- CMD:提供容器啟動的默認(rèn)命令或參數(shù),可以被覆蓋(被entrypoint覆蓋,或者被docker run后面跟的命令覆蓋)
- ENTRYPOINT:定義容器啟動時固定要執(zhí)行的主命令,一般不會覆蓋(除非使用--entrypoint)
示例1:使用CMD:
#dockerfile FROM busybox CMD ["echo", "hello world"] #構(gòu)建 docker build -t mytest #運(yùn)行 docker run mytest #輸出 hello world # 運(yùn)行 docker run myimage echo hi # 輸出:hi
說明:CMD 定義的命令可以被你在 docker run 中輸入的新命令替換掉。
示例2:ENTRYPOINT示例:
#dockerfile FROM busybox ENTRYPOINT ["echo", "hello"] # 運(yùn)行 docker run myimage # 輸出:hello #運(yùn)行 docker run myimage world # 輸出:hello world
說明:這里 ENTRYPOINT 是固定命令 echo,而 docker run myimage world 中的參數(shù) world 會被當(dāng)作 ENTRYPOINT 的參數(shù)。
示例3:你可以 組合 ENTRYPOINT + CMD 來實(shí)現(xiàn)“固定命令 + 默認(rèn)參數(shù)”模式
#dockerfile FROM busybox ENTRYPOINT ["sleep"] CMD ["60"] #運(yùn)行 docker run myimage # 等價于:sleep 60 docker run myimage 10 # 等價于:sleep 10
說明:
- ENTRYPOINT 是固定的命令:sleep
- CMD 提供默認(rèn)參數(shù):60
- 用戶在 docker run 中輸入?yún)?shù)會覆蓋 CMD,但不會影響 ENTRYPOINT
3、docker run運(yùn)行容器時的命令覆蓋和參數(shù)傳遞
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
[COMMAND] 和 [ARG...] 到底是「命令覆蓋」還是「參數(shù)傳遞」,取決于 Dockerfile 的 ENTRYPOINT/CMD 組合形式。
Dockerfile 內(nèi)容 | 啟動行為 | docker run IMAGE ... 的效果 |
1?? 只有 CMD | CMD 是默認(rèn)命令 | 運(yùn)行時的 [COMMAND] 會 覆蓋 CMD |
2?? 只有 ENTRYPOINT | ENTRYPOINT 是固定命令 | 對于exec風(fēng)格下,運(yùn)行時的 [COMMAND] 會被 當(dāng)作參數(shù)傳遞給 ENTRYPOINT |
3?? ENTRYPOINT + CMD | ENTRYPOINT 是固定命令,CMD 提供默認(rèn)參數(shù) | 對于exec風(fēng)格下,運(yùn)行時的 [COMMAND] 會 覆蓋 CMD(參數(shù)部分),但 不會覆蓋 ENTRYPOINT |
1)示例1:CMD 的shell和exec風(fēng)格:
#docker file FROM alpine:3.20 CMD echo hello #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hello docker run my-test echo hi 輸出 hi docker run my-test hi 報(bào)錯,“hi” executable file not found in $PATH: unknown.
說明:將dockerfile替換成CMD ["echo", "hello"] 運(yùn)行結(jié)果一樣!所以,對于CMD指令來說,只有ENTRYPOINT + CMD的組合的時候,才能通過docker run傳遞參數(shù)給CMD,只有CMD的時候,傳遞的“字符串”都是當(dāng)命令來執(zhí)行的,無法單獨(dú)為其傳遞參數(shù)!
2)示例2:ENTRYPOINT的shell風(fēng)格:
#docker file FROM alpine:3.20 ENTRYPOINT echo hahaha #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hahaha docker run my-test hi 輸出 hahaha docker run my-test echo hi 輸出 hahaha
說明:對于ENTRYPOINT的shell風(fēng)格,無法傳遞參數(shù)!
3)示例3:ENTRYPOINT的exec風(fēng)格:
#docker file FROM alpine:3.20 ENTRYPOINT ["echo", "hahaha!"] #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hahaha! docker run my-test hi 輸出 hahaha! hi docker run my-test echo hi 輸出 hahaha! echo hi
說明:對于ENTRYPOINT的Exec風(fēng)格,傳遞的字符串會當(dāng)作參數(shù)傳遞,并追加進(jìn)去!
4)示例4:組合模式exec風(fēng)格
#docker file FROM alpine:3.20 ENTRYPOINT ["echo"] CMD ["hi"] #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 hi docker run my-test abc 輸出 abc docker run my-test echo 123 輸出 echo 123
說明:docker run后面的字符串,會當(dāng)作參數(shù)覆蓋CMD。
5)示例5:組合模式shell風(fēng)格
#docker file FROM alpine:3.20 ENTRYPOINT echo CMD hi #構(gòu)建、運(yùn)行 docker build -t my-test . docker run my-test 輸出 空 docker run my-test abc 輸出 空 docker run my-test echo 123 輸出 空
說明:
docker官方文檔描述:
When using the exec form of ENTRYPOINT, the CMD value is passed as arguments to ENTRYPOINT.When using the shell form of ENTRYPOINT, the CMD value is ignored.
也就是說, Shell 形式的 ENTRYPOINT 會忽略 CMD 的內(nèi)容。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Docker復(fù)制現(xiàn)有容器的實(shí)現(xiàn)方法
在使用Docker進(jìn)行應(yīng)用開發(fā)和部署時,我們經(jīng)常需要基于現(xiàn)有的容器創(chuàng)建相似的環(huán)境,本文主要介紹了Docker復(fù)制現(xiàn)有容器的實(shí)現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下2024-03-03
ubuntu docker搭建Hadoop集群環(huán)境的方法
這篇文章主要介紹了ubuntu docker搭建Hadoop集群環(huán)境,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06
docker安裝jiacrontab可視化任務(wù)管理工具詳解
jiacrontab 是基于 Web 的可視化定時任務(wù)管理工具,由 server(調(diào)度多 client)和 client(執(zhí)行腳本)通過 RPC 通信構(gòu)成,支持超時處理、并發(fā)控制、依賴管理及兼容 Linux crontab 格式,便于多服務(wù)器統(tǒng)一管理2025-07-07
Docker安裝jenkins實(shí)現(xiàn)微服務(wù)多模塊打包的示例代碼
本文主要介紹了Docker安裝jenkins實(shí)現(xiàn)微服務(wù)多模塊打包的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Docker安裝并使用Mysql的詳細(xì)教程(實(shí)測可用!)
在日常的工作中經(jīng)常會需要將數(shù)據(jù)存在服務(wù)器,經(jīng)常用到的數(shù)據(jù)庫是mysql,下面這篇文章主要給大家介紹了關(guān)于Docker安裝并使用Mysql的詳細(xì)教程,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01

