dockerfile
基本结构
Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。
Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。
Docker分为四部分:
基础镜像信息
维护者信息
镜像操作指令
容器启动时默认要执行的指令
# This dockerfile uses the ubuntu image # VERSION 2 - EDITION 1 # Author: seancheng # Command format: Instruction [arguments / command] ... # 第一行必须指定基于的基础镜像 FROM ubuntu # 维护者信息 LABEL MAINTAINER=' lzx-01 2767565622@qq.com' # 镜像操作指令 RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list RUN apt-get update && apt-get install -y nginx RUN echo "ndaemon off;" >> /etc/nginx/nginx.conf # 容器启动时默认要执行的指令 CMD /usr/sbin/nginx
其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。
前面的docker镜像管理章节有说到,构建镜像的方式有两种:一种是基于容器制作,另一种就是通过Dockerfile。Dockerfile其实就是我们用来构建Docker镜像的源码,当然这不是所谓的编程源码,而是一些命令的组合,只要理解它的逻辑和语法格式,就可以编写Dockerfile了。
简要概括Dockerfile的作用:它可以让用户个性化定制Docker镜像。因为工作环境中的需求各式各样,网络上的镜像很难满足实际的需求。
Dockerfile Format(格式)Dockerfile整体就两类语句组成:
Comment 注释信息
Instruction arguments 指令 参数,一行一个指令。
编写时应注意:
Dockerfile文件名首字母必须大写。
Dockerfile指令不区分大小写,但是为方便和参数做区分,通常指令使用大写字母。
Dockerfile中指令按顺序从上至下依次执行。
Dockerfile中第一个非注释行必须是FROM指令,用来指定制作当前镜像依据的是哪个基础镜像。
Dockerfile中需要调用的文件必须跟Dockerfile文件在同一目录下,或者在其子目录下,父目录或者其它路径无效。
Dockerfile InstructionsFROM
Introduction
FROM指令必须为Dockerfile文件开篇的第一个非注释行,用于指定构建镜像所使用的基础镜像,后续的指令运行都要依靠此基础镜像所提供的的环境(简单说就是假如Dockerfile中所引用的基础镜像里面没有mkdir命令,那后续的指令是没法使用mkdir参数的。)
实际使用中,如果没有指定仓库,docker build会先从本机查找是否有此基础镜像,如果没有会默认去Docker Hub Registry上拉取,再找不到就会报错。
Syntax(语法)
FROM [:]
FROM @
Digest:镜像的哈希码,防止镜像被冒名顶替。
MAINTAINER(维护者)
Introduction
用于让Dockerfile的作者提供个人的信息
Dockerfile并不限制MAINTAINER指令的位置,但是建议放在FROM指令之后
在较新的docker版本中,已经被LABEL替代。
Syntax(语法)
MAINTAINER “2767565622@qq.com”
COPY
Introduction
复制宿主机上的文件到目标镜像中
Syntax(语法)
COPY …
COPY ["",… “”]
:要复制的源文件或者目录,支持通配符
:目标路径,即正创建的镜像的文件系统路径,建议使用绝对路径,否则,COPY指令会以WORKDIR为其起始路径。
如果路径中如果包含空白字符,建议使用第二种格式用引号引起来,否则会被当成两个文件。
Rules
必须是build上下文中的目录,不能是其父目录中的文件。
如果是目录,则其内部的文件或则子目录会被递归复制,但目录本身不会被复制。
如果指定了多个,或者中使用通配符,则必须是一个目录,且必须以 / 结尾。
如果事先不存在,它将会被自动创建,包括其父目录路径。
ADD
Introduction
ADD指令跟COPY类似,不过它还支持使用tar文件和URL路径。
当拷贝的源文件是tar文件时,会自动展开为一个目录并拷贝进新的镜像中;然而通过URL获取到的tar文件不会自动展开。
主机可以联网的情况下,docker build可以将网络上的某文件引用下载并打包到新的镜像中。
Syntax(语法)
ADD…
ADD ["",… “”]
WORKDIR
Introduction
同docker run -w
指定工作目录,可以指多个,每个WORKDIR只影响他下面的指令,直到遇见下一个WORKDIR为止。
WORKDIR也可以调用由ENV指令定义的变量。
Syntax(语法)
WORKDIR 相对路径或者绝对路径
相对路径是相对于上一个WORKDIR指令的路径,如果上面没有WORKDIR指令,那就是当前Dockerfile文件的目录。
VOLUME
Introduction
docker run -v简化版
用于在镜像中创建一个挂载点目录。上一章中有提到Volume有两种类型:绑定挂载卷和docker管理的卷。在dockerfile中只支持docker管理的卷,也就是说只能指定容器内的路径,不能指定宿主机的路径。
Syntax(语法)
VOLUME
VOLUME [""]
EXPOSE
Introduction
同docker run --expose
指定容器中待暴露的端口。比如容器提供的是一个https服务且需要对外提供访问,那就需要指定待暴露443端口,然后在使用此镜像启动容器时搭配 -P 的参数才能将待暴露的状态转换为真正暴露的状态,转换的同时443也会转换成一个随机端口,跟 -p :443一个意思。
EXPOSE指令可以一次指定多个端口,例如:EXPOSE 11111/udp 11112/tcp
Syntax(语法)
EXPOSE [/] [[/] …]
用于指定协议类型,如果不指定,默认TCP协议。
ENV
Introduction
同docker run -e
为镜像定义所需的环境变量,并可被ENV指令后面的其它指令所调用。调用格式为v a r i a b l e n a m e 或 者 variable_name或者variable
n
ame或者{variable_name}
使用docker run启动容器的时候加上 -e 的参数为variable_name赋值,可以覆盖Dockerfile中ENV指令指定的此variable_name的值。但是不会影响到dockerfile中已经引用过此变量的文件名。下面有举例说明:
Syntax(语法)
ENV
ENV = …
第一种格式一次只能定义一个变量,之后所有内容都会被视为的组成部分
第二种格式一次可以定义多个变量,每个变量为一个"="的键值对,如果中包含空格,可以用反斜线 进行转义,也可以为加引号,另外参数过长时可用反斜线做续行。
定义多个变量时,建议使用第二种方式,因为Dockerfile中每一行都是一个镜像层,构建起来比较吃资源。
RUN
Introduction
用于指定docker build过程中运行的程序,可以是任何命令。
RUN指令后所执行的命令必须在FROM指令后的基础镜像中存在才行。
Syntax
RUN
RUN [“executable”, “param1”, “param2”]
通常是一个shell命令,系统默认会把后面的命令作为shell的子进程来运行,以"/bin/sh -c"来运行它,也就意味着此进程在容器中的PID一定不为1,如果是1完事就结束了哇。
第二种格式的参数是一个JSON格式的数组,其中"executable"为要运行的命令,后面的"paramN"为传递给命令的选项或参数。此格式指定的命令不会以"/bin/sh -c"来发起,也就是直接由内核创建,因此不具备shell特性,类似于RUN [ “echo”, “$HOME” ],是无法识别 $ 的;如果想要依赖shell特性,可以替换命令为这样的格式[ “/bin/sh”, “-c”, “echo $HOME” ]。
CMD
Introduction
指定启动容器的默认要运行的程序,也就是PID为1的进程命令,且其运行结束后容器也会终止。如果不指定,默认是bash。
CMD指令指定的默认程序会被docker run命令行指定的参数所覆盖。
Dockerfile中可以存在多个CMD指令,但仅最后一个生效。因为一个docker容器只能运行一个PID为1的进程。
类似于RUN指令,也可以运行任意命令或程序,但是两者的运行时间点不同
RUN指令运行在docker build的过程中,而CMD指令运行在基于新镜像启动容器(docker run)时。
Syntax(语法)
CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用
CMD [“executable”,“param1”,“param2”] 使用exec执行,推荐方式
CMD [“param1”,“param2”] 提供给ENTRYPOINT的默认参数
前两种语法格式同RUN指令。第一种用法对于CMD指令基本没有意义,因为它运行的程序PID不为1。
第三种则需要结合ENTRYPOINT指令使用,CMD指令后面的命令作为ENTRYPOINT指令的默认参数。如果docker run命令行结尾有参数指定,那CMD后面的参数不生效。
ENTRYPOINT
Introduction
类似CMD指令的功能,用于为容器指定默认运行程序。
Dockerfile中可以存在多个ENTRYPOINT指令,但仅最后一个生效
与CMD区别在于,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT指令指定的程序。
不过,docker run的–entrypoint选项的参数可覆盖ENTRYPOINT指定的默认程序。示例如下:
Syntax(语法)
ENTRYPOINT command param1 param2
ENTRYPOINT [“executable”, “param1”, “param2”]
USER
Introduction
用于指定docker build过程中任何RUN、CMD等指令的用户名或者UID。
默认情况下容器的运行用户为root。
Syntax
USER [:]
USER [:]
实践中UID需要是/etc/passwd中某用户的有效UID,否则docker run命令将运行失败。
ONBUILD
Introduction
用于在Dockerfile中定义一个触发器。
ONBUILD后面指定的指令在docker build时是不会执行,构建完的镜像在被另一个Dockerfile文件中FROM指令所引用的时才会触发执行。
Syntax(语法)
onBUILD [INSTRUCTION]
几乎任何指令都可以成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令,多数情况是使用RUN或者ADD。
另外在使用COPY指令时,应该注意后续引用该镜像的Dockerfile的同级目录下是否有被拷贝的文件。
编写完成Dockerfile后,可以通过docker build命令来创建镜像。
基本的格式为docker build [选项] 路径,该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有内容发送给Docker服务端,由服务端来创建镜像。因此一般建议放置Dockerfile的目录为空目录。
另外,可以通过 .dockerignore 文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。
要指定镜像的标签信息,可以通过-t选项。
例如,指定Dockerfile所在路径为/tmp/docker_builder/,并且希望生成镜像标签为build_repo/first_image,可以使用下面的命令:
docker build -t build_repo/first_image /tmp/docker_builder/
源码编写apache的Dockerfile文件
##创建apache服务的dockerfile文件目录
[root@localhost ~]# mkdir apache
[root@localhost ~]# cd apache/
[root@localhost apache]# mkdir files
[root@localhost apache]# cd files/
##上传源码包
[root@localhost apache]# cd files/
[root@localhost files]# ls
apr-1.7.0.tar.gz apr-util-1.6.1.tar.gz httpd-2.4.49.tar.gz
##编写dockerfile文件
[root@localhost apache]# vim Dockerfile
[root@localhost apache]# cat Dockerfile
FROM centos
LABEL WAINTAINER='anan 14344@qq.com'
ADD files/* /usr/local
WOrKDIR /usr/local
RUN yum -y install openssl-devel pcre-devel pcre expat-devel libtool gcc gcc-c++ make which &&
cd apr-1.7.0 && sed -i '/$RM "$cfgfile"/d' configure &&
./configure --prefix=/usr/local/apr && make && make install &&
cd ../apr-util-1.6.1 &&
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr &&
make && make install &&
cd ../httpd-2.4.49 &&
./configure --prefix=/usr/local/apache
--enable-so
--enable-ssl
--enable-cgi
--enable-rewrite
--with-zlib
--with-pcre
--with-apr=/usr/local/apr
--with-apr-util=/usr/local/apr-util/
--enable-modules=most
--enable-mpms-shared=all
--with-mpm=prefork && make && make install
EXPOSE 80
CMD ["/usr/local/apache/bin/apachectl","-D","FOREGROUND"]
##构建镜像
[root@localhost ~]# docker build -t httpd/apache:v0.1 apache
·····省略部分·····
make[1]: Leaving directory '/usr/local/httpd-2.4.49'
Removing intermediate container 7af1ee7b4697
---> 7a1056e61f4c
Step 6/7 : EXPOSE 80
---> Running in be6cf29ac47c
Removing intermediate container be6cf29ac47c
---> c364d46ae347
Step 7/7 : CMD ["/usr/local/apache/bin/apachectl","-D","FOREGROUND"]
---> Running in 9eefe8d9f2c8
Removing intermediate container 9eefe8d9f2c8
---> 6cacc4ec01ac
Successfully built 6cacc4ec01ac
Successfully tagged anan/httpd:v0.1
##查看镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
best2001/httpd v0.1 6cacc4ec01ac 3 minutes ago 701MB
##使用新的镜像创建容器
[root@localhost ~]# docker run -d -P --name apache httpd/apache:v0.1
8c1d3aefadb7755a1bdea9bda69dc842bd05551fd0f86a5046e6859cf851a21b
[root@localhost ~]# docker ps
ConTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c1d3aefadb7 httpd/apache:v0.1 "/usr/local/apache/b…" 6 seconds ago Up 5 seconds 0.0.0.0:49153->80/tcp, :::49153->80/tcp apache



