核心篇,你必须要会的Dockerfile指令详解

Docker 专栏收录该内容
20 篇文章 8 订阅

一、Dockerfile介绍

二、Dockerfile构建失败时会怎样?

  • 如果在构建的过程中,Dockerfile某一步骤出错会怎样?下面通过一个演示案例来看看

演示案例

  • 第一步:编写当前路径下的Dockerfile,将第一个RUN指令中的“nginx”误写为“ngix”,如下所示
# Version: 0.0.2
FROM ubuntu:16.04
MAINTAINER dongyusheng "1286550014@qq.com"
RUN apt-get update && apt-get install -y ngin
RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html
EXPOSE 80

  • 第二步:接着构建镜像,查看结果
sudo docker build -t="dongyusheng/static_web" .
  • 第三步:可以看到在构建第三步的时候出错了,因为没有“ngin”这个软件

  • 第四步:Dockerfile每执行一条指令就会构造一个新的镜像,构建的时候虽然第3步出错了,但是前2步没有出错,前2步最后构造的镜像的ID为e6a19e1529ce

  • 然后通过docker images和docker ps -a查看,虽然镜像没有构建成功,但是构建了一个容器,容器ID为“e63cb83ef973”,镜像名为“e6a19e1529ce”

  • 第五步:我们可以尝试运行新创建的那个容器
sudo docker run -t -i e6a19e1529ce /bin/bash

  • 第六步:输入nginx命令,可以看到没有安装成功,因为上面“docker build”的第3步出错了,只执行成功了前2步

  • Dockerfile中途构建失败,仍然可以创建新的容器,我们可以基于该容器进行改造

三、构建缓存

  • 由于每一步的构建过程都会将结果提交为镜像,所以Docker的构建镜像过程就显得非常聪明。它会将之前的镜像层看做缓存
  • 例如,在上面的演示案例中,我们的Dockerfile第1步和第2步构建成功了,其中第1步构建的镜像会作为第2步构建过程中使用的镜像缓存,第2步构建的镜像会作为下面第3步构建的缓存...以此类推

--no-cache选项

  • 有时候需要确保构建过程中不会使用缓存,那么可以在“docker build”时指定--no-cache选项
  • 例如:指定了该选项,那么当再次“docker build”执行相同的Dockerfile文件时,相同的指令将不会再执行了,因此apt-get update命令也就不会执行,那么该镜像中的软件包就不会进行更新
sudo docker build --no-cache -t="dongshao/static_web" .

四、基于构建缓存的Dockerfile模板

  • 构建缓存带来的一个好处就是,我们可以实现简单的Dockerfile模板(比如在Dockerfile文件顶部增加仓库或者更新包,从而尽可能确保缓存命中)
  • 一般都会在自己的Dockerfile文件顶部使用相同的指令集模板,比如对ubuntu,Dockerfile文件如下所示:
    • 在这个Dockerfile文件中,我们使用ENV指令设置了一个名为“PEFRESHED_AT”的环境变量,这个环境变量用来表名该镜像模板最后的更新时间
    • 最后,我们使用RUN指令运行命令,该指令运行时将会刷新APT包的缓存,将要安装的每个软件包更新到最新版本
# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER dongyusheng "1286550014@qq.com"
ENV PEFRESHED_AT 2020-07-16
RUN apt-get -qq update
  • 有了上面那个模板,如果想刷新一个构件,只需要修改ENV指令中的日期。这使Docker在命令ENV指令时开始重置这个缓存,并运行后续指令而无须依赖该缓存。也就是说,RUN apt-get update这条指令将会被再次执行,包缓存也将会被刷新为最新内容。例如:
    • 下面将PEFRESHED_AT修改为“2020-07-18”,那么执行到ENV时,发现日期改变了,那么就会重新继续执行ENV及后面的所有指令
# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER dongyusheng "1286550014@qq.com"
ENV PEFRESHED_AT 2020-07-18
RUN apt-get -qq update
  • 可以扩展此模板,比如适配到不同的平台或者添加额外的需求。比如,可以向下面的Dockerfile文件为例来支持一个fedora镜像
FROM fedora:20
MAINTAINER dongyusheng "1286550014@qq.com"
ENV PEFRESHED_AT 2020-07-16
RUN yum -q makecache

