Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 来快速创建自定义的镜像。

1. 基本结构

Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。一般而言,Dockerfile,分为四部分:

  • 基础镜像信息;
  • 维护者信息;
  • 镜像操作指令;
  • 和容器启动时执行指令;

如下示例

# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx

其中,一开始必须指明所基于的镜像名称,接下来一般是说明维护者信息。后面则是镜像操作指令,例如 RUN 指令,RUN 指令将对镜像执行跟随的命令。每运行一条 RUN 指令,镜像就添加新的一层,并提交。最后是 CMD 指令,用来指定运行容器时的操作命令。

2. 指令说明

指令 说明
FROM 指定所创建镜像的基础镜像
MAINTAINER 指定维护者信息
RUN 运行命令
CMD 指定容器启动时默认执行的命令
LABEL 指定生成镜像的元数据标签信息
EXPOSE 声明镜像内服务所监听的端口
ENV 指定环境变量
ADD 复制指定的 路径下的内容到容器中的 路径下, 可以为 URL;如果为 tar 文件,会自动解压到 路径下
COPY 复制本地主机的 路径下的内容到镜像中的 路径下;一般情况下推荐使用 COPY 而不是 ADD
ENTRYPOINT 指定镜像的默认入口
VOLUME 创建数据卷挂载点
WORKDIR 配置工作目录
ARG 指定镜像内使用的参数 (例如版本号信息等)
ONBUILD 配置当所创建的镜像作为其它镜像的基础镜像时,所执行的创建操作指令
STOPSIGNAL 容器退出的信号值
HEALTHCHECK 如何进行健康检查
SHELL 指定使用 shell 时的默认 shell 类型

下面具体介绍各个指令

2.1 FROM

指定所创建镜像的基础镜像,如果本地不存在,则默认会去 Docker Hub 下载指定镜像。格式为

FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]

任何 Dockerfile 中的第一条指令必须为 FROM 指令。并且,如果在同一个 Dockerfile 中创建多个镜像,可以使用多个 FROM 指令(每个镜像一次)。

2.2 MAINTAINER

指定维护者信息,格式为

MAINTAINER <name> <email>

例如:

MAINTAINER image_creator@docker.com

该信息会写入生成镜像的 Author 属性域中。

2.3 RUN

RUN 指令在新镜像内部执行的命令,如:执行某些动作、安装系统软件、配置系统信息之类。格式为

RUN <command>
或
RUN ["executable","param1","param2"]

注意,后一个指令会被解析为 Json 数组,因此必须用双引号。前者默认将在 shell 终端中运行命令,即 /bin/sh -c ;后者则使用 exec 执行,不会启动 shell 环境。

指定使用其他终端类型可以通过第二种方式实现,例如

RUN ["/bin/bash","-c","echo hello"]

每条 RUN 指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。例如:

RUN apt-get update \&& apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \&& rm -rf /var/cache/apt

注:多行命令不要写多个 RUN ,原因是 Dockerfile 中每一个指令都会建立一层,多少个 RUN 就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

2.4 CMD

CMD 指令用来指定启动容器时默认执行的命令。它支持三种格式:

  • CMD["executable","param1","param2"] 使用 exec 执行,是推荐使用的方式;
  • CMD command param1 param2/bin/sh 中执行,提供给需要交互的应用;
  • CMD["param1","param2"] 提供给 ENTRYPOINT 的默认参数。

每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时手动指定了运行的命令(作为 run 的参数),则会覆盖掉 CMD 指定的命令。

如容器启动时进入 bash

CMD /bin/bash

或者可以用 exec 写法

CMD ["/bin/bash"]

ENTRYPOINTCMD 同时给出时,CMD 中的内容会作为 ENTRYPOINT 定义命令的参数,最终执行容器启动的还是 ENTRYPOINT 中给出的命令。

2.5 LABEL

LABEL 指令用来指定生成镜像的元数据标签信息。格式为:

LABEL <key>=<value><key>=<value><key>=<value>...

