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:/#

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM