Linux雲端計算教程全套影片合集:CMD指令講解

千鋒雲端計算發表於2020-03-20

Dockerfile 中只能有一條CMD指令。如果列出多個,CMD 則只有最後一個CMD會生效。CMD 主要目的是為執行容器時提供預設值。

Linux雲端計算教程全套影片合集:CMD指令講解

Docker 不是虛擬機器,容器就是程式,CMD 指令就是用於指定預設的容器主程式的啟動命令的。在啟動(執行)一個容器時可以指定新的命令來替代映象設定中的這個預設命令。

可以包含可執行檔案,當然也可以省略。CMD 指令的格式和 RUN 相似,也是兩種格式:

  • shell 格式:CMD <命令>exec 格式:CMD ["可執行檔案", "引數1", "引數2"...]引數列表格式:CMD ["引數1", "引數2"...]。在指定了 ENTRYPOINT 指令後,用 CMD 指定具體的引數。
注意:不要混淆RUN 和 CMD。RUN實際上執行一個命令並提交結果; CMD在構建時不執行任何操作,但指定映象的預設命令。

Linux雲端計算教程全套影片合集:CMD指令講解

插個小訊息,也方便想學習的同學,在文章下方留言即可試聽課程外加領取千鋒HTML5、UI互動設計、PHP、Java+雲資料、大資料開發、VR/AR/Unity遊戲開發、Python人工智慧、Linux雲端計算、全棧軟體測試、網路安全等全部的影片學習教程。

Docker 不是虛擬機器,容器內沒有後臺服務的概念。不要期望這樣啟動一個程式到後臺:

CMD systemctl start nginx

這行被 Docker 理解為:

CMD ["sh" "-c" "systemctl start nginx"]

對於容器而言,其啟動程式就是容器的應用程式,容器就是為了主程式而存在的,主程式退出,容器就失去了存在的意義,從而退出,其它輔助程式不是它需要關心的東西。

就像上面的示例中,主程式是 sh , 那麼當 service nginx start 命令結束後,sh 也就結束了,sh 作為主程式退出了,自然就會使容器退出。

Linux雲端計算教程全套影片合集:CMD指令講解

正確的做法是直接執行 nginx 這個可執行檔案,並且關閉後臺守護的方式,使程式在前臺執行。

CMD ["nginx", "-g", "daemon off;"]

ENTRYPOINT 指令

ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器的啟動程式及引數。

ENTRYPOINT 在執行時也可以被替代,不過比 CMD 要略顯繁瑣,需要透過 docker run 的引數 --entrypoint 來指定。

ENTRYPOINT 的格式和 RUN 指令格式一樣,也分為 exec 格式和 shell 格式。

當指定了 ENTRYPOINT 後,CMD 的含義就發生了改變,不再是直接的執行其命令,而是將 CMD 的內容作為引數傳給 ENTRYPOINT 指令,也就是實際執行時,將變為:

<ENTRYPOINT> "<CMD>"

有了 CMD 後,為什麼還要有 ENTRYPOINT 呢?

這種 <ENTRYPOINT> "<CMD>" 給我們帶來了什麼好處麼?

讓我們來看幾個場景。

  • 場景一:讓映象變成像命令一樣使用

CMD 方式

FROM centos

RUN yum update \

&& yum install -y curl

CMD [ "curl", "-s", " ]

構建映象後, 執行容器

# docker run --rm centos-echo-ip-cmd

執行下面命令會報錯

# docker run --rm centos-echo-ip-cmd -i

我們可以看到報錯,executable file not found。之前我們說過,跟在映象名後面的是 command,執行時會替換 CMD 的預設值。因此這裡的 -i 並不是新增在原來的 curl -s 後面。 而是替換了原來的 CMD,變成了 CMD ["-i"],而 -i 根本不是命令,所以報了可執行檔案找不到。

所以應該使用 ENTRYPOINT 方式

FROM centos

RUN yum install -y curl

ENTRYPOINT ["curl", "-s", "]

再次構建映象後, 執行容器

# docker run --rm centos-echo-ip-entrypoint

# docker run --rm centos-echo-ip-entrypoint -i

這樣的話, 最終的指令就變成 ENTRYPOINT ["curl", "-s", ", "-i"]

  • 場景二:應用執行前的準備工作

啟動容器就是啟動主程式,但有些時候,啟動主程式前,需要一些準備工作。

官方映象 redis 中的示例:

FROM alpine:3.4

RUN addgroup -S redis && adduser -S -G redis redis

ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379

CMD [ "redis-server" ]

可以看到其中為 redis 服務建立了 redis 使用者,並在最後指定了 ENTRYPOINT 為 docker-entrypoint.sh 指令碼。

#!/bin/sh

# allow the container to be started with `--user`

if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then

chown -R redis .

exec gosu redis "$0" "$@"

fi

exec "$@"

該指令碼的內容就是根據 CMD 的內容來判斷,如果是 redis-server 的話,則切換到 redis 使用者身份啟動伺服器,否則依舊使用 root 身份執行。比如:

$ docker run -it redis id

uid=0(root) gid=0(root) groups=0(root)

還有 ENTRYPOINT 指令不會被 RUN 指令覆蓋,而 CMD 指令會被 RUN 指令覆蓋。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69916964/viewspace-2681727/,如需轉載,請註明出處,否則將追究法律責任。

相關文章