ENTRYPOINT vs CMD

其实网上已经有许多关于entrypoint与cmd的比较介绍了, 英文中我主要参考了官方文档解释docker-run-vs-cmd-vs-entrypoint.

文档中是这么说的:

1
An ENTRYPOINT allows you to configure a container that will run as an executable.

允许你将容器变成类似可执行文件的运行方式.

1
Command line arguments to docker run <image> will be appended after all elements in an exec form ENTRYPOINT, and will override all elements specified using CMD.

docker run <image>之后的参数都会作为entrypoint的参数并且把CMD命令覆盖掉.

下面将会举几个例子, 其中也会包含一些操作:

只有entrypoint

1
2
3
4
FROM debian:buster-slim
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update && apt-get install -y htop
ENTRYPOINT ["htop"]

可以使用下面两个命令对比下效果

1
2
3
4
docker run -ti test

# 运行的命令应该时`htop -C`
docker run -ti test -C

CMD与entrypoint配合使用

1
2
3
4
5
FROM debian:buster-slim
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update && apt-get install -y htop
ENTRYPOINT ["htop"]
CMD ["-C"]

直接运行该容器, 效果其实是和htop -C一样的.

1
docker run -ti test

当然也有人这样用:

1
2
ENTRYPOINT ["echo", "hello"]
CMD ["world"]

当然会得到hello world这样的结果, 你可以理解为ENTRYPOINTCMD共同组成了一条命令, 我们在使用docker run时, 镜像名后面的会被认为是CMD并将Dockerfile中的默认CMD替换掉.

那么, 现在就有一个问题了, 怎么替换entrypoint呢?

启动时替换entrypoint

答案是--entrypoint参数, 注意写在镜像名称前面, 写在后面会被当成是CMD.

1
docker run -ti --entrypoint=/bin/bash <image>

一般什么时候会替换CMD或是ENTRYPOINT呢?

这样的用法一般用于调试镜像.

  1. 编写完Dockerfile后, 无法确定自己的entrypoint与cmd命令正确与否

  2. 对于某些无法直接运行的镜像, 需要hack进入镜像, 然后手动的执行命令, 相比于 看日志, 这个应该调试起来更快.

一个比较简单的ENTRYPOINT写法

从上面的描述中已经可以看出, Docker默认的运行方式是依靠ENTRYPOINT与CMD结合使用的. 所以我们在编写ENTRYPOINT时, 顺便考虑一下CMD的运行可能更好.

下面是我常用的一个entrypoint.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

set -e

DATA_DIR=/home/data

# Make sure the dir has been mounted.
[ -d "$DATA_DIR" ] || exit 1

# make sure the dir will create.
mkdir -pv $DATA_DIR/{log,run,scripts}
chown -R corvo:corvo $DATA_DIR

exec "$@"

这个entrypoint.sh主要用于在运行时确保某个目录被挂载, 而后的exec "$@"会直接运行CMD.