四、Dockerfile

1、Dockerfile初识

镜像的生成途径:Dockerfile 和 基于容器制作

Dockerfile 就是用来构建镜像的源码,它就是一个纯文本文件,中间包含了一些指令,这些指令是在Dockerfile制作镜像时规定使用的指令

Dockerfile 总共就两类语句组成:#Comment(注释信息)  和  INSTRUCTION arguments(指令加其参数),这里的指令为了区分对应的参数,一般使用大写的

Dockerfile 的执行是从上到下依次执行的;第一个非注释行必须是 FROM 指令,指定当前要做的镜像是基于哪个基础镜像来制作的(所有制作镜像都是建立在一个已经存在的镜像基础之上)

2、Dockerfile 工作逻辑

  • 在使用 Dockerfile 时候,需要有专用的工作目录
  • 如果要想基于当前目录向镜像中打包文件,那么这些文件做好之后要放在当前工作目录下(引用的文件路径不能是工作目录的父目录,只能是基于当前目录往下走的路径),如果此时想要将一个目录全部放入镜像中,也是可以的
  • 如果此时这个目录中存在有几百个文件,但是有几个文件不想放入镜像中,Dockerfile 还支持在当前工作目录中加入 .dockerignore 文件,这样就可以忽略部分指定的文件
  • 使用命令 docker build  命令来制作镜像了,做好镜像、打好标签、推导镜像仓库里面就可以使用了;其实这里的 docker build 构建一个镜像的时候,也是隐藏式的启动一个容器,然后在这个容器中执行相关的操作,和人工通过在 docker 容器中执行命令并最后打包镜像的操作没有什么本质区别

3、Dockerfile 指令

3.1、FROM

FROM 指令是最重要的一个且必须为 Dockerfile 文件开篇的第一个非注释行,用于为映射文件构建指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境

实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build 会在docker 主机上查找指定的镜像文件,在其不存在时,则会从 Docker Hub Registry 上拉取所需的镜像文件

FROM <repository>[:<tag>] 或
FROM <repository>@<digest>
    <repository>:指定作为base image的名称
    <tag>:base image的标签,为可选项,省略时默认为latest

3.2、MAINTAINER -> LABEL

用于让 Dockerfile 制作者提供本人的详细信息,这个目前已经废弃掉了

Dockerfile 并不限制 MAINTAINER 指令出现的位置,但推荐将其放在 FROM 之后

MAINTAINER "aaa<aaa@126.com>"

这个在 docker 的新版中间使用 LABEL 替换了,LABEL 是让用户为一个镜像指定各种各样的元数据,数据为 key-value 格式

LABEL author="aaa<aaa@126.com>"

其实这两个指令对于做镜像本身来说并没有什么实际的意义

3.3、COPY

用于从 docker 宿主机复制文件至创建的新映像文件

COPY <src> ... <dest> 或
COPY ["<src>",..."<dest>"]
    <src>:要复制的源文件或目录,支持使用通配符
    <dest>:目表路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路径,否则,COPY指令则会以WORKDIR为起始路径
在上面的源文件是一个相对路径,目标路径是一个绝对路径

注意:在路径中有空白字符时,通常使用第二种方式

文件复制准则

  • <src> 必须是 build 上下文中的路径,不能是其父路径中的文件
  • 如果 <src> 是目录,则其内部文件或子目录会被递归复制,但 <src> 目录自身不会被复制
  • 如果指定了多个 <src> ,或在 <src> 中使用了通配符,则 <dest> 必须是一个目录,且必须以 / 结尾
  • 如果 <dest> 事先不存在,它将会被自动创建,这包括父目录路径

在上面的 index.html ,可以看到和 Dockerfile 是在同一个目录中

下面就可以使用 docker build 来制作镜像了

如上,就创建好了一个镜像

将这个镜像启动,并查看中间的 index.html 文件,可以看到启动的容器中已经存在这个文件了

上面的流程是将一个单独的文件放到创建的镜像指定目录下,下面可以将一个目录中的内容打包进镜像中;这里提一嘴,在Dockerfile中要尽量的少写内容,每写一行的内容对应的就是镜像的一层,所以能够进行合并的就合并为一条指令

 

3.4、ADD

ADD 指令类似于 COPY 指令,ADD 支持使用 TAR 文件和 URL 路径

ADD <src> ... <dest> 或
ADD ["<src>",..."<dest>"]

操作准则

  • 同 COPY 命令
  • 如果 <src> 为 URL 且 <dest> 不以 / 结尾,则 <src> 指令的文件将被下载并直接被创建为 <dest> ;如果 <dest> 以 / 结尾,则文件名  URL 指定的文件将被执行下载并保存为 <dest>/<filename>
  • 如果 <src> 是一个本地系统上的压缩文件的tar文件,它将被展开为一个目录,其行为类似于 ```tar -x```  命令;然而,通过 URL 获取到的tar文件将不会自动展开
  • 如果 <src> 有多个,或其间接或直接使用了通配符,则 <dest> 必须是一个以 / 结尾的目录路径;如果 <dest> 不以 / 结尾,则其被视为一个普通文件,<src> 的内容将被直接写入 <dest>

