Dockerfile(9) - ENTRYPOINT 指令詳解

ENTRYPOINT

兩種寫法

# exec 格式
ENTRYPOINT ["executable", "param1", "param2"]

# shell 格式
ENTRYPOINT command param1 param2

 

重點

  • ENTRYPOINT 指定鏡像的默認入口命令,該入口命令會在啓動容器時作爲根命令執行,所有其他傳入值作爲該命令的參數
  • ENTRYPOINT 的值可以通過 docker run --entrypoint 來覆蓋掉
  • 只有 Dockerfile 中的最後一條 ENTRYPOINT 指令會起作用

 

ENTRYPOINT 和 CMD 聯合使用

  • 當指定了 ENTRYPOINT 後,CMD 的含義就發生了改變,不再是直接的運行其命令,而是將 CMD 的內容作爲參數傳給 ENTRYPOINT 指令
  • 換句話說實際執行時,會變成
<ENTRYPOINT> "<CMD>"

 

靈魂拷問

那麼有了 CMD 後,爲什麼還要有 ENTRYPOINT 呢?這種 <ENTRYPOINT> "<CMD>" 有什麼好處麼?

 

CMD 和 ENTRYPOINT 區別

CMD                   # 指定這個容器啓動的時候要運行的命令,不可以追加命令
ENTRYPOINT            # 指定這個容器啓動的時候要運行的命令,可以追加命令

啥意思?這其實也是 ENTRYPOINT 的應用場景之一,下面來看

 

測試 CMD

編寫 dockerfile 文件

FROM centos
CMD ["ls","-a"]    

 

構建鏡像

docker build -f CMD.dockerfile -t test .

 

運行容器

> docker run test
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

 

運行容器並追加命令

> docker run test -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.

 

  • 看到可執行文件找不到的報錯,executable file not found
  • 跟在鏡像名後面的是 command,運行時會替換 CMD 的默認值,因此這裏的 -l 替換了原來的 CMD,而不是追加在原來的 ls -a 後面
  • -l 根本不是命令,所以自然找不到

 

如果想加入 -i 參數,必須重寫 ls 命令

> docker run test ls -a -l
total 56
drwxr-xr-x   1 root root 4096 Oct 28 09:36 .
drwxr-xr-x   1 root root 4096 Oct 28 09:36 ..
-rwxr-xr-x   1 root root    0 Oct 28 09:36 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Oct 28 09:36 dev
drwxr-xr-x   1 root root 4096 Oct 28 09:36 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 221 root root    0 Oct 28 09:36 proc
dr-xr-x---   2 root root 4096 Sep 15 14:17 root
drwxr-xr-x  11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Oct 28 09:36 sys
drwxrwxrwt   7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var

可以了,但這明顯不是最優選擇,ENTRYPOINT 就可以解決這個問題

 

測試 ENTRYPOINT

編寫 dockerfile 文件

FROM centos
ENTRYPOINT ["ls","-a"]    

 

構建鏡像

docker build -f ENTRYPOINT.dockerfile -t test . 

 

運行容器並追加命令

> docker run test -l
total 56
drwxr-xr-x   1 root root 4096 Oct 28 09:38 .
drwxr-xr-x   1 root root 4096 Oct 28 09:38 ..
-rwxr-xr-x   1 root root    0 Oct 28 09:38 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Oct 28 09:38 dev
drwxr-xr-x   1 root root 4096 Oct 28 09:38 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 207 root root    0 Oct 28 09:38 proc
dr-xr-x---   2 root root 4096 Sep 15 14:17 root
drwxr-xr-x  11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Oct 28 09:38 sys
drwxrwxrwt   7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var

 

ENTRYPOINT 的第二個應用場景

  • 啓動容器就是啓動主進程,但啓動主進程,可能需要一些準備工作,比如 mysql 可能需要一些數據庫配置、初始化的工作,這些工作要在最終的 mysql 服務器運行之前解決
  • 還可能希望避免使用 root 用戶去啓動服務,從而提高安全性,而在啓動服務前還需要以 root 身份執行一些必要的準備工作,最後切換到服務用戶身份啓動服務
  • 這些準備工作是和容器 CMD 無關的,無論 CMD 爲什麼,都需要事先進行一個預處理的工作,這種情況下,可以寫一個腳本,然後放入 ENTRYPOINT 中去執行,而這個腳本會將接到的參數(也就是 <CMD>)作爲命令,在腳本最後執行

 

官方鏡像 redis

FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379
CMD [ "redis-server" ]

 

docker-entrypoint.sh 

#!/bin/sh
...
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
    find . \! -user redis -exec chown redis '{}' +
    exec gosu redis "$0" "$@"
fi

exec "$@"

該腳本的內容就是根據 CMD 的內容來判斷,如果是 redis-server 的話,則切換到 redis 用戶身份啓動服務器,否則依舊使用 root 身份執行

[root@poloyy ~]#  docker run -it redis id
uid=0(root) gid=0(root) groups=0(root)

# 直接進入容器內部
[root@poloyy ~]#  docker run -it redis
root@565f89976d63:/#

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章