Docker 中 CMD 和 ENTRYPOINT 的區別

Isaac Tony 2023年1月30日
  1. Docker 中的 CMD 命令
  2. Docker 中的 ENTRYPOINT 命令
  3. まとめ
Docker 中 CMD 和 ENTRYPOINT 的區別

在不同環境中管理軟體和依賴項時,Docker 容器已成為標準。在使用實際應用程式時,你需要在構建應用程式容器映像之前建立一個 docker 檔案。

docker 檔案只是一個只讀文字文件,其中包含一組在組裝映象時將呼叫的指令。這些命令包括 RUNCMDENTRYPOINT

在本文中,我們將討論這些命令的用法。大多數可能處於學習 docker 初始階段的開發人員傾向於交替使用這些命令,這可能會給你帶來一些問題。

Docker 中的 CMD 命令

此命令指定執行 docker RUN 命令時執行的指令。但是,這需要在不指定任何引數的情況下執行 docker RUN 命令。

指定引數時,此命令將被覆蓋。另一方面,如果沒有指定命令列引數,則執行 CMD 命令。

CMD 命令對於你的 docker 容器正常執行不是必需的,因為 ECHO 命令可以在執行時用於相同目的。但是,當每次容器啟動時執行可執行檔案時,CMD 命令會很方便。

為了演示如何使用 CMD 命令在執行時執行可執行檔案,我們將建立一個簡單的 docker 容器,其中包含一個列印出訊息的簡單 Flask 程式。請注意,這可以用任何語言複製,不一定是 Python。

我們將從建立我們的主應用程式開始,它應該如下所示那樣簡單。

from flask import Flask

app = Flask(__name__)


def hello():
    print("Hello, this is a simple Flask application")


hello()

在同一個資料夾中,我們將使用命令 touch Dockerfile 建立我們的 Dockerfile。

Dockerfile 只指定了基礎映象、工作目錄和應該安裝的包。

在最後一行,你應該注意 CMD 命令。在這種情況下,我們使用 CMD 命令在容器啟動時執行 app.py 檔案。

#  base image
FROM python

# Set your working directory
WORKDIR /var/www/

# Copy the necessary files
COPY ./app.py /var/www/app.py
COPY ./requirements.txt /var/www/requirements.txt

# Install the necessary packages
RUN pip install -r /var/www/requirements.txt

# Run the app
CMD python3 app.py

requirements.txt 應如下所示。

click==8.0.4
Flask==2.0.3
gunicorn==20.1.0
itsdangerous==2.1.0
Jinja2==3.0.3
MarkupSafe==2.1.0
Werkzeug==2.0.3

現在我們已經準備好了一切,我們現在可以繼續構建 docker 映象了。在此之前,我們需要確保我們位於儲存程式的同一資料夾中。

在我們的例子中,我們將在構建映像之前將 cd 放入 my-app 資料夾,如下所示。

~/my-app$ docker build -t isaactonyloi_image .

輸出:

 => [internal] load build context                                                                                                          0.9s
 => => transferring context: 320B                                                                                                          0.1s
 => [2/5] WORKDIR /var/www/                                                                                                                5.1s
 => [3/5] COPY ./app.py /var/www/app.py                                                                                                    3.2s
 => [4/5] COPY ./requirements.txt /var/www/requirements.txt                                                                                3.2s
 => [5/5] RUN pip install -r /var/www/requirements.txt                                                                                    53.9s
 => exporting to image                                                                                                                     6.9s
 => => exporting layers                                                                                                                    5.8s
 => => writing image sha256:5847e4777754d9d576accd929076bfbee633ca71f049ebe1af6e9bae161f3e96                                               0.1s
 => => naming to docker.io/library/isaactonyloi_image                                                                                      0.2s
isaac@DESKTOP-HV44HT6:~/my-app$

我們已經成功地基於早期的 docker 檔案構建了我們的映象。我們可以在下面驗證。

~/my-app$ docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
isaactonyloi_image   latest    5847e4777754   7 minutes ago   929MB

我們終於可以使用基於此映象的 docker run 命令建立我們的 docker 容器。另外,請注意,我們將在不傳遞任何引數來執行 CMD 命令的情況下執行此操作。

~/my-app$ docker run isaactonyloi_image
Hello, this is a simple Flask application

除此之外,CMD 命令還允許我們建立可以在執行時輕鬆覆蓋的引數。

我們在下面的示例中對 CMD 命令進行了更改。其他檔案保持不變,我們已經重建了一個新映象。

# base image
FROM python

# Set your working directory
WORKDIR /var/www/

# Copy the necessary filesls
COPY ./app.py /var/www/app.py
COPY ./requirements.txt /var/www/requirements.txt

