• FROM
  • MAINTAINER
  • RUN
  • COPY
  • ADD
  • CMD
  • ENTRYPOINT
  • EXPOSE
  • ENV
  • ARG
  • VOLUME
  • WORKDIR
  • ONBUILD

FROM

  • 说明:FROM,指定镜像构建的基础镜像,每个Dockerfile都必须包含FROM指令,且为第一条指令。
  • 格式:FROM [Image] 或 FROM [Image:tag]
  • 示例:
    • FROM scratch
    • FROM centos:centos7
  • 备注:
    • 官方镜像
    • 空白镜像:scratch
      • scratch: 虚拟的概念,不实际存在;以scratch为基础镜像意味着不以任何镜像为基础,接下来的构建质量将作为镜像的第一层存在。
      • Go 开发的应用通常使用scratch作为基础镜像,go程序包含了运行所需的一切库文件。

MAINTAINER

  • 说明:指定维护者信息
  • 格式:MAINTAINER Name
  • 示例:MAINTAINER zhezh.boy@gmail.com
  • 备注:

RUN

  • 说明:用来执行命令行命令。切记:每一层构建的最后一定要清理掉无关文件。
  • 格式:
    • shell:RUN [Command]
    • exec:RUN [“可执行程序”, “参数”, “参数”]
  • 示例:
    • RUN mkdir -p /home/api/ && \
      touch /home/api/Caddyfile && \
      touch /home/api/Dockerfile
  • 备注:
    • 在linux操作系统上默认 /bin/sh
    • 多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。RUN书写时的换行符是 \
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

COPY

  • 说明:COPY:指令将镜像构建的上下文目录中[源路径]表示的文件或目录拷贝到新一层的镜像的[目标路径]中去。
  • 格式:
    • shell: COPY [源路径] [目标路径]
    • exec: COPY [“源路径”], [“目标路径”]
  • 示例:
    • COPY run.sh /home/api/
  • 备注:
    • 有关 上下文 解释在这里
    • 源路径:可以是多个,也可以是通配符(满足Go的filepath.Match规则)
      • COPY hom* /mydir/
      • COPY hom?.txt /mydir/
    • 目标路径:可以是容器内的绝对路径,也可以是相对于工作目录( WORDDIR 指定工作目录 )的相对路径;目标路径不存在,则创建;COPY会保留源文件属性。
    • Best practices for writing Dockerfiles 中建议尽量使用COPY, 并使用RUN & COPY的组合来代替ADD, 建议只在复制tar文件时使用ADD

ADD

  • 说明:添加文件或文件夹到容器
  • 格式:ADD [src] [dest]
  • 示例:ADD api.tar.gz /home/api/
  • 备注:ADD和COPY类似,区别在于
    • ADD会自动解压文件,而COPY只是文件拷贝
    • 此外ADD的[源路径]可以是URL
1
2
3
FROM scratch
ADD  ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
     ...

CMD

  • 说明:容器 运行时 执行的命令,但是一个Dockerfile中只能有一条CMD命令,多条则执行最后一条CMD命令。
  • 格式:
    • shell:CMD [command] [para1] [para2]
    • exec:CMD [“exec”, “para2”, “para2”]
    • 参数列表:CMD [“参数1”,“参数2”, …]
  • 示例:
    • CMD [“/usr/bin/mongod”, “-f”, “/etc/mongod.conf”]
    • CMD [“C:\MongoDB\bin\mongod.exe”, “-f”, “D:\mgo\conf\mongod.conf”]
    • CMD [“-f”, “/etc/mongod.conf”]
  • 备注:
    • Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的
    • 当 docker run command 的命令匹配到 CMD command 时,会替换CMD执行的命令。
    • 在指令格式上,一般推荐使用 exec 格式,这类格式会被daemon解析为Json数组,因此一定要使用双引号 ", 而不要使用单引号。例如
      • CMD echo $HOME, 在实际执行中会被解析为:
      • CMD [ “sh”, “-c”, “echo $HOME” ]
    • 容器中的应用只有前台执行,容器内没有后台服务的概念;对于容器而言, 其启动程序就是容器运行的主进程,主进程执行完成,容器也就退出了。例如:
      • 容器执行:CMD service mongod start
      • 结果发现:容器执行后立即退出, 甚至systemctl命令根本就不能执行
      • 原因分析:
        • CMD service mongod start 被解析为:
        • CMD [ “sh”, “-c”, “service mongod start” ]
        • 此时,主进程其实为 sh, 当service命令执行完成后,sh也就结束了,即sh作为主进程退出, 随之容器也退出。
    • 正确的做法:直接执行mongod可执行文件,并且要求以前台方式执行。例如
      • CMD [“mongod”, “-f”, “/etc/mongod.conf”]
    • ENTRYPOINT & CMD 同时使用时,可用ENTRYPOINT来执行服务的可执行程序(monogd), CMD来执行服务启动的参数。例如:
      • ENTRYPOINT [“mongod”]
      • CMD [“-f”, “/etc/mongod.conf”]
  • Link

