Linux雲計算教程全套視頻合集:CMD指令講解

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> ""/<entrypoint>

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

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

讓我們來看幾個場景。

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

CMD 方式

FROM centos

RUN yum update \\

&& yum install -y curl

CMD [ "curl", "-s", "http://ip.cn" ]

構建鏡像後, 運行容器

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

執行下面命令會報錯

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

我們可以看到報錯,executable file not found。之前我們說過,跟在鏡像名後面的是 command,運行時會替換 CMD 的默認值。因此這裡的 -i 並不是添加在原來的 curl -s http://ip.cn 後面。 而是替換了原來的 CMD,變成了 CMD ["-i"],而 -i 根本不是命令,所以報了可執行文件找不到。

所以應該使用 ENTRYPOINT 方式

FROM centos

RUN yum install -y curl

ENTRYPOINT ["curl", "-s", "http://ip.cn"]

再次構建鏡像後, 運行容器

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

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

這樣的話, 最終的指令就變成 ENTRYPOINT ["curl", "-s", "http://ip.cn", "-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 指令覆蓋。


分享到:


相關文章: