CMD 指令的格式和 RUN 相似,也是兩種格式:
- shell 格式:CMD <命令>
- exec 格式:CMD ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2"...]
- 參數(shù)列表格式:CMD ["參數(shù)1", "參數(shù)2"...]狸相。在指定了 ENTRYPOINT 指令后薛匪,用 CMD 指定具體的參數(shù)。
容器是一個(gè)進(jìn)程。那么在啟動(dòng)容器的時(shí)候,就需要指定所運(yùn)行的程序及參數(shù)苞俘。
CMD 指令是用于指定默認(rèn)的容器主進(jìn)程的啟動(dòng)命令的苗胀,CMD 類屬于 RUN 命令基协,CMD 指令也可以用于運(yùn)行任何命令或應(yīng)用程序澜驮。
在運(yùn)行時(shí)可以指定新的命令來(lái)替代鏡像設(shè)置中的這個(gè)默認(rèn)命令杂穷,比如,ubuntu 鏡像默認(rèn)的 CMD 是 /bin/bash廊蜒,如果我們直接 docker run -it ubuntu 的話屁倔,會(huì)直接進(jìn)入 bash脑又。我們也可以在運(yùn)行時(shí)指定運(yùn)行別的命令嗅战,如 docker run -it ubuntu cat /etc/os-release。這就是用 cat /etc/os-release 命令替換了默認(rèn)的 /bin/bash 命令了色查,輸出了系統(tǒng)版本信息薯演。
在指令格式上,一般推薦使用 exec 格式秧了,這類格式在解析時(shí)會(huì)被解析為 JSON 數(shù)組跨扮,因此一定要使用雙引號(hào) ",而不要使用單引號(hào)验毡。
如果使用 shell 格式的話衡创,實(shí)際的命令會(huì)被包裝為 sh -c 的參數(shù)的形式進(jìn)行執(zhí)行。比如:
CMD echo $HOME
在實(shí)際執(zhí)行中晶通,會(huì)將其變更為:
CMD [ "sh", "-c", "echo $HOME" ]
這就是為什么我們可以使用環(huán)境變量的原因璃氢,因?yàn)檫@些環(huán)境變量會(huì)被 shell 進(jìn)行解析處理。
提到 CMD 就不得不提容器中應(yīng)用在前臺(tái)執(zhí)行和后臺(tái)執(zhí)行的問(wèn)題狮辽。這是初學(xué)者常出現(xiàn)的一個(gè)混淆拔莱。
Docker 不像虛擬機(jī),在容器中的應(yīng)用都應(yīng)該以前臺(tái)執(zhí)行隘竭,不像虛擬機(jī)那樣塘秦,用 systemd 去啟動(dòng)后臺(tái)服務(wù),容器內(nèi)沒(méi)有后臺(tái)服務(wù)餓概念动看。
如果 CMD 指令寫成:
CMD service nginx start
然后發(fā)現(xiàn)容器執(zhí)行后就立即退出了尊剔。甚至在容器內(nèi)發(fā)現(xiàn)無(wú)法執(zhí)行 systemctl 的指令。
對(duì)于容器而言菱皆,啟動(dòng)程序就是容器應(yīng)用進(jìn)程须误,容器就是為了主進(jìn)程而存在的,主進(jìn)程退出仇轻,容器就失去了存在的意義京痢。
而使用 service nginx start 命令,則是希望 upstart 來(lái)以后臺(tái)守護(hù)進(jìn)程啟動(dòng) nginx 服務(wù)篷店。
而剛才說(shuō)了 CMD service nginx start 會(huì)被理解為 CMD [ "sh", "-c", "service nginx start"]祭椰,因此主進(jìn)程實(shí)際上是 sh臭家。那么當(dāng) service nginx start 命令結(jié)束后,sh 也就結(jié)束了方淤,sh 作為主進(jìn)程退出了钉赁,自然就會(huì)令容器退出。
正確的做法是直接執(zhí)行 nginx 可執(zhí)行文件携茂,并且要求以前臺(tái)形式運(yùn)行你踩。比如:
CMD ["nginx", "-g", "daemon off;"]
該CMD 指令只能運(yùn)行一個(gè),如果存在多個(gè)讳苦,直留存一個(gè)带膜,最后一條 CMD 是生效的。
編寫Dockerfile 文件
[root@ip-10-1-0-142 mynginx]# cat Dockerfile
FROM nginx:latest
COPY hello.txt home/
COPY html/index.html /usr/share/nginx/
CMD ["nginx","-g","daemon off;"]
構(gòu)建鏡像的步驟
[root@ip-10-1-0-142 mynginx]# docker build -f Dockerfile -t nginx:v2 app
Sending build context to Docker daemon 3.631kB
Step 1/4 : FROM nginx:latest
---> 08b152afcfae
Step 2/4 : COPY hello.txt home/
---> f471772839c9
Step 3/4 : COPY html/index.html /usr/share/nginx/
---> c6c9239fc8a9
Step 4/4 : CMD ["nginx","-g","daemon off;"]
---> Running in ef82c58b610d
Removing intermediate container ef82c58b610d
---> 808dddfc65d6
Successfully built 808dddfc65d6
Successfully tagged nginx:v2