Dockerfile中CMD和ENTRYPOINT的用法
ENTRYPOINT 的兩種格式:
? ENTRYPOINT ["executable", "param1", "param2"] (exec格式,推薦使用此格式)
? ENTRYPOINT command param1 param2 (shell 格式)
ENTRYPOINT 的目的和 CMD 一樣,都是指定容器的啟動程序及參數。ENTRYPOINT 在運行時也可以通過 docker run 的參數 --entrypoint 來替代鏡像中默認的ENTRYPOINT,通過 --entrypoint 傳的必須是可執行的二進制程序, 即不會以sh -c 形式執行。
當指定了 ENTRYPOINT (exec格式)後,CMD 的含義就發生了改變,不再是直接運行的命令,而是將 CMD 的內容作為參數傳給 ENTRYPOINT 指令,換句話說實際執行時,將變為:<ENTRYPOINT> "<CMD>"
通過docker run <image>啟動容器時的命令行參數將作為ENTRYPOINT的參數追加到其已有的參數後面,此時所有的CMD參數將無效,被命令行參數覆蓋;
CMD作為 ENTRYPOINT 的參數時需要是exec格式,如果是shell格式將轉化成/bin/sh -c 式的exec格式,作為參數傳給 ENTRYPOINT 時可能會出錯;
當指定了ENTRYPOINT 為shell格式, CMD將無效, 即dockerfile裏的CMD和 啟動容器時傳的命令行參數都將無效,此時ENTRYPOINT 將以 /bin/sh –c 的形式啟動,即作為sh的子命令來執行,這種形式下ENTRYPOINT的執行程序不能通過Unix 信號控制,因進程號不是容器的PID 1 (sh的進程PID為1),也就不能以docker stop <container> 的形式來優雅地停止(接收SIGTERM信號)ENTRYPOINT的執行程序 ,因為這時docker stop <container>會在超時時間後通過發送SIGKILL信號給sh 強制停止容器,這會導致stop時間加長,為避免這種缺點,在shell命令前加exec,以這種方式運行即可, 如: ENTRYPOINT exec <shell command>。
二、 CMD指令
啟動容器的時候,需要指定所運行的程序及參數。CMD 指令就是用於指定默認的容器主進程的啟動命令的。
CMD指令有三種格式:
? CMD ["executable","param1","param2"] (exec 格式,推薦用此格式)
? CMD ["param1","param2"] (作為ENTRYPOINT 的默認參數)
? CMD command param1 param2 (shell 格式)
在dockerfile中只能有1個CMD指令,如有多個,最後一個生效。CMD的目的是提供默認的執行程序或執行程序的參數給容器,如果是參數,需要有ENTRYPOINT提供執行程序。
如果dockerfile中同時指定了ENTRYPOINT和CMD,CMD將作為ENTRYPOINT的默認參數,這裏兩個指令都指的是exec 格式,都將解析為JSON數組,所以只能用雙引號;
exec格式不會解析shell環境變量,如CMD [ "echo", "$HOME" ] 將無法解析變量HOME變量,dockerfile裏如果CMD用shell格式,在實際執行時將以 /bin/sh -c 執行,如:
CMD echo $HOME
在實際執行時將變成CMD [ "sh", "-c", "echo $HOME" ] 也就會解析出HOME變量。
CMD用exec格式執行系統的命令時,需要命令的全路徑和JSON數組格式,就是得使用雙引號,每個參數單獨分別地追加在數組中,如下用法:
CMD [“/usr/bin/wc”, ”--help”]
三、 理解和結合使用CMD和ENTRYPOINT
- Dockerfile 應該至少指定CMD或ENTRYPOINT其中的1個;
- 容器用作可執行的程序應用時應該用ENTRYPOINT;
- CMD應該用作ENTRYPOINT的默認參數來使用,或是在容器中執行臨時的命令;
- 啟動容器時如果傳遞參數將覆蓋dockerfile中指定的CMD參數;
下表列出了在CMD和ENTRYPOINT結合使用的情況下,哪個命令最終生效:
以上內容參考官方文檔:
https://docs.docker.com/engine/reference/builder/#usage
Dockerfile中CMD和ENTRYPOINT的用法