Docker

Dockerfile的ENTRYPOINT和CMD

2018-12-29  本文已影响0人  CodingCode

Dockerfile的ENTRYPOINT和CMD都是用来定义命令的执行入口。

  1. 定义ENTRYPOINT
$ cat Dockerfile 
FROM oraclelinux
ADD ./docker-entry.sh   /docker-entry.sh
ENTRYPOINT /docker-entry.sh

$ cat docker-entry.sh
#!/usr/bin/env bash
echo "Entry of ENTRYPOINT, ARGS[#]=$#"
for ((i = 0; i <= $#; i++ )); do
  echo "ENTRYPOINT ARGS[${i}]=[${!i}]"
done

$ docker build -t testimage

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=0

在docker run的时候ENTRYPOINT指定的命令被调用了。

  1. 定义CMD
$ cat Dockerfile 
FROM oraclelinux
ADD ./docker-cmd.sh   /docker-cmd.sh
CMD /docker-cmd.sh

$ cat docker-cmd.sh
#!/usr/bin/env bash
echo "Entry of CMD, ARGS[#]=$#"
for ((i = 0; i <= $#; i++ )); do
  echo "CMD ARGS[${i}]=[${!i}]"
done

$ docker build -t testimage

$ docker run --rm testimage
Entry of CMD, ARGS[#]=0

这里看起来,ENTRYPOINT和CMD的行为是一样的,没有啥区分。

  1. 同时定义ENTRYPOINT和CMD
$ cat Dockerfile 
FROM oraclelinux
ADD ./docker-cmd.sh   /docker-cmd.sh
ADD ./docker-entry.sh   /docker-entry.sh
CMD        /docker-cmd.sh
ENTRYPOINT /docker-entry.sh

$ docker build -t testimage

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=0
  1. ENTRYPOINT和CMD的两种写法

4.1 SHELL
格式:<ENTRYPOINT|CMD> executable param1 param2 ...
4.2 EXEC
格式:<ENTRYPOINT|CMD> ["executable", "param1", "param2", ...]

  1. 使用EXEC的方式重新执行上面三个case

5.1 定义ENTRYPOINT

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=0

5.2 定义CMD

$ docker run --rm testimage
Entry of CMD, ARGS[#]=0

5.3 同时定义ENTRYPOINT和CMD

Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[/docker-cmd.sh]

看到没有5.3这里和前面使用SHELL格式的有重大不一样,CMD的内容被作为参数传递给了ENTRYPOINT,虽然目前ENTRYPOINT没有用到,但是我们知道就可以用了。

  1. 使用run自带命令

6.1 ENTRYPOINT + SHELL格式

$ docker run --rm testimage date
Entry of ENTRYPOINT, ARGS[#]=0
ENTRYPOINT ARGS[0]=[/docker-entry.sh]

6.2 CMD + SHELL格式

$ docker run --rm testimage date
Sun Dec 30 04:44:33 UTC 2018

6.3 ENTRYPOINT + CMD + SHELL格式

$ docker run --rm testimage date
Entry of ENTRYPOINT, ARGS[#]=0
ENTRYPOINT ARGS[0]=[/docker-entry.sh]

6.4 ENTRYPOINT + EXEC格式

$ docker run --rm testimage date
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[date]

6.5 CMD + EXEC格式

$ docker run --rm testimage date
Sun Dec 30 04:47:12 UTC 2018

6.6 ENTRYPOINT + CMD + EXEC格式

$ docker run --rm testimage date
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[date]
  1. 总结

7.1. ENTRYPOINT和CMD都可以用来指定容器的入口命令。
7.2 ENTRYPOINT具有优先权

7.3 在EXEC模式下,CMD会被作为ARG[1]传递给ENTRYPOINT

7.3 docker run的时候如果后面指定命令,那么这个命令是CMD的替换。

7.4 因此建议ENTRYPOINT和CMD均采用EXEC的调用方式

完整例子:

$ cat Dockerfile
FROM oraclelinux

ADD ./docker-cmd.sh     /docker-cmd.sh
ADD ./docker-entry.sh   /docker-entry.sh

ENTRYPOINT  [ "/docker-entry.sh" ]
CMD         [ "/docker-cmd.sh" ]

$ docker build . -t testimage

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[/docker-cmd.sh]
$@=[/docker-cmd.sh]
Entry of CMD, ARGS[#]=0
CMD ARGS[0]=[/docker-cmd.sh]

$ docker run --rm testimage date
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[date]
$@=[date]
Sun Dec 30 05:03:34 UTC 2018

$ docker run --rm testimage date "+%s"
Entry of ENTRYPOINT, ARGS[#]=2
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[date]
ENTRYPOINT ARGS[2]=[+%s]
$@=[date +%s]
1546146222
  1. EXEC模式的缺陷

8.1 EXEC不能使用环境变量

例如在SHELL模式下:

$ cat Dockerfile
FROM oraclelinux

ADD ./docker-entry.sh   /docker-entry.sh

ENV VAR Hello

ENTRYPOINT  "/docker-entry.sh" "${VAR}"

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[Hello]
$@=[Hello]

而同样的功能如果在EXEC模式下:

$ cat Dockerfile
FROM oraclelinux

ADD ./docker-entry.sh   /docker-entry.sh

ENV VAR Hello

ENTRYPOINT  [ "/docker-entry.sh", "${VAR}" ]

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[${VAR}]
$@=[${VAR}]

这个环境变量$VAR没有被替换掉,而是源文本的方式穿下去了。

解决这个问题的办法使用"bash -c"来调用ENTRYPOINT指令:

$ cat Dockerfile
FROM oraclelinux

ADD ./docker-entry.sh   /docker-entry.sh

ENV VAR Hello

ENTRYPOINT  [ "/bin/bash", "-c", "/docker-entry.sh ${VAR}" ]

$ docker run --rm testimage
Entry of ENTRYPOINT, ARGS[#]=1
ENTRYPOINT ARGS[0]=[/docker-entry.sh]
ENTRYPOINT ARGS[1]=[Hello]
$@=[Hello]
上一篇下一篇

猜你喜欢

热点阅读