ENTPYPOINT 入口点
ENTRYOINT
的格式和 RUN
指令格式一样,分为 exec
格式和 shell
格式。
ENTRYPOINT
的目的和 CMD
一样,都是指定容器启动程序及其参数。ENTRYPOINT
在运行时可以替代,不过要比 CMD
略显繁琐,需要通过 docker run
的参数 --entrypoint
来指定。
当指定了 ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行命令,而是将 CMD
的内容作为参数传递给 ENTRYPOITN
指令。实际执行时,将变成:
为什么有了 CMD
后还要有 ENTRYPOINT
呢?ENTRYPOINT
到底有什么好处呢?让我们来看几个场景。
场景一:
假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD
来实现:
假设我们使用 docker build -t myip .
来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:
不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD
总可以看到实质的命令是 curl
,那么如果我们希望显示 HTTP 头信息,就需要加上 -i
参数,那么我们就不能说是在运行镜像的时候添加 -i
参数。
之前我们说过,跟在镜像名后面的是 command
,运行时会替换 CMD
的默认值。因此这里的 -i
替换了原来的 CMD
,所以自然找不到命令。况且 -i
根本就不是一个命令。
那么如果我们希望加入 -i
参数,就只能完整的输入这个命令:
这显然不是一个好的解决方案,因此诞生了 ENTRYPOINT
,使用ENTRYPOINT
就可以很好的解决命令被替换的问题。现在我们重新用 ENTRYPOINT
来实现这个镜像。
再次尝试执行 docker run myip -i
:
可以看到,这次是成功了,因为当 ENTRYPOINT
存在后,CMD
的内容将会作为参数传给 ENTRYPOINT
,而这里的 -i
就是新的 CMD
,因此会作为参数传给 curl
,从而达到预期的效果。
场景二
启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。
比如 mysql
数据库,可能需要一些数据库配置、初始化工作,这些工作需要在 mysql
服务器运行之前处理。
此外,可能希望避免使用 root
用户去启动服务,从而提供安全性,而在启动服务器之前还需要以 root
身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 root
身份,方便调试等。
这些准备工作适合容器 CMD
无关的,无论 CMD
是什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后范围 ENTRYPOINT
中去执行,从而这个脚本会将接收到的参数,作为命令,在脚本最后执行,比如 redis
中就是这么做的。
可以看到其中为了 redis
服务创建了 redis
用户,并在最后指定了 ENTRYPOINT
为 docker-entrypoint.sh
脚本。
该脚本的内容就是根据 CMD
的内容来判断,如果是 redis-server
的话,则切换到 redis
用户身份启动容器,否则依旧使用 root
身份执行。例如:
最后更新于
这有帮助吗?