2 「系统架构」如何使用Dockerfile制作Docker容器?


2 「系统架构」如何使用Dockerfile制作Docker容器?

文章插图
 
接着文章「系统架构」如何使用Dockerfile制作Docker容器?(1)我们继续介绍ENV、ARG、VOLUME、EXPOSE、WORKDIR、USER、HEALTHCHECK、ONBUILD几个命令 。
7、ENV
这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量 。
它的格式有两种:
  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...
ENV NODE_VERSION 7.2.0RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc&& grep " node-v$NODE_VERSION-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c -&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt&& ln -s /usr/local/bin/node /usr/local/bin/nodejsADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD等命令都支持环境变量展开 。
8、ARG
和ENV命令一样,ARG命令也是设置环境变量 。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的 。但是不要因此就使用 ARG 保存密码之类的信息,因为 Docker history 还是可以看到所有值的 。
ARG的格式为:ARG <参数名>[=<默认值>]
Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值 。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖 。
在 1.13 之前的版本,要求 --build-arg 中的参数名,必须在 Dockerfile 中用 ARG 定义过了,换句话说,就是 --build-arg 指定的参数,必须在 Dockerfile 中使用了 。如果对应参数没有被使用,则会报错退出构建 。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建 。这对于使用 CI 系统,用同样的构建流程构建不同的 Dockerfile 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改 。
9、VOLUME
此命令用来定义匿名卷 。之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中 。
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据 。
它的格式为:
  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>
VOLUME /data这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化 。当然,运行时可以覆盖这个挂载设置 。比如:
docker run -d -v mydata:/data xxxx在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置 。
10、EXPOSE
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务 。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口 。
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来 。-p是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射 。
11、WORKDIR
WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录 。
之前提到一些初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:
RUN cd /AppRUN echo "hello" > world.txt如果将这个 Dockerfile 进行构建镜像运行后,会发现找不到 /app/world.txt 文件,或者其内容不是 hello 。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile 中,这两行 RUN 命令的执行环境根本不同,是两个完全不同的容器 。这就是对 Dockerfile 构建分层存储的概念不了解所导致的错误 。


推荐阅读