Dockerfile CMD與ENTRYPOINT

簡介

在查看Dockerfile可用指令(instructions)時楼熄,會發(fā)看起來有一些“重復(fù)”指令(即不同指令實現(xiàn)的功能幾乎相同)腺占。之前我們講解了COPY和ADD的區(qū)別橡娄,本章會分析CMD與ENTRTYPOINT的不同。

ENTRYPOINT與CMD都可以對iamge配置啟動命令稠鼻。但兩者之間還是有一些細微的區(qū)別煤蚌。多數(shù)情況下需要用戶在二者中選擇其一使用,但也可以共同使用兩者鸿捧。下面將具體分析二者不同的使用場景:

ENTRYPOINT or CMD

最終,ENTRYPOINT與CMD都提供了一個方法疙渣,讓用戶指定容器默認啟動命令。事實上堆巧,如果你希望你的image是可執(zhí)行的(啟動docker run時不額外指定啟動命令就可以運行)妄荔,那么你必須在Dockerfile中使用ENTRYPOINT或CMD

嘗試運行一個沒有使用ENTRYPOINT或CMD指令的image,啟動時會報錯:

$ docker run alpine
FATA[0000] Error response from daemon: No command specified

你能在Docker Hub上找到的大多數(shù)linux版本基礎(chǔ)鏡像都使用了/bin/sh/bin/bash這樣的shell命令來作為CMD啟動命令谍肤。這意味著啦租,任何人運行這些image時,都會默認進入到交互式shell界面中(假設(shè)運行時指定了-t/-i參數(shù))

這對通用的基礎(chǔ)鏡像是十分方便的荒揣,但是當(dāng)你希望運行自己的image時(即非通用基礎(chǔ)iamge時)篷角,更多時候需要指定一個更具體的可執(zhí)行文件或命令來作為CMD或ENTRYPOINT參數(shù)。

Overrides

在Dockerfile中指定的ENTRYPOINT或CMD為你的image指定默認啟動命令系任。并且恳蹲,用戶可以選擇在容器運行時重寫(overrides)這些值中的任何一個虐块。

例如,假設(shè)我們有以下Dockerfile:

FROM ubuntu:trusty
CMD ping localhost

如果我們構(gòu)建該image 嘉蕾,在運行是會看到如下輸出:

$ docker run -t demo
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.051 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.038 ms
^C
--- localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.026/0.032/0.039/0.008 ms

你可以看到贺奠,在容器啟動時,自動運行了ping命令错忱。然而儡率,在啟動容器時,我們可以在image名稱后面添加一個參數(shù)來重寫默認CMD指令:

$ docker run demo hostname
6c1573c0d4c0

在上述例子中以清,hostname命令代替了ping命令運行

默認ENTRYPOINT指令也可以被類似的方式重寫儿普,不過需要使用--entrypoint參數(shù)

$ docker run --entrypoint hostname demo

CMD的使用場景

考慮到重寫CMD指令是非常簡單的,所以在希望用戶使用該image創(chuàng)建容器時擁有更高的靈活性掷倔,可以更方便的指定任何自己想要的啟動命令時箕肃,更推薦CMD指令。例如今魔,你有一個通用的Ruby Image勺像,默認情況下將啟動一個交互式的irb會話(CMD irb),但你也想給用戶一個選項來運行任意的Ruby腳本(docker運行Ruby Ruby -e 'puts "Hello"')错森。

ENTRYPOINT的使用場景

相反吟宦,ENTRYPOINT指令適合用于:希望容器最終運行時所執(zhí)行的命令與Dockerfile內(nèi)配置的命令相同的場景下。也就是說涩维,不希望用戶重寫image啟動命令

通常使用Docker作為指定可執(zhí)行文件的容器是很方便的殃姓。假設(shè)您有一個Python腳本的實用程序,您需要發(fā)布它瓦阐,但又不想讓安裝正確的解釋器版本和依賴項給最終用戶帶來負擔(dān)蜗侈。你可以配置好解釋器版本與依賴后,通過ENTRYPOINT指定可執(zhí)行文件睡蟋。用戶便可以使用docker運行你的image踏幻,它的行為就像直接運行你的腳本,但又不用考慮依賴項戳杀、啟動命令參數(shù)等信息该面,直接運行即可。

當(dāng)然信卡,使用CMD指令可以實現(xiàn)同樣的功能隔缀,但使用了ENTRYPOINT相當(dāng)于給用戶傳遞了一個強烈的信息:這個容器只為運行這一個程序而存在,盡量不要修改容器啟動命令來另作他用傍菇。

