docker 容器的一些概念辨析
文章目录
本篇的主要内容是为了澄清 docker 容器的一些容易混淆的概念,主要分两部分,
一是容器端口的publish和expose,二是 Dockerfile 中ENTRYPOINT和CMD的区分。
Expose or Publish
expose的作用是为了容器间通信,也就是说 expose 的端口只能被其他容器访问,但是
不能被 docker 之外访问,而publish的端口即可用于容器间通信也可被外界访问。所以从
逻辑上来说,publish包含了expose。
有这样的区分主要是为了可移植性。我们知道在Dockerfile文件中只有Expose命令,
expose暴露的端口只能用于容器间通信,不会跟主机上的端口冲突。如果在
Dockerfile中加入了publish,在其他的机器上构建时就有可能导致端口冲突。
在命令行里使用这两个参数时,二者是可以混用的,不会冲突。同时指定--expose和
--publish与单独使用--publish的效果一样。
ENTRYPOINT or CMD
Docker 提供了一个默认的ENTRYPOINT:/bin/sh -c,但是没有默认的CMD。比如当我们
在命令行里执行docker run -it ubuntu bash的时候,entrypoint 就是/bin/sh -c,
command 就是bash。
在命令行里,所有镜像名字之后的参数都是作为 command 传给了 entrypoint。在Dockerfile
中,我们可以指定默认的ENTRYPOINT和CMD。比如我们执行docker run -it ubuntu的
时候,效果和docker run -it ubuntu bash是一样的,因为 ubuntu 的 Dockerfile 里指定了
CMD为bash.
二者的分离主要也是应用在 Dockerfile 中,通过灵活的设置,我们可以做出来一些有趣的,
很方便使用的镜像。比如将ENTRYPOINT设为[/bin/cat],那么在执行docker run catimg /etc/password的时候就相当于在执行/bin/cat /etc/password,整个镜像此时变
成了一个二进制程序。这个例子可能显得有点无聊,但是既然任意程序都可以用做
ENTRYPOINT,自然是只有想不到,没有做不到了。如果将一个 redis 镜像的ENTRYPOINT设
为["redis", "-H", "something", "-u", "toto"],那么在执行docker run redisimg get key就相当于docker run redisimg redis -H something -u toto get key,这就是
一个简单明了的 redis 客户端,也不用输那么多参数了。
Dockerfile 中与此相关的命令还有一个RUN,相关细节较为琐碎,下面将详细叙述:
RUN
RUN用来在上一层 layer 的基础上执行一些系统命令并且创建新的一层,可以说是
Dockerfile 中最为常见的命令了,主要有两种形式
RUN <command>通过/bin/sh -c执行RUN ["executable", "param1", "param2"](exec 形式)
exec 形式可以避免 shell 对参数的一些处理并且可以用在一些没有/bin/sh的基本镜像上,
如果想使用别的 shell,也可以使用此种方式,比如RUN ["/bin/bash", "-c", "echo hello"]。
注意事项:
- exec 形式是以 json 数组的形式来解析的,所以各参数必须用双引号
"",不能用单引号''。 - exec 形式下如果不明确制定是不会调用 shell 的,也就意味着一些环境变量是无法解析的,
比如RUN [ "echo", "$HOME" ],如果需要必须自己明确指定所用的 shell
CMD
CMD主要是为容器提供默认的运行程序,有三种形式:
CMD ["executable","param1","param2"](exec 形式)CMD ["param1","param2"](将参数传给ENTRYPOINT)CMD command param1 param2(shell 形式,/bin/sh -c执行)
一个 Dockerfile 中只能有一个CMD,如果指定了多个,只有最后一个起作用。运行时的参
数会覆盖 Dockerfile 中CMD。
注意事项可参考RUN的注意事项
ENTRYPOINT
ENTRYPOINT有两种形式:
ENTRYPOINT ["executable", "param1", "param2"](exec 形式)ENTRYPOINT command param1 param2(shell 形式)
类似于CMD,如果指定了多个ENTRYPOINT,只有最后一个起作用。docker run --entrypoint可覆盖 Dockerfile 中的设置。
exec 形式是最常用的,shell 形式会阻止任何CMD或者run的参数的执行(因为已经在
ENTRYPOINT 中指定了执行程序),但是不能传递信号。
## 参考链接
文章作者 涯余
上次更新 2015-04-16