Docker学习6 — Dockerfile + docker build 详解
一、Dockerfile概述
Docker通过Docerfile自动构建镜像,Dockerfile是一个包含用于组建镜像的文本文件,由一条一条的指令组成。
二、Dockerfile常用指令
指令 描述 FROM 构建新镜像是基于哪个镜像 LABEL 标签 RUN 构建镜像时运行的shell命令 COPY 拷贝文件或目录到镜像中 ADD 解压压缩包并拷贝 ENV 设置环境变量 USER 为RUN、CMD和ENTRYPOINT执行命令指定运行用户 EXPOSE 声明容器运行的服务端口 WORKDIR 为RUN、CMD、ENTRYPOINT 、COPY和ADD设置工作目录 VOLUME 用于指定持久化目录 ENTRYPOINT 配置容器,使其可执行化。配合CMD可省去"application",只使用参数。 ARG 用于指定传递给构建运行时的变量 MAINTAINER 维护者信息 CMD 运行容器时默认执行,如果有多个CMD指令,最后一个生效
FROM指令:
FROM 指令是最重要的一个且必须为 Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境 。
实践中,基准镜像可以是任何可用镜像文件,默认情况下, docker build会在 docker主机上查找指定的镜像文件,在其不存在时,
则会从 Docker Hub Registry上拉取所需的镜像文件 .如果找不到指定的镜像文件, docker build会返回一个错误信息。
命令格式:
FROM <repository>[:<tag>] 或者 FROM <repository>@<digest>或 FROM <image>
<repository>:指定作为base image的名称
<tag>:base image的标签,为可选项,省略时默认为 latest;
<digest>为校验码
LABEL
LABEL用于为镜像添加元数据,元数以键值对的形式指定:
命令格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
LABEL age="18" name="小明" gender="男"
说明:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
RUN:构建镜像时执行的命令
RUN用于指定 docker build过程中运行的程序,其可以是任何命令,但是这里有个限定,一般为基础镜像可以运行的命令,如基础镜像为centos,安装软件命令为yum而不是ubuntu里的apt-get命令。
RUN和CMD都可以改变容器运行的命令程序,但是运行的时间节点有区别,RUN表示在docker build运行的命令,而CMD是将镜像启动为容器运行的命令。
因为一个容器正常只用来运行一个程序,因此CMD一般只有一条命令,如果CMD配置多个,则只有最后一条命令生效。而RUN可以有多个。
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行格式:
RUN <command>
exec执行格式:
RUN ["executable", "param1", "param2"]
第一种格式中,<command>通常是一个shell命令,且以“/bin/sh -c”作为父进程来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用 docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号;
第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,
表示这种命令在容器中直接运行,不会作为shell的子进程,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行,不过,如果要运行的没能力依赖此shell特性的话,可以将其替换为类似下面的格式:
RUN ["/bin/bash","-C","<executable>","<paraml>"]
注意:json数组中使用双引号
示例:
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
说明:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache。
COPY:用于从 Docker主机复制文件至创建的新映像文件
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
语法:
COPY <src> ... <dest>或 . COPY ["<src>",... "<dest>"]
<src>:要复制的源文件或目录,支持使用通配符
<dest>:目标路径,即正在创建的 image的文件系统路径;建议为 <dest>使用绝对路径,<dest>绝对路径为镜像中的路径,而不是宿主机的路径。否则, COPY指定则以 WORKDIR为其起始路径
注意:在路径中有空白字符时,通常使用第二种格式 。
文件复制准则
<src>必须是build上下文中的路径,即只能放在workshop这个工作目录下,不能是其父目录中的文件
如果<src>是目录,其内部文件或者子目录会被递归复制,但<src>目录自身不会被复制
如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且dest目录必须以/结尾
如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径
ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
说明:
如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载,并保存为<dest>/<filename>,注意,URL不能是ftp格式的url
如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令,然后,通过URL获取到的tar文件将不会自动展开
如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;
ENV:设置环境变量
ENV用于为镜像定义所需的环境变量,并可被 Dockerfile文件中位于其后的其它指令(如 ENV、ADD、COPY等)所调用 ,即先定义后调用。
格式:
ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat=fluffy
USER: 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。
格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
示例:
USER www
注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
EXPOSE:指定于外界交互的端口
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443
EXPOSE 8080 EXPOSE 11211/tcp 11211/udp
注:
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
WORKDIR:工作目录,类似于cd命令
格式:
WORKDIR /path/to/workdir
示例:
WORKDIR /a (这时工作目录为/a)
WORKDIR b (这时工作目录为/a/b)
WORKDIR c (这时工作目录为/a/b/c)
注:
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
VOLUME:用于指定持久化目录
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
ENTRYPOINT:配置容器,使其可执行化。配合CMD可省去"application",只使用参数
类似 CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。
与CMD不同的是,由 ENTRYPOINT启动的程序不会被 docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给 ENTRYPOINT指定指定的程序 .不过, docker run命令的 --entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序。
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
注:
ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
ARG:用于指定传递给构建运行时的变量
格式:
ARG <name>[=<default value>]
示例:
ARG age
ARG build_user=nginx
MAINTAINER: 维护者信息
格式:
MAINTAINER <name>
示例:
MAINTAINER xiaoming
MAINTAINER xiaoming@163.com
MAINTAINER xiaoming <mail@163.com>
CMD:构建容器后调用,也就是在容器启动时才进行调用。
类似于 RUN指令, CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同 . RUN指令运行于映像文件构建过程中,而 CMD指令运行于基于 Dockerfile构建出的新映像文件启动一个容器时 。
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过, CMD指定的命令其可以被 docker run的命令行选项所覆盖 .在Dockerfile中可以存在多个 CMD指令,但仅最后一个会生效。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
注:
CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
三、通过Dockerfile构建容器镜像
1、docker build命令
docker build命令用于根据给定的Dockerfile和上下文以构建Docker镜像。
2、命令格式
docker build [OPTIONS] <PATH | URL | ->
常用OPTIONS选项说明
--build-arg,设置构建时的环境变量。
--no-cache,默认false。设置该选项,将不使用Build Cache构建镜像。
--pull,默认false。设置该选项,总是尝试pull镜像的最新版本。
--compress,默认false。设置该选项,将使用gzip压缩构建的上下文。
--disable-content-trust,默认true。设置该选项,将对镜像进行验证。
-f,--file, Dockerfile的完整路径,指定Docerfile文件路径,默认值为‘PATH/Dockerfile’。
--isolation,默认--isolation="default",即Linux命名空间;其他还有process或hyperv。
--label,为生成的镜像设置metadata。
--squash,默认false。设置该选项,将新构建出的多个层压缩为一个新层,但是将无法在多个镜像之间共享新层;设置该选项,实际上是创建了新image,同时保留原有image。
-t,--tag, 镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag。
--network,默认default。设置该选项,Set the networking mode for the RUN instructions during build。
-q ,--quiet,默认false。设置该选项,Suppress the build output and print image ID on success。
--force-rm,默认false。设置该选项,总是删除掉中间环节的容器。
--rm,默认--rm=true,即整个构建过程成功后删除中间环节的容器。
PATH | URL | -说明:
给出命令执行的上下文。
上下文可以是构建执行所在的本地路径,也可以是远程URL,如Git库、tarball或文本文件等。
如果是Git库,如https://github.com/docker/rootfs.git#container:docker,则隐含先执行git clone --depth 1 --recursive,到本地临时目录;然后再将该临时目录发送给构建进程。
构建镜像的进程中,可以通过ADD命令将上下文中的任何文件(注意文件必须在上下文中)加入到镜像中。
-表示通过STDIN给出Dockerfile或上下文。
3、构建镜像示例
示例1
docker build -t tomcat:V1 --rm .
解析:
-t tomcat:V1: 为构建的镜像标记名称,即镜像名为:tomcat,打标为V1;
--rm: 整个构建过程成功后删除中间环节的容器;
-f /path/to/a/Dockerfile: 指定dockerfile路径,不指定的话,默认会读取上下文路径( . )下的 dockerfile
.: 单独的点,意思为根据当前目录下的Dockerfile文件生成镜像
示例2
docker build -f /path/to/a/Dockerfile .
解析:
-f /path/to/a/Dockerfile: 指定dockerfile路径,不指定的话,默认会读取上下文路径( . )下的 dockerfile
示例3
docker build --add-host=docker:10.1.1.143 .
解析:
--add-host:可以使用一个或多个 --add-host 标志将其他主机添加到容器的 /etc/hosts 文件中
四、Dockerfile示例
1、nginx的Dockerfile
# This is nginx Dockerfile
# Version 1.0.0
# Base images 基础镜像
FROM centos:7
#MAINTAINER 维护者信息
MAINTAINER lufei
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 需要再宿主机的Dockerfile目录放nginx压缩包,拷过去会自动解压
ADD nginx-1.9.2.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y lftp gcc gcc-c++ make openssl-devel pcre-devel pcre iproute net-tools telnet wget curl gd-devel && yum clean all && rm -rf /var/cache/yum/*
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.9.2
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-pcre && make -j 4 && make install \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 拷贝配置文件,需要再宿主机的Dockerfile目录放配置文件
COPY nginx.conf /usr/local/nginx/conf/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx", "-g", "daemon off;"]