可以看到,这里 ADD 后面如果跟上 URL 的时候,先会进行下载的操作,之后将下载好的文件传到构建的镜像中去,当启动这个镜像的时候,可以看到,这个文件是并没有展开的

下面将一个本地tar文件传入到镜像中去

3.5、WORKDIR

用于为 Dockerfile 中的所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指定设定工作目录

WORKDIR <dirpath>

在 Dockerfile 文件中,WORKDIR 指令可出现多次,其路径也可为相对路径,不过,其是相对此前一个 WORKDIR 指令指定的路径

另外,WORKDIR 也可调用由 ENV 指定定义的变量

WORKDIR /var/log
WORKDIR $STATEPATH

3.6、VOLUME

用于在image中创建一个挂载点目录,以挂载 Docker Host 上面的卷或其他容器上的卷

VOLUME <mountpoint> 或
VOLUME ["<mountpoint>"]

可以看到,这个容器中的目录已经成功挂载在宿主机上面了

3.7、EXPOSE

用于为容器打开指定要监听的端口以实现与外部通信

EXPOSE <port>[/protocol] [<port>[/protocol]] ...

EXPOSE 指令可一次指定多个端口

EXPOSE 11211/udp 11211/tcp

这里注意,这里在文件中间指定了 EXPOSE 端口,并不是说之后依据这个镜像启动容器就一定就会暴露这个端口,在 ```docker container run``` 命令中,有一个 ```-P``` 选项,加上这个参数在启动容器的时候就会自动将这里 EXPOSE 指定的端口进行对外暴露(-P 表示暴露要镜像中指定要暴露的所有端口)

3.8、ENV

用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中位于其后的其他指令(如 ENV、ADD、COPY等)所调用

调用格式为 ${variable_name} 或 $variable_name

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

  • 第一种格式中,<key> 之后的所有内容均会被视为 <value> 的组成部分,因此,一次只能设置一个变量
  • 第二种格式可以一次设置多个变量,每一个变量为一个 “<key>=<value>” 的键值对,如果 <value> 中包含空格,可以使用反斜线(\)进行转义,也可以通过对 <value> 加引号进行标识;另外,反斜线也可用于续行

定义多个变量时,建议使用第二种格式,以便在同一层中完成所有功能

在 Dockerfile 中定义的所有环境变量,在启动容器之后,在容器中是可以看到的(printenv),在 docker container run 的时候,也是可以为容器设定环境变量的(-e,--env),此时如果在启动的时候设定了一个和 Dockerfile 定义相同的环境变量,后者会冲掉前者定义的环境变量

3.9、RUN

用于指定 docker build 过程中运行的程序,其可以是任何命令

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

在第一种格式中,<command> 通常是一个shell命令,并以 /bin/sh -c 来运行它,这意味着此进程在容器中的PID不为1,不能接受 Unix 信号,因此,当使用 docker stop <container> 命令停止容器时,此进程接收不到 SIGTERM 信号

第二种语法格式中的参数是一个json格式的数组,其中 <executable> 为要运行的命令,后面的 <paramN> 为传递给命令的选项或参数;然而,此种格式指定的命令不会以 /bin/sh -c 来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行,不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式

RUN ["/bin/bash","-c","<executable>","<param1>"]

3.10、CMD

类似于 RUN 指令,CMD 指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同

  • RUN 指令运行于映像文件构建过程中,而 CMD 指令运行于基于 Dockerfile 构建出的新映像文件启动一个容器时
  • CMD 指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将被终止;不过,CMD 指定的指令其可以被 docker container run 的命令行选项所覆盖
  • 在 Dockerfile 中可以存在多个 CMD 指令,但仅有最后一个生效

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

前两种语法格式的意义同 RUN,第三种则用于为 ENTRYPOINT 指令提供默认参数

3.11、重点

在上面使用到的 CMD 和 RUN 命令,如果后面直接跟上的就是命令,这样执行的命令默认是在shell下执行的,即所启动的进程的父进程是shell,且这样启动的docker并不能接受到 Unix 信号,比如使用 docker stop,就无法关闭docker,这是因为其主进程不唯一(原理是这样,但是docker会自动做替换,将启动的命令作为进程为1启动,这样启动的容器就能够接收 Unix 信号了)

可以看到,在 Dockerfile 中定义的时候,CMD 后面是命令行,正常来看的话,所启动命令的父进程应该是shell,进入容器之后可以看到,启动的命令的进程ID为1,这是docker自身对其进行了替换,这样就能够使用相关的docker命令来对容器进行管理了

3.12、ENTRYPOINT

类似于 CMD 指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序

与 CMD 不同的是,由 ENTRYPOINT 启动的程序不会被 docker run 命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给 ENTRYPOINT 指定的程序

这里需要注意:如果在启动容器的时候,使用了 --entrypoint 选项的参数可覆盖 ENTRYPOINT 指令指定的程序

ENTRYPOINT <command>
ENTRYPOINT ["<executable>","<param1>","<param2>"]

docker run 命令传入的命令参数会覆盖 CMD 指令的内容并且附加到 ENTRYPOINT 命令最后作为其参数使用,Dockerfile 文件中也可以存在多个 ENTRYPOINT 指令,但仅有最后一个会生效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值