將ENTRYPOINT與CMD組合使用時猾瘸,ENTRYPOINT的效用將會更清楚,但我們在后文討論這種用法。

Shell vs. Exec

ENTRYPOINT與CMD指令都支持兩種不同的參數(shù)格式:Shell格式Exec格式牵触,在上面的例子中淮悼,我們使用了shell格式

CMD executable param1 param2

Shell

當(dāng)使用Shell格式時,容器啟動時會使用/bin/sh -c來執(zhí)行指定的可執(zhí)行/二進制/文件荒吏。容器啟動后敛惊,運行docker ps 就可以清楚看到:

$ docker run -d demo
15bfcddb11b5cde0e230246f45ba6eeb1e6f56edb38a91626ab9c478408cb615

$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED
15bfcddb4312 demo:latest "/bin/sh -c 'ping localhost'" 2 seconds ago

我們再次運行了“demo”容器,可以看到容器啟動命令為:/bin/sh -c 'ping localhost

這看起來沒什么問題绰更,命令也正常被運行瞧挤。但是當(dāng)我們使用shell格式來傳遞ENTRYPOINT或CMD參數(shù)時還是會有一些微妙的小問題。現(xiàn)在我們進入到容器內(nèi)儡湾,查看容器內(nèi)的進程就會看到如下信息:

$ docker exec 15bfcddb ps -f
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 20:14 ? 00:00:00 /bin/sh -c ping localhost
root 9 1 0 20:14 ? 00:00:00 ping localhost
root 49 0 0 20:15 ? 00:00:00 ps -f

請注意特恬,PID為1的進程并不是我們所期望的ping命令,而是/bin/sh徐钠。這會導(dǎo)致當(dāng)我們需要向容器發(fā)送任何類型的POSIX信號癌刽,/bin/sh不會將信號轉(zhuǎn)發(fā)給子進程(詳細原理可參考: Gracefully Stopping Docker Containers)。

除了PID1的問題外尝丐,可能很多輕量化的image并不會包含任何shell程序显拜。當(dāng)容器啟動時,并不會檢查容器內(nèi)是否有shell程序可用爹袁。如果你的鏡像并不包含/bin/sh命令远荠,那么顯然容器會啟動失敗。

Exec

所以更好的選擇是使用Exec格式來傳遞ENTRYPOINT與CMD參數(shù)失息,例如:

CMD ["executable","param1","param2"]

注意譬淳,CMD指令后的參數(shù)被格式化成了JSON數(shù)組

當(dāng)使用Exec格式的CMD指令后,容器啟動時該命令將不會通過Shell的方式運行盹兢,而是直接執(zhí)行邻梆。

讓我們將上述的Dockerfile改為Exec格式看看實際效果:

FROM ubuntu:trusty
CMD ["/bin/ping","localhost"]

重新構(gòu)建image,查看容器啟動命令:

$ docker build -t demo .
[truncated]

$ docker run -d demo
90cd472887807467d699b55efaf2ee5c4c79eb74ed7849fc4d2dbfea31dce441

$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED
90cd47288780 demo:latest "/bin/ping localhost" 4 seconds ago

可以看到绎秒,ping命令在沒有shell介入的情況下直接運行浦妄。并且是容器內(nèi)的PID1進程

所以無論使用ENTRYPOINT或CMD指令,都推薦使用Exec格式替裆。因為它可以使你的應(yīng)用清晰的運行在容器的PID1進程上校辩。

ENTRYPOINT and CMD

到目前為止,我們討論了如何使用ENTRYPOINTCMD指令來指定image默認啟動命令辆童。然而,在一些情況下惠赫,我們可以同時使用ENTRYPOINTCMD把鉴。

將ENTRYPOINT與CMD組合使用依舊可以指定image默認啟動命令,同時也了指定image啟動命令的默認參數(shù)。同時該參數(shù)可以被方便的重寫庭砍。讓我們看下述例子:

FROM ubuntu:trusty
ENTRYPOINT ["/bin/ping","-c","3"]
CMD ["localhost"]

重新構(gòu)建image并不附加任何參數(shù)啟動容器:

$ docker build -t ping .
[truncated]

$ docker run ping
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.051 ms

--- localhost ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.025/0.038/0.051/0.010 ms

$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED
82df66a2a9f1 ping:latest "/bin/ping -c 3 localhost" 6 seconds ago

請注意场晶,啟動命令為Dockerfile中ENTRYPOINT與CMD值的組合。當(dāng)同時使用ENTRYPOINT與CMD指令時怠缸,CMD指令的值會被追加到ENTRYPOINT值的后面诗轻,組合成為一條啟動命令。且CMD指令仍然保留容易被重寫的特性揭北,用戶可以很方便的通過在docker run后添加參數(shù)來重寫CMD值(即啟動命令的參數(shù))扳炬。下例展示了如何修改ping命令的默認參數(shù):

