Hang

docker 容器的一些概念辨析

2015-04-16

本篇的主要内容是为了澄清 docker 容器的一些容易混淆的概念,主要分两部分,
一是容器端口的publishexpose,二是 Dockerfile 中ENTRYPOINTCMD的区分。

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
中,我们可以指定默认的ENTRYPOINTCMD。比如我们执行docker run -it ubuntu
时候,效果和docker run -it ubuntu bash是一样的,因为 ubuntu 的 Dockerfile 里指定了
CMDbash.

二者的分离主要也是应用在 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"]
注意事项:

  1. exec 形式是以 json 数组的形式来解析的,所以各参数必须用双引号"",不能用单引号''
  2. 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 中指定了执行程序),但是不能传递信号。

## 参考链接

  1. Dockerfile Reference
  2. Difference between “expose” and “publish” in docker
  3. What is the difference between CMD and ENTRYPOINT in a Dockerfile?
Tags: docker