docker RUN ENTRYPOINT CMD命令

运行时机

RUN在Dockerfile构建镜像的过程(Build)中运行,最终被commit的到镜像.

ENTRYPOINT和CMD在容器运行(run、start)时运行

都有shell和exec形式

shell形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RUN command param1 param2
CMD command param1 param2
ENTRYPOINT command param1 param2
# ENTRYPOINT的Shell格式会忽略任何CMD或docker run提供的参数
#eg
RUN apt-get install python3
ENTRYPOINT echo "Hello world"
CMD echo "Hello world"
ENV name Cloud Man
ENTRYPOINT echo "Hello, $name"
# shell 格式底层会调用 /bin/sh -c <command>
# 所以执行 docker run <image> 将输出
# Hello, Cloud Man

shell形式还有一个严重的问题:由于其默认使用/bin/sh来运行命令,如果镜像中不包含/bin/sh,容器会无法启动.

exec形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RUN ["executable", "param1", "param2"]
ENTRYPOINT ["executable", "param1", "param2"]
CMD ["executable", "param1", "param2"]
#eg
RUN ["apt-get", "install", "python3"]
ENTRYPOINT ["/bin/echo", "Hello world"]
CMD ["/bin/echo", "Hello world"]
ENV name Cloud Man
ENTRYPOINT ["/bin/echo", "Hello, $name"]
# Hello, $name
ENV name Cloud Man
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
# Hello, Cloud Man

CMD还多了一种用于为ENTRYPOINT提供参数的形式:
此时 ENTRYPOINT 必须使用 Exec 格式
参数格式

1
CMD ["param1","param2"]

shell形式和exec的形式的本质区别在于shell形式提供了默认的指令/bin/sh -c,所以其指定的command将在shell的环境下运行.因此指定command的pid将不会是1,因为pid为1的是shell,command进程是shell的子进程.

exec形式则不然,但由于exec指定的命令不由shell启动,因此也就无法使用shell中的环境变量,如$HOME.如果希望能够使用环境变量,可以指定命令为sh:CMD [ “sh”, “-c”, “echo”, “$HOME” ]

重载问题

Dockerfile中只有最后一个ENTRYPOINT指令会生效,其他会被重载.

Dockerfile中只有最后一个CMD指令会生效,其他会被重载.

CMD指定的命令可以被docker run传递的命令覆盖.

1
2
3
4
5
6
CMD echo "Hello world"
# 运行容器 docker run -it [image] 将输出:
# Hello world
docker run -it [image] /bin/bash
# CMD 会被忽略掉,命令 bash 将被执行
# root@10a32dc7d3d3:/#

ENTRYPOINT指定的命令不会被docker run传递的命令覆盖.容器名后面的所有内容都当成参数传递给其指定的命令.

1
2
3
4
5
6
7
8
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["echo","world"]
# 当容器通过 docker run -it [image] 启动时,输出为:
# Hello echo world
# 而如果通过 docker run -it [image] CloudMan 启动,则输出为:
# Hello CloudMan

当然,ENTRYPOINT指定的命令并不是不能重载的,只需指定–entrypoint来重载即可.

最佳实践

  1. 使用 RUN 指令安装应用和软件包,构建镜像.

  2. 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令.CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数.

  3. 如果想为容器设置默认的启动命令,可使用 CMD 指令.用户可在 docker run 命令行中替换此默认命令.

    ENTRYPOINT和CMD进行组合,运行shell脚本

    1
    2
    3
    4
    5
    6
    7
    FROM busybox
    MAINTAINER femn
    COPY ./entrypoint.sh /
    RUN chmod +x /entrypoint.sh
    ENTRYPOINT ["/entrypoint.sh"]
    CMD ["echo","CMD"]

entrypoint.sh如下:

1
2
3
4
5
#!/bin/sh
set -e
echo "ENTRYPOINT"
exec "$@"
# 脚本中使用exec "$@"来运行CMD中的命令

运行时则输出 ENTRYPOINT CMD,而运行的参数 都是传递给entrypoint.sh的.

Share Comments