$ docker run ping docker.io
PING docker.io (162.242.195.84) 56(84) bytes of data.
64 bytes from 162.242.195.84: icmp_seq=1 ttl=61 time=76.7 ms
64 bytes from 162.242.195.84: icmp_seq=2 ttl=61 time=81.5 ms
64 bytes from 162.242.195.84: icmp_seq=3 ttl=61 time=77.8 ms

--- docker.io ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 76.722/78.695/81.533/2.057 ms

$ docker ps -l --no-trunc
CONTAINER ID IMAGE COMMAND CREATED
0d739d5ea4e5 ping:latest "/bin/ping -c 3 docker.io" 51 seconds ago

現(xiàn)在,運行image就像運行一個普通可執(zhí)行文件(命令)一樣搔体,指定要執(zhí)行的可執(zhí)行文件(image)恨樟,并在其后指定相應(yīng)的參數(shù)。

請注意疚俱,作為ENTRYPOINT的一部分包含的-c 3參數(shù)實際上成為了ping命令的“硬編碼”參數(shù)劝术。它包含在image的每次調(diào)用中,重寫CMD參數(shù)并不會影響ENTRYPOINT中的參數(shù)呆奕。

Always Exec

當(dāng)同時使用ENTRYPOINT與CMD养晋,請注意必須使用Exec格式來傳遞參數(shù)。你會發(fā)現(xiàn)梁钾,使用Shell格式或混合使用绳泉,將永遠不會得到你想要的效果:

Dockerfile    Command
ENTRYPOINT /bin/ping -c 3
CMD localhost    /bin/sh -c '/bin/ping -c 3' /bin/sh -c localhost
ENTRYPOINT ["/bin/ping","-c","3"]
CMD localhost    /bin/ping -c 3 /bin/sh -c localhost
ENTRYPOINT /bin/ping -c 3
CMD ["localhost"]"    /bin/sh -c '/bin/ping -c 3' localhost
ENTRYPOINT ["/bin/ping","-c","3"]
CMD ["localhost"]    /bin/ping -c 3 localhost

上述例子中,只有當(dāng)同時使用Exec格式的ENTRYPOINT與CMD時陈轿,才能實現(xiàn)我們想要的功能圈纺。

總結(jié)

ENTRYPOINT與CMD指令都可以幫助你在Dockerfile中配置容器啟動命令。但二者各對應(yīng)了不同的應(yīng)用場景麦射,實際使用中還需挑選一個合適的指令蛾娶。并且二者并不是互斥了,在某些場景下同時使用兩個指令也是必須的潜秋。但無論如何使用蛔琅,請忘記Shell格式,在任何情況下Exec格式都一定是正確的選擇峻呛。

參考:https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末罗售,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钩述,更是在濱河造成了極大的恐慌寨躁,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牙勘,死亡現(xiàn)場離奇詭異职恳,居然都是意外死亡所禀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門放钦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來色徘,“玉大人,你說我怎么就攤上這事操禀」硬撸” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵颓屑,是天一觀的道長斤寂。 經(jīng)常有香客問我,道長邢锯,這世上最難降的妖魔是什么扬蕊? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮丹擎,結(jié)果婚禮上尾抑,老公的妹妹穿的比我還像新娘。我一直安慰自己蒂培,他們只是感情好再愈,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著护戳,像睡著了一般翎冲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上媳荒,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天抗悍,我揣著相機與錄音,去河邊找鬼钳枕。 笑死缴渊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鱼炒。 我是一名探鬼主播衔沼,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昔瞧!你這毒婦竟也來了指蚁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤自晰,失蹤者是張志新(化名)和其女友劉穎凝化,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酬荞,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡缘圈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年劣光,在試婚紗的時候發(fā)現(xiàn)自己被綠了袜蚕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糟把。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牲剃,靈堂內(nèi)的尸體忽然破棺而出遣疯,到底是詐尸還是另有隱情,我是刑警寧澤凿傅,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布缠犀,位于F島的核電站,受9級特大地震影響聪舒,放射性物質(zhì)發(fā)生泄漏辨液。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一箱残、第九天 我趴在偏房一處隱蔽的房頂上張望滔迈。 院中可真熱鬧,春花似錦被辑、人聲如沸燎悍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈山。三九已至,卻和暖如春宏怔,著一層夾襖步出監(jiān)牢的瞬間奏路,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工臊诊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸽粉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓妨猩,卻偏偏與公主長得像潜叛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子壶硅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容