昨天用Dockerfile來啟動mongodb的集群,啟動參數--replSet死活沒執行,最后就決定研究一哈cmd和entrypoint。但是上網看了一些資料個人覺得講的不好,還是沒有說出根本的東西,決定自己研究並且整理一哈。
首先上docker官網:https://docs.docker.com/engine/reference/builder/#cmd
感覺官網關於這兩個命令講的簡直不要太清楚。
cmd:
這個命令是用來做什么的?下面是官網的答案:
The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
意思是,cmd給出的是一個容器的默認的可執行體。也就是容器啟動以后,默認的執行的命令。重點就是這個“默認”。意味着,如果docker run沒有指定任何的執行命令或者dockerfile里面也沒有entrypoint,那么,就會使用cmd指定的默認的執行命令執行。同時也從側面說明了entrypoint的含義,它才是真正的容器啟動以后要執行命令。
所以這句話就給出了cmd命令的一個角色定位,它主要作用是默認的容器啟動執行命令。(注意不是“全部”作用)
這也是為什么大多數網上博客論壇說的“cmd會被覆蓋”,其實為什么會覆蓋?因為cmd的角色定位就是默認,如果你不額外指定,那么就執行cmd的命令,否則呢?只要你指定了,那么就不會執行cmd,也就是cmd會被覆蓋。
明白了cmd命令的主要用途。下面就看看具體用法。
總共有三種用法:
The CMD instruction has three forms: CMD ["executable","param1","param2"] (exec form, this is the preferred form) CMD ["param1","param2"] (as default parameters to ENTRYPOINT) CMD command param1 param2 (shell form)
因為還沒有講entrypoint,所以先不看用法2。
用法3:shell form,即沒有中括號的形式。那么命令command默認是在“/bin/sh -c”下執行的。比如下面的dockerfile:
FROM centos CMD echo "hello cmd!"
運行:
用法1:帶有中括號的形式。這時,命令沒有再任何shell終端環境下,如果我們要執行shell,必須把shell加入到中括號的參數中。這種用法就像一個c語言的exec函數,意思是我們要執行一個進程。如果采用非shell的方法,那么上面的例子要修改為:
FROM centos CMD ["/bin/bash", "-c", "echo 'hello cmd!'"]
需要注意,采用中括號形式,那么第一個參數必須是命令的全路徑才行。而且,一個dockerfile至多只能有一個cmd,如果有多個,只有最后一個生效。
官網推薦采用這種方法。
當然,以上都是體現了cmd的“默認”行為。如果我們在run時指定了命令或者有entrypoint,那么cmd就會被覆蓋。仍然是上面的image。run命令變了:
可以看到,最終容器里面執行的是run命令后面的命令,而不是cmd里面定義的。
接下來再看entrypoint:
An ENTRYPOINT allows you to configure a container that will run as an executable.
也就是說entrypoint才是正統地用於定義容器啟動以后的執行體的,其實我們從名字也可以理解,這個是容器的“入口”。
有兩種用法:
ENTRYPOINT has two forms: ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred) ENTRYPOINT command param1 param2 (shell form)
命令行和shell。
先看命令行模式,也就是帶中括號的。和cmd的中括號形式是一致的,但是這里貌似是在shell的環境下執行的,與cmd有區別。如果run命令后面有東西,那么后面的全部都會作為entrypoint的參數。如果run后面沒有額外的東西,但是cmd有,那么cmd的全部內容會作為entrypoint的參數,這同時是cmd的第二種用法。這也是網上說的entrypoint不會被覆蓋。當然如果要在run里面覆蓋,也是有辦法的,使用--entrypoint即可。
下面看幾個例子。
dockerfile為:
FROM centos CMD ["p in cmd"] ENTRYPOINT ["echo"]
如果run不帶參數:
如果run帶參數:
而且,確實entrypoint的中括號形式下,command是在shell環境下運行的,否則這里的echo是無法被執行的。
第二種是shell模式的。在這種模式下,任何run和cmd的參數都無法被傳入到entrypoint里。官網推薦第一種用法。
FROM centos CMD ["p in cmd"] ENTRYPOINT echo
cmd的參數沒有被打印。
總結下一般該怎么使用:一般還是會用entrypoint的中括號形式作為docker 容器啟動以后的默認執行命令,里面放的是不變的部分,可變部分比如命令參數可以使用cmd的形式提供默認版本,也就是run里面沒有任何參數時使用的默認參數。如果我們想用默認參數,就直接run,否則想用其他參數,就run 里面加參數
感謝:https://blog.csdn.net/u010900754/article/details/78526443