五、Dockerfile指令

  • 在下面,我们介绍一些比较常用的指令
  • Dockerfile可以放入很多其他指令,完整的指令可以参阅:https://docs.docker.com/engine/reference/builder/
  • 本文介绍的指令有:
    • FROM
    • MAINTRINER
    • RUN
    • EXPOSE
    • CMD
    • ENTRYPOINT
    • WORKDIR
    • ENV
    • USER
    • VOLUME
    • ADD
    • COPY
    • LABEL
    • STOPSIGNAL
    • ARG
    • ONBUILD

SHELL形式与EXEC形式的注意事项1

  • Dockerfile的RUN、CMD、ENTRYPOINT等指令可以用来执行命令。执行命令的方式有2种:
    • shell形式(默认方式):默认的情况下,Docker是使用shell来执行这些命令的,例如ENTRYPOINT node app.js
    • exec形式:如果你想要以exec形式运行命令,那么可以使用数组的形式运行命令,例如,如ENTRYPOINT["node","app.js"]
  • shell形式与exec形式有什么区别:
    • shell:会启动一个shell,然后在shell上面运行程序。也就是说,该形式运行的命令,会自动在前面加上/bin/sh -c
    • exec:不启动shell,直接运行程序
  • 如果在一个不支持shell的平台上运行或者不希望在shell中运行(比如避免shell字符串篡改),也可以使用exec格式的RUN指令
  • 例如,下面以exec形式运行ENTRYPOINT指令:

  • 之后查看容器中的运行进程列表,可以看到这里是直接运行node进程,而并非在shell中执行

  • 如果采用shell形式(ENTRYPOINT node app.js),容器进程如下所示,可以看到其是在shell上运行的程序

SHELL形式与EXEC形式的注意事项2

  • 但是当涉及到的命令涉及一些变量时,那么EXEC是不能识别常量的。于是就需要使用shell形式来执行
  • 例如,执行下面的ENTRYPOINT指令,那么容器运行时,打印的是"hello &name",不会识别出name变量
FROM ubuntu
ENV name Docker
ENTRYPOINT ["/bin/echo", "hello $name"]
  • 对于上面问题的更改就是改用/bin/bash来执行,例如下面就是正确的了,最终会打印"hello Docker"
FROM ubuntu
ENV name Docker
ENTRYPOINT ["/bin/bash", "-c", "echo hello $name"]

六、FORM指令

  • 每个Dockerfile的第一条指令必须是FROM。该指令指定了一个已经存在的镜像,后续指令都将基于该镜像进行,这个镜像备被称为基础镜像
  • 例如,下面的Dockerfile以ubuntu:16.04为基础镜像
# Version: 0.0.1
FROM ubuntu:16.04

MAINTAINER dongyusheng "1286550014@qq.com"
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html
EXPOSE 80

FROM指令的形式

  • FROM指令可以指定多种形式
  • scratch:scratch是内置关键词,并不是一个真实存在的镜像。 FROM scratch 会使用一个完全干净的文件系统,不包含任何文件。 因为Go语言编译后不需要运行时,也就不需要安装任何的运行库。 FROM scratch 可以使得最后生成的镜像最小化,其中只包含了 server 程序
# 从头开始制作一个简单的镜像
FROM scratch
  • 指定系统:指定一个系统作为构建的基础镜像
FROM ubuntu
  • 指定系统+版本:与上面一样,只不过指定了系统的版本
FROM ubuntu:16.04

七、MAINTRINER指令

  • 该指令告诉Docker该镜像的作者是谁,以及作者的电子邮箱地址

八、RUN指令

  • RUN指令就是来指定在构造镜像时执行的命令
  • 例如,在构建下面的镜像时,我们执行了两条命令
# Version: 0.0.1
FROM ubuntu:16.04

MAINTAINER dongyusheng "1286550014@qq.com"
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html
EXPOSE 80

指定EXEC形式运行

  • 在文章前面我们介绍过了exec与shell。因此,你也可以使用exec形式来运行RUN指令。例如:
# 用一个数组来指定要运行的命令和传递给该命令的每个参数
RUN { "apt-get", " install", "-y", "nginx" }

九、EXPOSE指令

  • 该指令告诉Docker该容器内的应用程序将会使用容器的指定端口
  • 出于安全的原因,Docker并不会自动打开该端口而是需要用户在使用docker run运行容器时来指定需要打开哪些端口,也就是需要在执行"docker run"运行时使用-p来指定这个端口
  • 可以指定多个EXPOSE指令来向外部公开多个端口
  • 备注:Docker也可以使用EXPOSE指令来帮助将多个容器链接,用户可以在运行时以docker run命令通过--expose选项来指定对外部公开的端口

