Docker Certified Associate(DCA)認證考試學習-Dockerfile CMD ENTRYPOINT 兩者的差別 Docker Certified Associate(DCA)認證相關資源、Dockerfile CMD ENTRYPOINT 兩者的差別

Published on Monday, February 20, 2023

Dockerfile CMD

在前幾篇的文章中: Docker Certified Associate(DCA)認證考試學習-Dockerfile

在我們查看Docker Run時,有提到 CMDENTRYPOINT 並且附上了一個表格

  • Dockerfile 最少必須要有一個 CMDENTRYPOINT 指令
  • 如果要將container當作成一個可執行檔,使用ENTRYPOINT
No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

當初只有快速的帶過這部分,並沒有詳細提及
今天來好好將他們的區別研究清楚

首先先看一下CMD的文檔
CMD指令有三種使用格式

  • CMD ["executable","param1","param2"] exec格式,優先選擇使用此格式
  • CMD ["param1","param2"] 做為ENTRYPOINT的預設輸入參數
  • CMD command param1 param2 shell格式

並且要注意以下事項

  • 一個Dockerfile只能有一個CMD指令,如果多於一個的話後面宣告的會蓋掉之前的
  • exec格式會將內容解析為JSON Array所以必須使用雙引號不可以是用單引號
  • exec格式並不會並不會調用shell

這邊來做幾個簡單測試

#Dockerfile
From alpine
CMD [ "echo", "$HOME" ]

可以對照上方的表格CMD [“exec_cmd”, “p1_cmd”] and No ENTRYPOINT,預期輸出的結果為 exec_cmd p1_cmd 因可得知輸出的語法為echo $HOME 這邊因為是使用exec格式所以shell並沒有介入,因此並沒有將$HOME參數修改成我們的地址

$ docker build -t cmdimage .
$ docker run cmdimage
$HOME

如果要使用exec格式還希望調用shell,也是可以做到

#Dockerfile
From alpine
CMD [ "sh", "-c", "echo $HOME" ]

改成這種寫法其實就跟我們平常寫shell命令時一樣
可以對照上方的表格CMD [“exec_cmd”, “p1_cmd”] and No ENTRYPOINT,預期輸出的結果為 exec_cmd p1_cmd 因可得知輸出的語法為sh -c "echo $HOME"

$ docker build -t cmdimage .
$ docker run cmdimage
/root

接下來試試看shell格式

#Dockerfile
From alpine
CMD echo $HOME

可以對照上方的表格CMD exec_cmd p1_cmd and No ENTRYPOINT,預期輸出的結果為 /bin/sh -c exec_cmd p1_cmd 因可得知輸出的語法為/bin/sh -c echo $HOME

$ docker build -t cmdimage .
$ docker run cmdimage
/root

接下來複習一下docker run的使用方法
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

這邊的[COMMAND]也就代表Dockerfile 裡面的 CMD指令,所以在使用docker run如果這邊有帶入參數,那就會覆蓋掉Dockerfile裡的CMD

[node1] (local) root@192.168.0.28 ~/cmd
$ docker run cmdimage echo hello
hello
[node1] (local) root@192.168.0.28 ~/cmd
$ docker run cmdimage && echo hello
/root
hello

Dockerfile ENTRYPOINT

首先先看一下ENTRYPOINT的文檔
ENTRYPOINT指令有兩種使用格式

  • ENTRYPOINT ["executable", "param1", "param2"] exec格式,優先選擇使用此格式
  • ENTRYPOINT command param1 param2 shell格式

首先先測試下exec格式

#Dockerfile
From alpine
ENTRYPOINT [ "echo", "$HOME" ]

可以對照上方的表格No CMD and ENTRYPOINT [“exec_entry”, “p1_entry”],預期輸出的結果為 exec_entry p1_entry

$ docker build -t entryimage .
$ docker run entryimage
$HOME

跟CMD一樣如果要使用exec格式還希望調用shell

#Dockerfile
From alpine
ENTRYPOINT [ "sh", "-c", "echo $HOME" ]
$ docker build -t entryimage .
$ docker run entryimage
/root

到目前為止大家應該能看懂表格想要表達的意思了
所以ENTRYPOINT在shell格式下就能很輕鬆的推斷出輸出的結果了 也就是不管有沒有CMD指令ENTRYPOINT在shell格式下只會輸出/bin/sh -c exec_entry p1_entry 也就是說如果Dockerfile要使用同時使用ENTRYPOINT與CMD只能使用shell格式

那麼再做最後的測試

#Dockerfile
From alpine
ENTRYPOINT [ "echo", "$HOME" ]
CMD echo $HOME

可以對照上方的表格CMD exec_cmd p1_cmd and ENTRYPOINT [“exec_entry”, “p1_entry”],預期輸出的結果為 exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

$ docker build -t entryimage .
$ docker run entryimage
$HOME /bin/sh -c echo $HOME

最後兩個都使用shell格式

#Dockerfile
From alpine
ENTRYPOINT [ "echo", "$HOME" ]
CMD ["echo", "$HOME"]

可以對照上方的表格CMD exec_cmd p1_cmd and ENTRYPOINT [“exec_entry”, “p1_entry”],預期輸出的結果為 exec_entry p1_entry exec_cmd p1_cmd

$ docker build -t entryimage .
$ docker run entryimage
$HOME echo $HOME

那麼如果在docker run 後面在帶參數會發生什麼事呢

[node1] (local) root@192.168.0.28 ~/entry
$ docker run entryimage echo hello
$HOME echo hello
[node1] (local) root@192.168.0.28 ~/entry
$ docker run entryimage && echo hello
$HOME echo $HOME
hello

Summary

今天內容有點雜,不過Docker官方與有說建議使用exec格式,所以真的比較常用的也只有三個

  • CMD [“exec_cmd”, “p1_cmd”] + No ENTRYPOINT = exec_cmd p1_cmd
  • No CMD + ENTRYPOINT [“exec_entry”, “p1_entry”] = exec_entry p1_entry
  • CMD [“exec_cmd”, “p1_cmd”] + ENTRYPOINT [“exec_entry”, “p1_entry”] = exec_entry p1_entry exec_cmd p1_cmd

確實在大多範例也都只會使用到這三種情況,其它情況例如呼叫起程式也同時執行bash的命令,可能才會使用到其他的搭配
可以按照自己的需求來選擇