一開始學習 Docker 時,我也同時看了網路上將 App 包裝成進去 Docker container 的筆記或教學文,Dockerfile 的配置很好寫,但是在不同的文章中,有一個地方,在每篇文章幾乎都只有提到如何使用,沒有解說為何這樣使用的指令就是 CMD 和 ENTRYPOINT。

從不同的範例學習時,只要按照原作者的邏輯,都完全可以執行程式,而 CMD 和 ENTRYPOINT 有時候看起來又根本沒區別,我就有點被搞混了,網路上也有各種範例在解釋 CMD 和 ENTRYPOINT。不過其實看了一下原文的文件,他們的想法其實也是非常簡單;而我想要從結論開始討論回去,要知道要如何選擇 CMD 或是 ENTRYPOINT ,從自己的目的去決定後,就很快知道他們的概念。

首先,CMD 和 ENTRYPOINT 其實都不一定是必要的。

既然 Docker 是虛擬機,那我們就想像他是一部自己的電腦吧,然後我們準備要在上面開發網站。那開發網站通常有幾件事情要做,那就是打開電腦,安裝必要軟體,把程式碼下載到電腦上面,設定好環境,最後我們要啟動伺服器,像是 rails snode app.js ...等這類當我們寫完程式後,要啟動伺服器的指令,而 CMD 和 ENTRYPOINT 就是可以輔助我們去執行這些指令。

而不一定必要的原因是因為在執行 Docker 時,我們可以把想要執行的指令直接接在 docker run 之後,Docker 就會啟動後再執行那個指令,但如果這樣就可以解決問題,就不會有需要 CMD 和 ENTRYPOINT ,也就不會有這個問題了。簡單的說就是,這樣直接把想要執行的指令接在後面不是個好方法,如果要執行的指令還有參數很多怎麼辦?docker 本身就有自己的參數,會不會搞混呢?...等問題。

所以這兩個指令的意義就是我們想要在 Docker 中設定預設的啟動「服務」的方式,那這樣的話,為什麼需要兩種方式?

這就有兩種情況可以考慮了。

  1. 我想要設定執行的方法,但是如果執行 docker run 時有新的啟動的指令組合,我只考慮新的指令。 > 用 CMD
  2. 我想要設定執行的方法,而且這個方法在執行 docker run 時不能被覆寫掉,但我會考慮接受新的參數設定 > 用 ENTRYPOINT

其中 Docker 只會考慮 Dockerfile 中最後的 CMD 和 ENTRYPOINT,另外 CMD 和 ENTRYPOINT 可以並存。

基於 Docker 的設計裡面,最佳的實踐其實可以是這樣

  • 執行指令,使用 ENTRYPOINT 設定。
  • 執行指令的參數,使用 CMD 設定。
  • 只有需要用到不同於預設的參數設定時,將參數在執行 docker run時,傳進去。

另外 CMD 和 ENTRYPOINT 在不同的語法下,有不同的意義,但我覺得按照我寫的實踐方法時,已經沒有太大的意義去討論不同語法產生不同意義的問題了(其實是我懶得寫了XD)

理解幾個思考點後,官網的解釋其實很簡單可以理解了。

Docker - Understand how cmd and entrypoint interact