十、CMD指令

  • 介绍CMD指令用于指定一个容器启动时要运行的命令
  • Dockerfile中只能有一条CMD指令:
    • Dockerfile中只能有一条CMD指令
    • 如果指定了多条CMD指令,那么只有最后一条CMD指令会被使用
    • 如果想要在启动容器时运行多个进程或者多条命令,可以考虑使用类似Supervisor这样的服务管理工具
  • 与RUN指令的区别:
    • RUN指令是在使用"docker build"命令构建镜像时,让镜像执行的命令
    • CMD指令是使用该镜像运行容器时,让镜像运行的命令
  • CMD指令与"docker run"的关系:
    • 我们知道,在执行"docker run"让容器运行时,可以在"docker run"命令的最后加上命令让容器去运行
    • CMD指令与上面的功能是一样的。不过"docker run"的命令会覆盖CMD指令,下面有演示

演示案例

  • 下面是Dockerfile中的1条CMD指令,其让容器运行时执行/bin/bash命令启动一个shell
CMD ["/bin/bash"]
  • 上面的功能等同于执行下面的命令:
sudo docker run -i -t dongshao/images /bin/bash
  • 当然,如果要运行的命令指定了相关参数与选项,那么可以使用exec形式来运行该命令。例如:
CMD ["bin/bash", "-l"]

"docker run"会覆盖CMD指令

  • 概念:如果我们在Dockerfile中设置了CMD命令,但是同时执行"docker run"运行容器时指定了容器要运行的命令,那么"docker run"的命令会覆盖Dockerfile中的CMD指令,从而只执行"docker run"指定的命令
  • 例如:下面的Dockerfile设置了一条CMD指令,让容器运行时运行/bin/bash
CMD ["/bin/bash"]
  • 但是,我们在使用"docker run"运行容器时指定了容器要运行的命令"/bin/ps",那么CMD的/bin/bash命令就不会执行,只执行/bin/ps
sudo docker run -i -t dongshao/images /bin/ps
  • 与ENTRYPOINT指令之间的相互关系CMD指令与ENTRYPOINT指令之间有相互配合的关系,见下面ENTRYPOINT指令的介绍

十一、ENTRYPOINT指令

  • 介绍:ENTRYPOINT指令与CMD指令非常类似,也是用来在运行容器时执行命令,但是与CMD有许多不同的地方,请看下面的介绍

演示案例

  • 例如,我们在Dockerfile中设置下面的ENTRYPOINT指令,那么容器在运行时就会执行/usr/sbin/nginx,从而运行nginx服务器
ENTRYPOINY ["/usr/sbin/nginx"]
  • 与CMD一样,当命令有参数和选项时,也可以以数组的形式设置命令。例如:
ENTRYPOINY ["/usr/sbin/nginx", "-g", "daemon off;"]

"docker run"不会覆盖ENTRYPOINT指令,而是传递给ENTRYPOINT使用

  • "docker run"不会覆盖ENTRYPOINT指令,反而会将"docker run"最后的命令传递给ENTRYPOINT使用
  • 例如:下面我们在Dockerfile中设置了如下的ENTRYPOINT指令,让其运行Nginx
ENTRYPOINY ["/usr/sbin/nginx"]
  • 我们在启动一个容器时,在最后执行了-g "daemon off;",那么:
    • "docker run"最后的一些参数与选项会传递给ENTRYPOINT指令
    • 因此整个容器执行的命令是/usr/sbin/nginx -g daemon off
sudo docker run -i -t dongshao/images -g "daemon off;
  • "docker run"的--entrypoint选项:如果"docker run"命令带有--entrypoint选项,那么"docker run"就会覆盖Dockerfile中的ENTRYPOINT指令了

ENTRYPOINT指令与CMD指令的结合

  • 我们知道CMD指令与"docker run"最后输入的命令作用是相同的,因此CMD指定的命令也会接在ENRRYPOINT的命令后面,相当于传递给ENTRYPOINT使用
  • 例如,下面的Dockerfile指定了ENTRYPOINT指令和CMD指令,那么容器运行时最终运行的命令是/usr/sbin/nginx  -h
ENTRYPOINY ["/usr/sbin/nginx"]

CMD ["-h"]
  • RUN指令有时是作为ENTRYPOINT的默认参数使用的。例如,下面我们的Dockerfile执行了下面的命令
ENTRYPOINY ["/usr/sbin/nginx"]

CMD ["-h"]
  • 但是"docker run"时的命令是下面这样的:
