简介
Dockerfile是Docker用来构建镜像的文本文件,包含自定义的指令和格式。可以通过docker build命令从Dockerfile中构建镜像。这个过程与传统分布式集群的编排配置过程相似,且提供了一系列统一的资源配置语法。用户可以用这些统一的语法命令来根据需求进行配置,通过这份统一的配置文件,在不同的平台上进行分发,需要使用时就可以根据配置文件自动化构建同时,Dockerfile与镜像配合使用,使Docker在构建时可以充分利用镜像的功能进行缓存,大大提升了Docker的使用效率。
示例
首先我们可以去docker官网上下载一个centos7.4的景象,想在地址是:https://hub.docker.com/
这里说一下,如果我们去docker官网或者自建的仓库中下载镜像的时候,一定要加上tag,也就是标签,如果不加默认是latest(最新版)。
我们下载一下上面的centos7.4的镜像,发现这个镜像的tag就是dadoha/centos7.4.1708:latest,冒号前面标注了下载地址,冒号后面标注了下载的版本,有人说7.4.1708不就是版本么,怎么还有个latest呢。你可以理解为每个版本的镜像里面的改动地方不同,所以一般都会再标注一个小版本。
简单的Dockerfile
cd /root/docker
mkdir /root/docker
touch Dockerfile
上面我们已经创建了一个简单的Dockerfile文件,From是告诉docker这个镜像的基础镜像是dadoha/centos7.4.1708(前面我们已经下载过了,所以它会从本地查找,如果本地没有就会从官网直接下载),具体的命令都是做什么用的,后面我们再详细介绍。下面是创建镜像的命令,-t指的是新镜像的标签,后面的路径是Dockerfile的存放路径,这里可以写绝对路径,也可以写相对路径。
新的镜像已经生成,不过还有地方需要补充,后面我们再了解。
Dockerfile指令
简介
Dockerfile的基本格式如下:INSTRUCTION arguments
在Dockerfile中,指令(INSTRUCTION)不区分大小写,但是为了与参数区分,推荐大写。Docker会顺序执行Dockerfile中的指令,第一条指令必须是FROM指令,它用于指定构建镜像的基础镜像。
在Dockerfile中以#开头的行是注释,而在其他位置出现的#会被当成参数。
Dockerfile中的指令有FROM、MAINTAINER、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、USER、WORKDIR、ONBUILD,错误的指令会被忽略。
Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
基础镜像信息 # FROM
维护者信息 # MAINTAINER
镜像操作指令 # RUN、COPY、ADD、EXPOSE等
容器启动时执行指令 #CMD、ENTRYPOINT
基础镜像是需要说明我们这个新的镜像是要以哪个镜像作为基础,维护者信息这里一般会标明作者和作用,镜像指令说明在这个镜像里面要执行哪些命令,安装软件、建文件和文件夹等等系统操作,容器启动时执行指令这里需要注意一下,如果我们安装的是服务,比如说tomcat、nginx,zabbix,这里要写的就是启动这些服务,如果是操作系统这里也要写一个一直在执行的指令,我们叫守护进程,否则它执行完以后就直接退出了。
详细说明
ENV
格式:ENV <key> <value>或ENV <key>=<value>,前者一般是在设置一个环境变量时候使用,后者是可以同时设置多个。中间用空格隔开,例如key1=path2 key2=path2
ENV指令可以为镜像创建出来的容器生命环境变量。并且在Dockerfile中,ENV指令声明的环境变量会被后面的特定指令(即ENV、ADD、COPY、WORKDIR、EXPOSE、VOLUME、USER)解释使用。其他指令使用环境变量时,使用格式为$variable_name或者${variable_name}。在变量前面添加斜杠\可以转义,如\$foo或者\${foo},将会被分别转换为$foo和${foo},而不是环境变量所保存的值。另外,ONBUILD指令不支持环境替换。
FROM
格式:FROM <image> 或FROM <image>:<tag>
FROM指令的功能是为后面的指令提供基础镜像,因此一个有效的Dockerfile必须以FROM指令作为第一条非注释指令。从公共镜像库中拉取镜像很容器,基础镜像可以选择任何有效的镜像。在一个Dockerfile中,FROM指令可以出现多次,这样会构建多个镜像。在每个镜像创建完成后,Docker命令行界面会输出该镜像的ID。若FROM指令中参数tag为空,则tag默认是latest;若参数image或tag指定的镜像不存在,则返回错误。
COPY
格式:COPY <src> <dest>
COPY指令复制<src>所指向的文件或目录,将它添加到新镜像中,复制的文件或目录在镜像中的路径是<dest>。<src>所指定的源可以有多个,但必须在上下文中,即必须是上下文根目录的相对路径。不能使用形如COPY ../something /something这样的指令。此外,<src>可以使用通配符指向所有匹配通配符的文件或目录,例如,COPY hom* /mydir/ 表示添加所有以“hom”开头的文件到目录/mydir/中。
<dest>可以使文件或目录,但必须是目标镜像中的绝对路径或者相对于WORKDIR的相对路径(WORKDIR即Dockerfile中WORKDIR指令指定的路径,用来为其他指令设置工作目录)。若<dest>以反斜杠/结尾则其指向的是目录;否则指向文件。<src>同理。若<dest>是一个文件,则<src>的内容会被写入到<dest>中;否则<src>所指向的文件或目录中的内容会被复制添加到<dest>目录中。当<src>指定多个源时,<dest>必须是目录。另外,如果<dest>不存在,则路径中不存在的目录会被创建。
ADD
格式:ADD <src> <dest>
ADD与COPY指令在功能上很相似,都支持复制本地文件到镜像的功能,但ADD指令还支持其他功能。<src>可以是一个指向一个网络文件的URL,此时若<dest>指向一个目录,则URL必须是完全路径,这样可以获得该网络文件的文件名filename,该文件会被复制添加到<dest>/<filename>。例如,ADD http:example.com/foobar /会创建文件/foobar。
<src>还可以指向一个本地压缩归档文件,该文件在复制到容器中时会被解压提取,如ADD example.tar.xz /。但若URL中的文件为归档文件则不会被解压提取。
RUN
ADD和COPY指令虽然功能相似,当一般推荐使用COPY,因为COPY只支持本地文件,相比ADD而言,它更透明。
RUN指令有两种格式:
RUN <commadn> (shell格式)
RUN ["executable","param1","param2" ](exec格式,推荐格式)
RUN指令会在前一条命名创建出的镜像的基础上创建一个容器,并在容器中运行命令,在命令结束运行后提交容器为新镜像,新镜像被Dockerfile中的下一条指令使用。
RUN指令的两种格式表示命令在容器中的两种运行方式。当使用shell格式时,命令通过/bin/sh -c运行;当使用exec格式时,命令是直接运行的,容器不调用shell程序,即容器中没有shell程序。exec格式中的参数会当成JSON数据被Docker解析,故必须使用双引号而不能使用单引号。因为exec格式不会再shell中执行,所以环境变量的参数不会被替换,例如,当执行CMD ["echo","$HOME"]指令时,$HOME不会做变量替换。如果希望运行shell程序,指令可以写成CMD["shell","-c",“echo",“$HOME”]
示例:
多个命令之间用&&隔开,换行用/即可。这里一定要注意一个dockerfile里面用一个RUN最佳,因为多个RUN会形成多层镜像。
CMD
功能为容器启动时要运行的命令
语法有三种写法
1. CMD ["executable","param1","param2"]
2. CMD ["param1","param2"]
3. CMD command param1 param2
第三种比较好理解了,就时shell这种执行方式和写法
第一种和第二种其实都是可执行文件加上参数的形式
举例说明两种写法:
CMD [ "sh", "-c", "echo $HOME" ]
CMD [ "echo", "$HOME" ]
补充细节:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号。
原因是参数传递后,docker解析的是一个JSON array
RUN & CMD
不要把RUN和CMD搞混了。
RUN是构件容器时就运行的命令以及提交运行结果
CMD是容器启动时执行的命令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子
ENTRYPOINT
ENTRYPOINT指令有两种格式:
ENTRYPOINT <command> (shell格式)
ENTRYPOINT ["executable","param1","param2"] (exec格式,推荐格式)
ENTRYPOINT和CMD很像,他两可以如果一起用执行不同的命令的话,谁在最后面就谁生效,当前前者就不再执行了。还有一种用法如下:
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
这种用法简直就是变态,直接CMD ["/usr/bin/ls","-l"]或者CMD ls -l,但就是有这中用法,很尴尬。
USER
USER:指定运行容器时的用户名或 UID,后续的操作都会使用指定用户。使用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参数来覆盖所指定的用户。
WORKDIR
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径,示例:
WORKDIR /root
WORKDIR test
RUN vim 1.txt
等同于:
RUN cd /root/test/ && vim 1.txt
ARG
ARG是Docker1.9 版本才新加入的指令。格式:ARG<name>[=<default value>]
ARG指定了一个变量在docker build的时候使用,可以使用--build-arg <varname>=<value>来指定参数的值,不过如果构建的时候不指定就会报错。
LABEL
LABEL执行是向镜像中添加元数据,一个LABEL是一个键值对,在LABEL的值中使用添加空格,使用双引号和反斜线。示例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
示例:
LABEL multi.label1="value1" \
multi.label2=
"value2" \
other="value3"
查看镜像的LABEL可以使用docker inspect命令:
"Labels": {
"com.example.vendor": "ACME Incorporated"
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple lines.",
"multi.label1": "value1",
"multi.label2": "value2", "
other": "value3"
},
VOLUME
格式:VOLUME ["/data"]或者直接VOLUME /data
可以将本地文件夹或者其他container的文件夹挂载到container中,注意这里说的是管理卷,生成的镜像不管在哪里运行,都会将本地的/data目录挂载到容器中。
EXPOSE
功能为暴漏容器运行时的监听端口给外部,但是EXPOSE并不会使容器访问主机的端口,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -p参数,例如-p 80:80,意义为将后者(容器的80端口)映射到前者(宿主机的80)端口上。
附加:
1、修改镜像标签
docker tag 原名称:版本 新名称:版本
例如:docker tag testcentos7.4.01:latest testcentos7:latest