例如:

LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."

2.6 EXPOSE

声明镜像内服务所监听的端口。EXPOSE 命名适用于设置容器对外映射的容器端口号,格式为

EXPOSE <port>[<port>...]

例如:

EXPOSE 22 80 8443

注意,该指令只是起到声明作用,并不会自动完成端口映射。

在启动容器时需要使用 -PDocker 主机会自动分配一个宿主机的临时端口转发到指定的端口;使用 -p,则可以具体指定哪个宿主机的本地端口会映射过来。

Tomcat 容器内使用的端口 8081,则用 EXPOSE 命令可以告诉外界该容器的 8081 端口对外,在构建镜像时用 Docker run -p 可以设置暴露的端口对宿主机器端口的映射。

EXPOSE 8081

EXPOSE 8081 其实等价于 Docker run -p 8081 当需要把 8081 端口映射到宿主机中的某个端口(如8888)以便外界访问时,则可以用 Docker run -p 8888:8081

2.7 ENV

指定环境变量,在镜像生成过程中会被后续 RUN 指令使用,在镜像启动的容器中也会存在。ENV 命名用于设置容器的环境变量,这些变量以 key=value 的形式存在,在容器内被脚本或者程序调用,容器运行的时候这个变量也会保留。格式为

ENV <key>  <value>
或
ENV <key>=<value>...

例如:

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
postgress && ...
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

指令指定的环境变量在运行时可以被覆盖掉,如

docker run --env <key>=<value> built_image

在使用 ENV 设置环境变量时,有几点需要注意:

具有传递性,也就是当前镜像被用作其它镜像的基础镜像时,新镜像会拥有当前这个基础镜像所有的环境变量;

ENV 定义的环境变量,可以在 Dockerfile 被后面的所有指令( CMD 除外)中使用,但不能被 Docker run 的命令参数引用 。 如:

ENV Tomcat_home_name Tomcat_7
RUN mkdir $Tomcat_home_name

除了 ENV 之外,docker run -e 也可以设置环境变量传入容器内。

docker run -d Tomcat -e "Tomcat_home_name=Tomcat_7"

这样我们进入容器内部用 ENV 可以看到 Tomcat_home_name 这个环境变量。

通过 ENV 指令和 ARG 指令所定义的参数,在使用时都是采用 $ + NAME 这种形式来占位的,所以它们之间的定义就存在冲突的可能性。对于这种场景,大家只需要记住,ENV 指令所定义的变量,永远会覆盖 ARG 所定义的变量,即使它们定时的顺序是相反的。

2.8 ADD

作用和使用方法和 COPY 一样。该命令将复制指定的 src 路径下的内容到容器中的 dest 路径下。格式为

ADD <src> <dest>

其中

  • src 可以是 Dockerfile 所在目录的一个相对路径(文件或目录),也可以是一个 URL ,还可以是一个 tar 文件(如果为 tar 文件,会自动解压到 dest 路径下)。
  • dest 可以是镜像内的绝对路径,或者相对于工作目录( WORKDIR )的相对路径。路径支持正则格式,例如:
ADD *.c /code/

2.9 COPY

COPY 命令用于将宿主机器上的的文件复制到镜像内,如果目的位置不存在,Docker 会自动创建。但宿主机器用要复制的目录必须是和 Dockerfile 文件同级目录下。 格式为

COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

复制本地主机的 src (为 Dockerfile 所在目录的相对路径、文件或目录)下的内容到镜像中的 dest 下。目标路径不存在时,会自动创建。路径同样支持正则格式。当使用本地目录为源目录时,推荐使用COPY

COPY 命令和 ADD 类似,唯一的不同是 ADD 会自动解压压缩包,还可以直接下载 url 中的文件但是官方建义使用 wget 或者 curl 代替 ADD

# 拷贝并解压
ADD nickdir.tar.gz .
# 仅拷贝
ADD https://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

应该改成这样子