sudo docker run -i -t dongshao/images -g "daemon off;
  • 那么运行容器时的意思就是,如果"docker run"最后没有指定命令,那么容器就执行/usr/sbin/nginx -h命令,如果"docker run"最后指定了命令,那么容器运行时执行的命令就是/usr/sbin/nginx -g daemon off

十二、WORKDIR指令

  • 介绍:WORKDIR指令用来执行容器运行时,执行容器运行时的工作目录,ENTRYPOINT指令和/和CMD指令运行的命令就是在这个指令所指定的工作目录下执行的

演示案例

  • 一个Dockerfile如下所示,其将容器的工作路径切换到/opt/webapp/db目录下,然后执行了RUN指令
WORKDIR /opt/webapp/db

RUN bundle install
  • 指定多个WORKDIR,表示在构建镜像时切换工作目录。例如,下面构建镜像时,先将工作目录切换到/opt/webapp/db执行RUN指令,然后再将工作目录切换到/opt/webapp执行rackup命令
WORKDIR /opt/webapp/db
RUN bundle install

WORKDIR /opt/webapp/
ENTRYPOINT [ "rackup" ]

docker run的-w选项会覆盖WORKDIR指令

  • "docker run"命令中的-w选项会覆盖Dockerfile中的WORKDIR指令
  • 例如,下面设置了当前的工作路径为/var/log
sudo docker run -it -w /var/log dongshao/images pwd

十三、ENV指令

  • 介绍:ENV指令用来在镜像构建中设置环境变量

演示案例

  • 例如下面设置了一个环境变量RVM_PATH,其值为/home/rmv
ENV RVM_PATH /home/rmv
  • 从Docker 1.4开始,可以指定多个环境变量。例如,下面设置了两个环境变量:
ENV RVM_PATH=/home/rmv RVM_ARCHFLAGS="-arch i386"
  • 一些注意点:
    • 当设置了环境变量之后,后面的任何RUN指令等操作都是基于这个环境变量进行操作
    • 如果需要,可以通过在环境变量前加上一个反斜线来进行转义
    • 该指令设置的环境变量,会在镜像中永久保存,因此基于该镜像创建的任何容器都会使用这个环境变量

-e选项

  • 默认情况下,ENV设置的环境变量是在镜像中永久保存的,因此每次创建容器,进入系统之后变量都会在系统中
  • "docker run"的-e选项可以指定:只在本次创建的容器运行时有效,容器退出或删除后环境变量失效
  • 例如,下面启动时指定容器的WEN_PORT环境变量为8080,当该容器退出后变量失效
sudo docker run -it -e "WEB_PORT=8080" dongshao/images

十四、USER指令

  • USER指令可以用来指定该镜像会以什么样的用户去运行
  • 如果没有指定USER指令,默认的用户为root,因此容器运行时很多命令都不需要加上sudo
  • 例如:下面的Dockerfile指定容器运行时,以nginx的身份去运行容器
USER nginx
  • 还可以指定UID以及组或GID:USER指令还可以指定用户名或UID以及组或GID,甚至是两者的组合。例如:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group

十五、VOLUME指令

  • USER指令用来向基于镜像创建的容器添加卷
  • 一个卷是可以存在于一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化的功能:
    • 卷可以在容器间共享和重用
    • 一个容器可以不是必须和其他容器共享卷
    • 对卷的修改是立即生效的
    • 对卷的修改不会对更新镜像产生影响
    • 卷会一直存在直到没有任何容器再使用它
  • 卷功能让我们可以将数据(如源代码)、数据库或者其他内容添加到镜像中而不是将这些内容提交到镜像中,并且允许我们在多个容器间共享这些内容。我们可以利用此功能来测试容器和内部的应用程序代码,管理日志,或者处理容器内部的数据库

演示案例

  • 下面这条指令会为基于此镜像创建的任何容器创建一个名为/opt/project的挂载点
VOLUME ["/opt/project"]
  • 也可以以数组的形式指定多个卷。例如:
VOLUME ["/opt/project", "/data"]

十六、ADD指令

  • 介绍:ADD指令用来将Dockerfile构建环境下的文件和目录复制到镜像中
  • 例如:下面的Dockerfile中有如下的ADD指令,当基于该镜像的容器运行时,会将与当前Dockerfile同一路径中的softwarte.lic文件(宿主机中的)复制到容器的/opt/application/目录下,名为software.lic(名字其实可以自己指定的)