# Install the necessary packages
RUN pip install -r /var/www/requirements.txt

# Run the app
CMD ["echo", "Hello, Developer"]

這是我們根據對 Dockerfile 的更改重建的新映像。

~/my-app$ docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
new_image            latest    73f323be0d2f   25 minutes ago   929MB

在不傳遞任何引數的情況下再次建立新的 docker 容器時,我們應該在 CMD 命令下收到訊息。

isaac@DESKTOP-HV44HT6:~/my-app$ docker run new_image
Hello, Developer

但是,當我們在執行時傳遞引數時,CMD 命令將自動被覆蓋,並且新引數應該優先。因此,它為我們提供了在執行時新增新引數的靈活性,如下所示。

~/my-app$ docker run new_image hostname
da0a832888cb

上面的輸出顯示 CMD 命令沒有被新的主機名引數執行和覆蓋。

Docker 中的 ENTRYPOINT 命令

docker ENTRYPOINT 命令與 CMD 命令有相似之處,但並不完全相同。

當使用 CMD 命令時,我們可以通過在執行時傳遞引數輕鬆地覆蓋它,但 ENTRYPOINT 命令並非如此。

因此,ENTRYPOINT 可用於在執行時不覆蓋入口點指令。

如下所示,我們可以通過簡單地將 Dockerfile 中的 CMD 命令替換為 ENTRYPOINT 命令來探索此命令的工作原理。我們將根據對 docker 檔案的更改構建一個新映象。

isaac@DESKTOP-HV44HT6:~/my-app$ docker build -t tonyloi_newimage .
[+] Building 42.7s (10/10) FINISHED

輸出:

 => [internal] load build definition from Dockerfile                                                                                                                          2.0s
 => => transferring dockerfile: 365B                                                                                                                                          0.7s
 => [internal] load .dockerignore                                                                                                                                             1.6s
 => => transferring context: 2B                                                                                                                                               0.4s
 => [internal] load metadata for docker.io/library/python:latest                                                                                                             35.4s
 => [1/5] FROM docker.io/library/python@sha256:c90e15c86e2ebe71244a2a51bc7f094554422c159ce309a6faadb6debd5a6df0                                                               0.3s
 => [internal] load build context                                                                                                                                             1.2s
 => => transferring context: 63B                                                                                                                                              0.1s
 => CACHED [2/5] WORKDIR /var/www/                                                                                                                                            0.0s
 => CACHED [3/5] COPY ./app.py /var/www/app.py                                                                                                                                0.0s
 => CACHED [4/5] COPY ./requirements.txt /var/www/requirements.txt                                                                                                            0.0s
 => CACHED [5/5] RUN pip install -r /var/www/requirements.txt                                                                                                                 0.0s
 => exporting to image                                                                                                                                                        2.1s
 => => exporting layers                                                                                                                                                       0.0s
 => => writing image sha256:15fb8e4e3ff58ed529b11342bba75b029fd4323beb24aac70ca36b178d04cb34                                                                                  0.2s
 => => naming to docker.io/library/tonyloi_newimage                                                                                                                           0.1s
isaac@DESKTOP-HV44HT6:~/my-app$

此輸出證明我們已成功構建了新映像。現在我們可以基於這個映象建立一個新的 docker 容器。

你可以選擇使用映象名稱或映象 ID 建立容器,這兩者都可以使用 docker images 命令訪問。這也將顯示我們之前建立的映象。

~/my-app$ docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
tonyloi_newimage     latest    15fb8e4e3ff5   48 minutes ago   929MB
new_image            latest    73f323be0d2f   48 minutes ago   929MB
isaactonyloi_image   latest    5847e4777754   48 minutes ago   929MB

如果我們在不新增任何引數的情況下構建 docker 容器,我們應該得到如下輸出。

isaac@DESKTOP-HV44HT6:~/my-app$ docker run tonyloi_newimage
Hello, Developer

如果我們在基於此映象建立另一個容器時嘗試傳遞引數,你會注意到,與 CMD 命令的情況不同,這些新引數不會覆蓋 ENTRYPOINT 命令。

我們可以在下面驗證這一點。

isaac@DESKTOP-HV44HT6:~/my-app$ docker run tonyloi_newimage Welcome to ADC
Hello, Developer Welcome to ADC

まとめ

我們可以說這兩個命令非常相似; 但是,它們的區別在於 CMD 命令可以在執行時被覆蓋,而 ENTRYPOINT 命令不能。

此外,某些情況可能需要同時使用這兩個命令。

作者: Isaac Tony
Isaac Tony avatar Isaac Tony avatar

Isaac Tony is a professional software developer and technical writer fascinated by Tech and productivity. He helps large technical organizations communicate their message clearly through writing.

LinkedIn

相關文章 - Docker Command