如何向 Docker 容器傳遞引數
我們在執行 docker 映象時希望能用下面的命令向容器傳遞命令列引數
docker run <image-name> <command> arg1 arg2
docker run <image-name> arg1 arg2
其實只有第一種形式,緊隨映象名後那個總是一個命令,其後才是引數。如果要向 docker 容器傳遞引數時,Dockerfile 該如何寫,這就有必要稍稍瞭解一下 Dockerfile 中 CMD 和 ENTRYPOINT 這兩個指令,並且它們有 exec 和 shell 兩種格式的寫法。詳情請見上篇 Dockerfile 中命令的兩種書寫方式的區別
對於一個 docker 映象,我們可以這麼來理解 ENTRYPOINT 與 CMD 的關係
- 如果沒有定義 ENTRYPOINT, CMD 將作為它的 ENTRYPOINT
- 定義了 ENTRYPOINT 的話,CMD 只為 ENTRYPOINT 提供引數
- CMD 可由
docker run <image>
後的命令覆蓋,同時覆蓋引數
對於 #1 和 #2 更精緻的理解是容器執行的最終入口由 ENTRYPOINT 和實際的 CMD 拼接而成。ENTRYPOINT 和 CMD 需轉換為實際映象中的 exec 格式來拼接,合併後的第一個元素是命令,其餘是它的引數。
舉四個例子進行說明
一, 未定義 ENTRYPOINT, 定義了 CMD
#ENTRYPOINT []
CMD ["echo", "hello"]
實際入口是它們拼接後還是 CMD 本身,["echo", "hello"]
二, 定義了 ENTRYPOINT 和 CMD
ENTRYPOINT ["echo", "hello"]
CMD ["echo", "world"]
實際入口是它們拼接起來,形成 ["echo", "hello", "echo", "world"]
, 執行 docker run test
顯示為 hello echo world
三, 定義了 ENTRYPOINT, CMD 由 docker run
ENTRYPOINT ["echo", "hello"]
執行命令 docker run <image> rm -rf /
, 實際入口是由 ["echo", "hello"]
與 ["rm", "-rf", "/"]
拼接而成的 ["echo", "hello", "rm", "-rf", "/"]
, 輸出為 hello rm -rf /
。看到 rm -rf /
也不用擔心,用 ENTRYPOINT 就是讓人放心
注:ENTRYPOINT 同樣可以被覆蓋,如 docker run --entrypoint ls test -l /
,將會執行 ls -l /
命令。
四, 如果 ENTRYPOINT 用 shell 格式定義的
ENTRYPOINT java -jar /app.jar
CMD ["hello", "world"]
通過 docker inspect
命令看到映象中實際的 ENTRYPOINT 是
ENTRYPOINT ["/bin/sh", "-c", "java -jar /app.jar"]
所以與 CMD 連線起來的入口就是 ["/bin/sh", "-c", "java -jar /app.jar", "hello", "world"]
, "bin/sh" 直接忽略掉後面的 "hello" 與 "world",這就是為什麼 shell 命令方式無法獲取引數。
有了以上幾點概念,以及四個例項作為感觀認識後,想要怎麼往容器傳遞引數應該很容易確定了。
未定義 ENTRYPOINT
沒有定義 ENTRYPOINT 的映象想怎麼來就怎麼來,docker run <image>
後面的輸入你自己作主。
有定義 ENTRYPOINT
定義了 ENTRYPOINT 的映象,則是 CMD 或 docker run <image>
後的輸入作為 ENTRYPOINT 中命令的附加引數。再次提醒 shell 格式的 ENTRYPOINT 和 CMD 務必要轉換為相應 exec 格式來理解。
shell 格式的 ENTRYPOINT
如果是複雜的 shell 命令不容易拆解出一個個引數,而希望用 shell 格式來定義 ENTRYPOINT 的話,也有辦法。shell 格式的 ENTRYPOINT 是由 "/bin/sh -c" 啟動的,而它是可以解析變數的。另一方面 CMD 或 docker run <image>
的輸入第一個元素存成了 $0
,其他剩餘元素存為 [email protected]
, 所以 shell 格式的 ENTRYPOINT 可以這麼寫
ENTRYPOINT echo hello $0 [email protected]
注:shell 中 $0
表示命令本身,[email protected]
為所有引數
這樣執行下面 docker 命令將可獲得所有的引數輸入
$ docker run test world and China
hello world and China
如果只是按常規 shell 指令碼來對待,想當然的寫成
ENTRYPOINT echo hello [email protected]
效果將是
$ docker run test world and China
hello and China
第一個引數將被丟失,docker run <image>
後第一個輸入通常是一個命令,所以是 $0
, 而 ENTRYPOINT 又希望它是一個普通引數,因此$0 [email protected]
要同時寫上。
直接用 docker inspect <container-id>
檢視
最簡單且準確的方式就是直接用 docker inspect <container-id>
檢視實際啟動的命令及引數