ADD software.lic /opt/application/software.lic
  • 格式说明:
    • 在ADD文件时,Docker通过目的地址(后面的路径)参数末尾的字符来判断文件源(前面的路径)是目录还是文件
    • 如果目标地址以/结尾,那么Docker就认为源位置指向的是一个目录,那么会在文件源放置在这个目录下
    • 如果目标地址不是以/结尾,那么Docker就认为源位置指向的是文件,那么表示将文件源拷贝成该指定的文件
  • 文件源也可以是URL格式的:例如,下面将一个网页中的文件下载到/root/目录下,名为wordpress.zip
ADD http://wordpress.org/latest.zip /root/wordpress.zip

对归档文件有特殊处理(自动解压)

  • 如果文件源是本地归档文件(tar archive)时有特殊的处理,如果将一个归档文件(合法的归档文件包括gzip、bzip2、xz)复制到容器中,那么Docker会自动将归档文件解压
  • 如果目的位置已经存在了归档文件同名的文件或者目录,那么目录位置中的文件或者目录不会被覆盖
  • 目前Docker还不支持以URL方式制定的源位置中使用归档文件。这种行为稍显有点儿不统一,在以后的版本中应该会有所变化
  • 例如,一个Dockerfile中的ADD指令如下:
    • 下面将当前构建目录下的latest.tar.gz文件解压之后复制到容器的/var/ww/wordpress/目录下
    • 行为等同于带-x选项的tar命令一样
ADD latest.tar.gz /var/ww/wordpress/
  • 如果目的位置不存在会怎么样?
    • 如果目的位置不存在的话,Docker将会为我们在容器中创建这个全路径,包括路径中的任何目录
    • 新创建的文件和目录的模式为0775,并且UID和GID都是0
  • ADD指令会使Dockerfile缓存失效:如果通过ADD指令向镜像添加一个文件或者目录,那么这将使Dockerfile中的后续指令都不能继续使用之前的构建缓存

十七、COPY指令

  • 介绍:COPY指令非常类似于ADD指令,它们根本的不同是COPY只关心在构建上下文中复制本地文件,而不会去做文件提取(extraction)和解压(decomposition)的工作
  • 例如,下面是将宿主机当前构建目录下的conf.d/目录拷贝到镜像的/etc/apache2/目录下
COPY conf.d/ /etc/apache2/
  • 相关说明:
    • 文件源路径必须是一个与当前构建环境相对的文件或者目录,本地文件都放到和Dockerfile同一个目录下。不能复制该目录之外的任何文件,因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中运行的。任何位于构建环境之外的东西都是不可用的
    • COPY指令的目的位置必须是容器内部的一个绝对路径
    • 与ADD指令一样,如果目的位置不存在,那么也会进行创建,任何由该指令创建的文件或者目录的UID和GID都会设置为0
    • 如果源路径是一个目录,那么这个目录将整个复制到容器中,包括文件系统元数据
    • 如果源路径是一个文件,则该文件会随同元数据一起被复制

十八、LABEL指令

  • 介绍:LABEL指令用于为Docker镜像添加元数据,元数据以键值对的形式展现。类似于注释或者说明信息
  • LABEL指令是在Docker 1.6版本中加入的

演示案例

  • 例如下面构建镜像时,会添加一个元数据version
LABEL version="1.0"
  • 当然,你也可以在一条指令中指定多个元数据,不同的元数据用空格分隔
LABEL location="New York" type="Data Center" role="Web Server"
  • 我们建议所有的元数据都放到一条LABEL指令中,以防止不同的元数据指令创建过多镜像层

查看镜像标签

  •  通过docker inspect令来查看某个Docker镜像的标签信息。例如:
sudo docker inspect --format='{{ .ContainerConfig.Labels }}' dongshao/consul

十九、STOPSIGNAL指令

  • STOPSIGNAL指令用来设置停止容器时发送什么系统调用信号给容器
  • 这个信号必须是内核系统调用表中合法的数,比如9,或者SIGNAME格式中的信号名称,如SIGKILL
  • STOPSIGNAL指令是在Docker 1.9版本中引入的

二十、ARG指令

  • 介绍:
    • ARG指令用来定义可以在docker build构建镜像时传递构建运行时的变量,定义之后在执行"docker build"时使用--build-arg就可以使用该变量了
    • ARG指令是在Docker 1.9版本中引入的,可以在Docker文档阅读详细的说明:https://docs.docker.com/engine/reference/builder/#arg

