Dockerfile文件ENTRYPOINT指令和 CMD 一樣,都是在指定容器啟動程序及參數。ENTRYPOINT 在運行時也可以替代,不過比 CMD 要略顯繁瑣,需要通過 docker run 的參數 --entrypoint 來指定。
當指定了 ENTRYPOINT 后,CMD 的含義就發生了改變,不再是直接的運行其命令,而是將 CMD 的內容作為參數傳給 ENTRYPOINT 指令,換句話說實際執行時,將變為:
ENTRYPOINT "CMD"
ENTRYPOINT的使用場景:讓鏡像變成像命令一樣使用
假設我們需要一個得知自己當前公網 IP 的鏡像,那么可以先用 CMD 來實現:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "http://ip.cn" ]
假如我們使用 docker build -t myip . 來構建鏡像的話,如果我們需要查詢當前公網 IP,只需要執行:
$ docker run myip
上面的 CMD 中可以看到實質的命令是 curl,那么如果我們希望顯示 HTTP 頭信息,就需要加上 -i 參數。但當我們加上-i參數就會報executable file not found的錯誤,這是因為跟在鏡像名后面的是 command,運行時會替換 CMD 的默認值。因此這里的 -i 替換了原來的 CMD,而不是添加在原來的 curl -s http://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。
如果我們希望加入 -i 這參數,我們就必須重新完整的輸入這個命令:
$ docker run myip curl -s http://ip.cn -i
使用ENTRYPOINT 就是一個很好的解決方案,使用命令如下:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
ENTRYPOINT的使用場景:應用運行前的準備工作
啟動容器就是啟動主進程,但有些時候,啟動主進程前,需要一些準備工作。
比如 mysql 類的數據庫,可能需要一些數據庫配置、初始化的工作,這些工作要在最終的 mysql 服務器運行之前解決。
此外,可能希望避免使用 root 用戶去啟動服務,從而提高安全性,而在啟動服務前還需要以 root 身份執行一些必要的準備工作,最后切換到服務用戶身份啟動服務。或者除了服務外,其它命令依舊可以使用 root 身份執行,方便調試等。
這些準備工作是和容器 CMD 無關的,無論 CMD 為什么,都需要事先進行一個預處理的工作。這種情況下,可以寫一個腳本,然后放入 ENTRYPOINT 中去執行,而這個腳本會將接到的參數(也就是)作為命令,在腳本最后執行。比如官方鏡像 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 腳本。