RUN mkdir -p /usr/src/things \
&& curl -SL https://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all

2.10 ENTRYPOINT

指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。支持两种格式:

ENTRYPOINT ["executable", "param1", "param2"](exec调用执行)
ENTRYPOINT command param1 param2(shell中执行)

此时,CMD 指令指定值将作为根命令的参数。每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个有效。在运行时,可以被 --entrypoint 参数覆盖掉,如 docker run--entrypoint

ENTRYPOINT 的作用和用法和 CMD 一模一样,但是 ENTRYPOINT 有和 CMD 有 2 处不一样:

  • CMD 的命令会被 Docker run 的命令覆盖而 ENTRYPOINT 不会;
  • CMDENTRYPOINT 都存在时,CMD 的指令变成了 ENTRYPOINT 的参数,并且此 CMD 提供的参数会被 Docker run 后面的命令覆盖;

CMDENTRYPOINT 命令相同点:

  1. 为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束,所以如果想要容器长期运行就让这个命令指定的命令长期运行。
  2. CMD 指令,仅最后一个生效。

CMDENTRYPOINT 命令不同点:

  1. CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖,但 ENTRYPOINT 不会。

命令加参数的形式

ENTRYPOINT [ "echo", "a" ]
$ docker run  test
a

加参数,但是不会替换

ENTRYPOINT [ "echo", "a" ]
$ docker run  test b
a b

CMDENTRYPOINT 提供默认参数

ENTRYPOINT [ "echo", "a" ]
CMD ["b"]
$ docker run  test
a b

加参数 c 会替换 CMD 提供的参数

ENTRYPOINT [ "echo", "a" ]
CMD ["b"]
$ docker run  test c
a c

ENTRYPOINTCMD 的组合示例:

2.11 VOLUME

创建一个数据卷挂载点。格式为

VOLUME ["/data"]

可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。VOLUME 用来创建一个可以从本地主机或其他容器挂载的挂载点。

但使用数据卷需要我们在创建容器时通过 -v 选项来定义,而有时候由于镜像的使用者对镜像了解程度不高,会漏掉数据卷的创建,从而引起不必要的麻烦。

VOLUME 指令中定义的目录,在基于新镜像创建容器时,会自动建立为数据卷,不需要我们再单独使用 -v 选项来配置了。

例如我们知道 TomcatWebapps 目录是放 Web 应用程序代码的地方,此时我们要把 Webapps 目录挂载为匿名卷,这样任何写入 Webapps 中的心都不会被记录到容器的存储层,让容器存储层无状态化。

如创建 TomcatWebapps 目录的一个挂载点

 VOLUME /usr/local/Tomcat/Webapps

这样,在运行容器时,也可以用过 Docker run -v 来把匿名挂载点挂载都宿主机器上的某个目录,如

docker run -d -v /home/Tomcat_Webapps:/usr/local/Tomcat/Webapps

2.12 USER

指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。需要注意的是这个用户必须是已经存在,否则无法指定。格式为

USER daemon

当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户。例如:

RUN groupadd -r postgres && useradd -r -g postgres postgres

要临时获取管理员权限可以使用 gosu 或 sudo 。

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。 WORKDIR 是改变工作目录, USER 则是改变之后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。 注意, USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu 。

# 建立 redis 用户,并使用 gosu 换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis
# 下载 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.12/gosu-amd64" \&& chmod +x /usr/local/bin/gosu \&& gosu nobody true
# 设置 CMD,并以另外的用户执行
CMD [ "exec", "gosu", "redis", "redis-server" ]

2.13 WORKDIR

为后续的 RUNCMDENTRYPOINT 指令配置工作目录。其效果类似于 Linux 命名中的 cd 命令,用于目录的切换,但是和 cd 不一样的是:如果切换到的目录不存在,WORKDIR 会为此创建目录。格式为

WORKDIR /path/to/workdir

可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为 /a/b/c

2.14 ARG