演示案例

  • 例如,下面定义了两个变量,其中第二个变量拥有默认值
ARG build
ARG webapp_user=user
  • 当我们基于该Dockerfile构建镜像时,就可以输入下面的命令:
    • 其中将build变量设置为1234
    • 因为webapp_user有默认值了,因此下面就没有再指定
sudo docker build --build-arg build=1234 -t dongshao/webapp .
  • 不要传递证书或者秘钥:有些人可能会使用ARG来传递证书或者秘钥之类的信息,但是千万别这么做,因为机密信息会在构建过程中以及镜像的构建历史中被暴露出来

预定义的ARG变量

  • Dockerfile预定义了一组ARG变量,可以在构建时直接使用,而不必再到Dockerfile中自行定义了
  • 预定义的ARG变量如下:
HTTP_PROXY
http_proxy

HTTPS_PROXY
https_proxy

FTP_PROXY
ftp_proxy

NO_PROXY
no_proxy
  • 想要使用这些预定义的变量,在"docker build"命令中用--build-arg <variable>=<value>来指定就可以了

二十一、ONBUILD指令

  • ONBUILD指令能为镜像添加触发器

相关介绍

  • 当一个镜像被用作其他镜像的基础镜像时(比如用户的镜像需要从某未准备好的位置添加源代码,或者用户需要执行特定于构建镜像的环境的构建脚本),该镜像中的触发器将会被执行
  • 触发器会在构建过程中插入新指令,我们可以认为这些指令是紧跟在FROM之后指定的
  • 触发器可以是任何构建指令
  • 例如,下面的Dockerfile定义了2条ONBUILD指令
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make
  • 当然,可以在使用"docker inspect"来查看镜像或者容器的ONBUILD指令
  • 有几条指令不能用在ONBUILD中,包括:FROM、MAINTRINER和ONBUILD本身。这么做的原因是为了防止Dockerfile构建过程中产生递归调用的问题

演示案例

  • 下面创建一个apache2目录,然后进入创建一个Dockerfile文件

  • Dockerfile内容如下,其中安装了apache2服务器
FROM ubuntu:16.04
MAINTAINER dongshao "https://blog.csdn.net/qq_41453285"

RUN apt-get update && apt-get install -y apache2

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2

ONBUILD ADD . /var/www/

EXPOSE 80

ENTRYPOINT ["/usr/sbin/apache2"]

CMD ["-D", "FOREGROUND"]
  • 我们使用上面的Dockerfile来构建一个镜像
sudo docker build -t="dongshao/apache2" .

  • 查看创建好的镜像
sudo docker images dongshao/apache2

  • 现在我们创建好了一个镜像,这个镜像中创建了apache2服务器,因此我们可以把这个镜像当做一个Web应用程序的模板,其他镜像可以以这个镜像为基础镜像来构建自己的Web应用程序
  • 现在我们准备以上面的镜像为基础镜像来创建一个属于自己的镜像(添加自己想要的功能)。首先回到前一目录,创建一个自己Webapp的目录,然后创建一个Dockerfile
cd ..

mkdir webapp

cd webapp

touch Dockerfile

  • Dockerfile的内容如下
FROM dongshao/apache2

MAINTAINER dongshao "https://blog.csdn.net/qq_41453285"

ENV APPLICATION_NAME webapp
ENV ENVIRONMENT development
  • 上面的Dockerfile使用了我们之前的dongshao/apche2镜像,又因为dongshao/apche2镜像的Dockerfile中设置了一条“ONBUILD ADD . /var/www/”指令,因此当我们构建镜像时就会执行这条命
  • 因此,下面来构建看看,如下所示:因为该镜像依赖于dongshao/apache2镜像,因此Step第一步的时候执行了dongshao/apache2镜像Dockerfile中的ONBUILD指令
sudo docker build -t="dongshao/webapp" .

  • 总结:
    • 这种机制使得我们每次构建镜像时都会执行ONBUILD所指定的命令,因此可以将这种之前的镜像作为一种镜像模板
    • ONBILD触发器会按照在父镜像中指定的顺序执行,并且只能被继承一次(也就是说只能在子镜像中执行,而不会在孙子镜像中执行)。例如,如果我们基于上面的"dongshao/webapp"再构建一个镜像,那么"dongshao/apache2"中的ONBUILD指令是不会在"dongshao/webapp"的子镜像中执行的。

  • 我是小董,V公众点击"笔记白嫖"解锁更多【Docker】资料内容。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 护眼 设计师:闪电赇 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值