ENTRYPOINT

  • 说明:容器入口点。container 启动时 执行的命令,但是一个Dockerfile中只能有一条ENTRYPOINT命令,多条则只执行最后一条;不可以被容器运行时的命令所覆盖。
  • 格式:
    • exec:ENTRYPOINT [“可执行程序”, “参数1”, “参数2”]
    • shell:ENTRYPOINT [command] [para1] [para2]
  • 示例:
    • ENTRYPOINT [“mongod”, “-f”, “/etc/mongod.conf”]
  • 备注:
    • ENTRYPOINT没有CMD的可替换特性
    • 当指定ENTRYPOINT后,CMD不在执行命令,而是将CMD的内容作为参数传递给ENTRYPOINT指令
    • 可在docker run命令时使用–entrypoint指定(但是只能用写法一)
    • ENTRYPOINT有两种写法,第二种(shell form)会屏蔽掉docker run时后面加的命令和CMD里的参数

EXPOSE

  • 说明:暴露容器的端口
  • 格式:EXPOSE [port] [port]…
  • 示例:EXPOSE 80
  • 备注:Docker中有两种暴露端口方式:
    • EXPOSE: 隐式暴露,只在Dockerfile中出现,所暴露的端口只是被其他容器使用(Docker容器内部使用)
    • PUBLISH:显示暴露,供外部网络使用;PUBLISH只是一个概念,在Dockerfile中没有具体指令,是通过docker run 的参数 -p 或 -P,或者docker-compose中的ports来体现的
    • -P:自动映射,
    • -p:固定映射,格式:-p 宿主端口:容器端口

ENV

  • 说明:设置环境变量
  • 格式:
    • ENV [key] [value]
    • ENV [“key1=value1”] [“key2=value2”]
  • 示例:
    • ENV APIVersion=1.0 APIHome=/home/api/
  • 备注:ENV设置的环境变量和Shell中的用法一样,通过 $APIVersion 获取值

ARG

  • 说明:设置 docker build 时的参数
  • 格式:ARG [参数名] [=默认值]
  • 示例:ARG user=boyzhe
  • 备注:
    • ARG 命令设置的环境变量只在build时有效,在容器运行时是不会存在这些变量的
    • ARG 指令是定义参数名称,以及默认值;该默认值在build时可通过 –build-arg <参数名>=<参数值>来覆盖
    • 如果在build镜像时指定了一个在Dockerfile中不存在的 ARG 参数,则会出现一个Warning.

VOLUME

  • 说明:创建挂载点,可用来让其他容器挂载以实现数据共享或对容器数据的备份、恢复或迁移
  • 格式:
    • VOLUME [path]
    • VOLUME [“path1”, “path2”…]
  • 示例:
    • VOLUME /home/mongo/data /home/mongo/log
  • 备注:
    • 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失, 所以当数据需要持久化时用这个命令。
  • Dockerfile中使用VOLUME挂载目录和docker run时通过-v参数指定的挂载目录有何不同?
    • 主要的不同点就是docker run的-v参数可以指定挂载到宿主机的那个目录, 而Dockerfile的VOLUME不能,其在宿主机上的挂载目录是随机生成的。
    • -v参数格式及实例
      • docker run -v host_dir|file:container_dir|file

WORKDIR

  • 说明:设置工作目录
  • 格式:WORKDIR [path]
  • 示例:WORKDIR /home/mongo/
  • 备注:
    • 可以使用绝对路径,也可以使用相对路径,设置之后的所有操作都将在这个目录下完成
    • 设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。

ONBUILD

  • 说明:用来设置一些触发指令, 这些指令在当前镜像构建时不会被执行, 只有当以当前镜像为基础镜像, 去构建下一级镜像的时候才会被执行
  • 格式:ONBUILD [其他指令]
  • 示例:
    • ONBUILD COPY run.sh /home/api/
    • ONBUILD RUN [“apt-get”, “install”, “vim”]
  • 备注:

See Also

Thanks to the authors 🙂