指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行 docker build 命令时才以 --build-arg <varname>=<value> 格式传入。格式为

ARG  <name> [=<default value>]

示例

docker build --build-arg <name>=<value> .

来指定参数值。

示例,Dockefile 文件内容

FROM debian:stretch-slim## ......ARG TOMCAT_MAJOR
ARG TOMCAT_VERSION## ......RUN wget -O tomcat.tar.gz "https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz"## ......

构建命令

$ sudo docker build --build-arg TOMCAT_MAJOR=8 --build-arg TOMCAT_VERSION=8.0.53 -t tomcat:8.0 ./tomcat

2.15 ONBUILD

配置当所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令。意思就是:这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的 ONBUILD 命令。格式为

ONBUILD [INSTRUCTION]

例如,Dockerfile 使用如下的内容创建了镜像 image-A:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像,会自动执行 ONBUILD 指令的内容,等价于在后面添加了两条指令:

FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的镜像,推荐在标签中注明,例如ruby: 1.9-onbuild。

2.16 STOPSIGNAL

指定所创建镜像启动的容器接收退出的信号值。例如:

STOPSIGNAL signal

2.17 HEALTHCHECK

配置所启动容器如何进行健康检查(如何判断健康与否),自 Docker 1.12开始支持。格式有两种:

  • HEALTHCHECK[OPTIONS]CMD command:根据所执行命令返回值是否为 0 来判断。
  • HEALTHCHECK NONE:禁止基础镜像中的健康检查。

OPTION支持:

  • interval=DURATION(默认为:30s):过多久检查一次;
  • timeout=DURATION(默认为:30s):每次检查等待结果的超时;
  • retries=N(默认为:3):如果失败了,重试几次才最终确定失败。

2.18 SHELL

指定其他命令使用 shell 时的默认 shell 类型。默认值为 ["/bin/sh","-c"] 。注意对 于Windows 系统,建议在 Dockerfile 开头添加 #escape=` 来指定转义信息。

3. 创建镜像

编写完成 Dockerfile 之后,可以通过 docker build 命令来创建镜像。

基本的格式为

docker build [OPTIONS] PATH | URL | -

OPTIONS 有很多指令,下面列举几个常用的:

  • --build-arg=[] :设置镜像创建时的变量;
  • -f :指定要使用的 Dockerfile 路径;
  • --force-rm :设置镜像过程中删除中间容器;
  • --rm:设置镜像成功后删除中间容器;
  • --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式。

该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下的所有内容发送给 Docker 服务端,由服务端来创建镜像。因此除非生成镜像需要,否则一般建议放置 Dockerfile 的目录为空目录。

有两点经验:

  • 如果使用非内容路径下的 Dockerfile,可以通过 -f 选项来指向文件系统中任何位置的 Dockerfile
docker build -f /path/to/a/Dockerfile .
  • 要指定生成镜像的标签信息,可以使用 -t 选项。例如,指定 Dockerfile 所在路径为 /tmp/docker_builder/,并且希望生成镜像标签为 build_repo:first_image,可以使用下面的命令:
$ docker build -t build_repo:first_image /tmp/docker_builder/

执行命名之后,会看到控制台逐层输出构建内容,直到输出两个 Successfully 即为构建成功。

4.使用.dockerignore文件

可以通过 .dockerignore 文件(每一行添加一条匹配模式)来让 Docker 忽略匹配模式路径下的目录和文件。例如:

