2016-12-28 49 views
1

我有一個Dockerfile,屬於Understand how CMD and ENTRYPOINT interact中找到的矩陣中的exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd類別。這種行爲不是我期待的。我期待/bin/sh -c exec_cmd p1_cmd先評價然後通過exec_entry p1_entry。我正在觀察的是,/bin/sh -c exec_cmd p1_cmd從字面上得到了exec_entry p1_entry,我認爲這很有趣。入口點的Docker CMD評估

爲了提供更多的背景,我特別從existing Dockerfile如果母公司具有派生新Dockerfile:

ENTRYPOINT ["/bin/registrator"] 

我想在特定的命令行參數來傳遞從我Dockerfile:

FROM gliderlabs/registrator:v7 
CMD echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST" 

當我在一個容器中運行我的碼頭工人形象:

$ docker run --rm --name=test-registrator --volume=/var/run/docker.sock:/tmp/docker.sock -e "EXTERNAL_IP=<some-ip>" -e "CONSUL_HOST=<some-consul-hostname>:8500" my/registrator 

我得到以下錯誤:

2016/12/28 19:20:46 Starting registrator v7 ... 
Extra unparsed arguments: 
    -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST" 
Options should come before the registry URI argument. 

Usage of /bin/registrator: 
    /bin/registrator [options] <registry URI> 

-cleanup=false: Remove dangling services 
-deregister="always": Deregister exited services "always" or "on-success" 
-internal=false: Use internal ports instead of published ones 
-ip="": IP for ports mapped to the host 
-resync=0: Frequency with which services are resynchronized 
-retry-attempts=0: Max retry attempts to establish a connection with the backend. Use -1 for infinite retries 
-retry-interval=2000: Interval (in millisecond) between retry-attempts. 
-tags="": Append tags for all registered services 
-ttl=0: TTL for services (default is no expiry) 
-ttl-refresh=0: Frequency with which service TTLs are refreshed 

這意味着-c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"簡直是獲取傳遞到/bin/registrator作爲參數。

我做錯了什麼,或者這是一個使用案例的侷限性,其中/bin/sh -c exec_cmd p1_cmd在被傳遞到ENTRYPOINT之前沒有被首先排除?如果後者是真的,那麼你是否也可以解釋這個用例的用處?

回答

2

是的。這正是它應該如何工作。

CMD的值僅作爲參數傳遞給ENTRYPOINT。

CMD和ENTRYPOINT之間的主要區別在於,CMD只是爲ENTRYPOINT程序提供了默認命令參數,並且通常會被參數運行命令覆蓋。另一方面,如果要執行不同的命令,則必須使用--entrypoint選項明確重新定義ENTRYPOINT。

另外,請注意,根據ENTRYPOINT和CMD在Dockerfile中定義的方式,事情是如何執行的有所不同。當它們以['arg1','arg2']的形式被定義爲數組時,該數組被原樣傳遞給ENTRYPOINT命令,並且ENTRYPOINT的第一個元素是被執行的程序。在另一種情況下,當它們被定義爲一個簡單的字符串,如arg1 arg2該字符串首先傳遞的前綴是「/ bin/sh -c」,注意Docker不執行/ bin/sh並返回評估結果,該字符串本身被傳遞給ENTRYPOINT程序。

所以你的情況,你必須使用合格的參數數組方法:

CMD [-ip, $EXTERNAL_IP, consul://$CONSUL_HOST] 
+0

那我就不明白什麼是這個用例'exec_entry p1_entry/bin/sh的-c EXEC_CMD p1_cmd點'。這將需要'exec_entry'應用程序來處理我認爲很奇怪的命令。 – mikehwang

+0

啊,錯過了那部分。實際上,當CMD是以字符串形式定義的時候是退化的情況,但是您的ENTRYPOINT不是shell。我認爲它沒有任何用處。只有當你的ENTRYPOINT是一個shell(bash,sh,csh)並且你有像這樣的命令行「ls * .c」才能使用這種語法是有意義的。否則,ls只會獲得'* .c'作爲參數,並將查找名爲'* .c'的文件而不是以'.c'結尾的文件集合。 – Vlad

+0

感謝您的輸入!我想指出(雖然它會很好),因爲環境變量不能解決,CMD [-ip,$ EXTERNAL_IP,consul:// $ CONSUL_HOST]不起作用。請參閱[本文](http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/)* Shell形式*然後* Exec形式*。 – mikehwang