# comment
*/temp*
*/*/temp*
tmp?

Docker 入门系列(7)- Dockerfile 使用(FROM、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、WORKDIR)相关推荐

  1. Docker入门系列之二:使用dockerfile制作包含指定web应用的镜像

    2019独角兽企业重金招聘Python工程师标准>>> 在前一篇文章:Docker入门系列之一:在一个Docker容器里运行指定的web应用 里, 我们已经成功地将我们在本地开发的一 ...

  2. Docker入门系列之三:如何将dockerfile制作好的镜像发布到Docker hub上

    这个系列的前两篇文章,我们已经把我们的应用成功地在Docker里通过nginx运行了起来,并且用dockerfile里制作好了一个镜像. Docker入门系列之一:在一个Docker容器里运行指定的w ...

  3. Docker入门系列(一):目标和安排

    Docker入门系列(一) 这个系列的教程来源于docker的官方文档,此文档的目的在于一步一步学习docker的使用方法. 这一系列的教程有如下几篇文档: docker安装启动 构建第一个docke ...

  4. Docker 入门系列(2)- Docker 镜像, 免 sudo 使用 docker 命令、获取查看、修改镜像标签、查找删除创建镜像、导入导出镜像

    1. 免 sudo 使用 docker 命令 如果还没有 docker group 就添加一个 sudo groupadd docker 将用户加入该 group 内 sudo gpasswd -a ...

  5. OllyDBG 入门系列5 消息断点及 RUN 跟踪

    标 题: [原创]OllyDBG 入门系列(五)-消息断点及 RUN 跟踪 作 者: CCDebuger 时 间: 2006-02-19,16:02:46 链 接: http://bbs.pediy. ...

  6. Marco's Java【Docker入门(四) 之 Dockerfile容器数据卷详解】

    前言 咱们上节已经接触过Dockerfile并使用Dockerfile创建容器数据卷,但是Dockerfile的作用远远不止如此! 因此本节会更深入的了解Dockerfile以及它的诸多使用方式, & ...

  7. Docker入门系列之一:在一个Docker容器里运行指定的web应用

    实现题目描述的这个需求有很多种办法,作为入门,让我们从最简单的办法开始. 首先使用命令docker ps确保当前没有正在运行的Docker实例. 运行命令docker run -it nginx: 然 ...

  8. Docker 入门系列(6)- Docker 互联

    容器互联机制 容器的互联 (linking) 是一种让多个容器中应用进行快速交互的方式.它会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的 IP 地址. 1. ...

  9. Docker 入门系列(5)- Docker 端口映射(映射所有IP地址、映射到指定地址和指定端口、映射指定地址任意端口、查看映射端口配置)

    端口映射 映射容器内应用的服务端口到本地宿主主机 1. 从外部访问容器应用 在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的.当容器中运行一些网络应用,要 ...

最新文章

  1. LeetCode实战:二叉搜索树中第K小的元素
  2. CSS属性:font-family
  3. Spring学习手册番外:context:annotation-config/ 和 mvc:annotation-driven / 的区别
  4. AngularJS进阶学习
  5. JZOJ 3769. 【NOI2015模拟8.14】A+B
  6. 7-66 计算工资 (15 分)
  7. MySQL【第三篇】数据类型
  8. 在线文本行固定长度填充工具
  9. AngularJS指令范围中的#39;@#39;和#39;=#39;有什么区别?
  10. okvis odometry的安装与运行
  11. ACL'21 | 对比学习论文一句话总结
  12. 托管代码 非托管代码
  13. 算法设计与分析学习总结
  14. Xposed框架未安装解决方法
  15. 计算机word基础操作知识点,计算机WORD知识点整理
  16. WIN10外接显示器有妙招
  17. 趋势杀毒曝远程执行漏洞 可盗取用户所有密码
  18. 阿里巴巴校园招聘在线面试之附加题
  19. 洛谷P1200你的飞船在这
  20. net start mysql:无法启动

热门文章

  1. vue-devTools插件安装流程
  2. 每个年龄段,都有每个年龄段的“好”
  3. pandas数据框,统计某列或者某行数据元素的个数
  4. Pytorch | BERT模型实现,提供转换脚本【横扫NLP】
  5. MindSpore张量mindspore::tensor
  6. 稀疏性如何为AI推理增加难度
  7. NVIDIA Turing Architecture架构设计(下)
  8. NVIDIA Turing Architecture架构设计(上)
  9. YOLO v1到YOLO v4(下)
  10. 操作系统常用词典(三)