Docker file的作用方便管理员来根据需求来进行构建镜像,前面学习过commit来将一个容器打包成镜像,但是Docker 并不建议用户通过commit方式构建镜像。
原因如下:
1. 这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。比如要在 debian base 镜像中也加入 vi,还得重复前面的所有步骤。 2. 更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审 计,存在安全隐患。 3. 用 Dockerfile(推荐方法)构建镜像,底层也 docker commit 一层一层构建新镜像的。docker file能够帮 助我们更加深入地理解构建过程和镜像的分层结构。
运行 docker build 命令,-t 将新镜像命名为 centos-yum,命令末尾的 . 指明 build context 为当前目录。 Docker 默认会从 build context 中查找名为Dockerfile 文件,我们也可以通过 -f 参数指定 Dockerfile 的位 置。
构建一个安装了vim的centos7
[root@localhost ~]# vi Dockerfile
FROM centos:7
RUN yum install -y vim
[root@localhost ~]# docker build -t centos7:vim .
[+] Building 18.9s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 74B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [1/2] FROM docker.io/library/centos:7 0.0s
=> [2/2] RUN yum install -y vim 17.8s
=> exporting to image 1.1s
=> => exporting layers 1.1s
=> => writing image sha256:634da32af45aaaea9c68309bb41676ba9b4b96586621ed0600aa726fa8f93b8c 0.0s
=> => naming to docker.io/library/centos7:vim 0.0s
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos7 vim 634da32af45a 7 seconds ago 468MB
registry.cn-hangzhou.aliyuncs.com/conquerbug/test v1 feb5d9fea6a5 21 months ago 13.3kB
centos 7 eeb6ee3f44bd 21 months ago 204MB
构建这个镜像的过程
-
运行docker build命令 -t 将新镜像命名为centos7:vim,找到当前路径的Dockerfile文件
-
开始根据Dockerfile的命令来进行构建
-
执行FROM,将centos7做为base镜像
-
执行RUN,安装vim
-
启动一个临时的容器,在容器中安装vim
-
安装完成后,将当前容器创建为镜像
-
删除临时容器
-
镜像构建完成,通过docker images 查看镜像信息
Docker file命令
1.FROM
功能为指定基础镜像,并且必须是第一条指令。 如果不以任何镜像为基础,那么写法为:FROM scratch。 同 时意味着接下来所写的指令将作为镜像的第一层开始 语法:
FROM <image>
FROM <image>:<tag>
2.RUN
功能为运行指定的命令 RUN命令有两种格式
-
RUN
-
RUN ["executable", "param1", "param2"] 第一种后边直接跟shell命令 . 在linux操作系统上默认 /bin/sh -c . 在windows操作系统上默认 cmd /S /C 第二种是类似于函数调用。 可将executable理解成为可执行文 件,后面就是两个参数。
两种写法比对:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", "-c", "echo hello"]
注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层. 多少个RUN就构建了多 少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。 RUN书写时的换行 符是\
3.CMD
功能为容器启动时要运行的命令
语法有三种写法
-
CMD ["executable","param1","param2"]
-
CMD ["param1","param2"]
-
CMD command param1 param2
第三种比较好理解了,就时shell这种执行方式和写法 第一种和第二种其实都是可执行文件加上参数的形 式 举例说明两种写法:
CMD [ "sh", "-c", "echo $HOME"]
CMD [ "echo", "$HOME" ]
注意:补充细节:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号。 原因是参数传递后,docker解析的是一个JSON array
4.RUN和CMD的区别
不要把RUN和CMD搞混了。 RUN是构件容器时就运行的命令以及提交运行结果 CMD是容器启动时执行的命 令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子
5.LABEL
功能是为镜像指定标签,为镜像写一些注释信息
语法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
一个Dockerfile种可以有多个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会继承基础镜像种的LABEL,如遇到key相同,则值覆盖
6.EXPOSE
功能为暴漏容器运行时的监听端口给外部 但是EXPOSE并不会vim 使容器访问主机的端口 如果想使得容器与主 机的端口有映射关系,必须在容器启动的时候加上 -P参数
语法:
EXPOSE 90/tcp 9090/udp 6000/tcp
注意:如果在端口号后面加/tcp,默认为tcp协议,如果需要UDP端口需要添加/udp
7.ENV
功能为设置环境变量 语法有两种
1. ENV 变量名=值
2. ENV = 变量名1=值1,变量名2=值2
两者的区别就是第一种是一次设置一个,第二种是一次设置多个
例子:创建一个httpd服务的镜像
[root@localhost ~]# vi Dockerfile
FROM centos:7
RUN yum install -y httpd
CMD /bin/bash
LABEL version="1.0"
LABEL "QQ"="34241235324"
LABEL "email=123434453@qq.com"
EXPOSE 80/tcp
ENV service=httpd
docker build -t cenos7:httpd .
docker run -itd --name httpd --privileged=true cenos7:httpd /usr/sbin/init -p 80:80
docker exec -it 487cdf7ddfc56249f59bee6639b52b03f2bd1090c6430eafc2e6973567249372 /bin/bash
8.ADD
一个复制命令,把文件复制到镜象中。 如果把虚拟机与容器想象成两台linux服务器的话,那么这个命令就类似 于scp,只是scp需要加用户名和密码的权限验证,而ADD不用。
语法如下:
ADD source源文件 目标位置
ADD http:/aliyuan/httpd.html 目标位置
ADD tar包 目标位置
注意:尽量不要把写成一个文件夹,如果是一个文件夹了,复制整个目录的内容,包括文件系统元数据
9.COPY
复制命令,与ADD类似
语法如下:
COPY 源文件 目标文件
10.ADD与COPY的区别
-
ADD在拷贝tar包时,到目标位置会自动解压,COPY还是源文件不会有任何变化
-
ADD在拷贝过程中可以使用http链接来下载文件
11.ENTRYPOINT
该命令与CMD类似,用于执行命令使用,还可以与CMD命令一起拼合使用
它与CMD的区别: 相同点:只能写一条,如果写多条,那么只有最后一条生效
不同点:CMD在创建容器时,在后面添加其他的CMD指令,CMD会被覆盖,但是ENTRYPOINT不会被覆盖,如果两个同时使用,CMD会变成ENTRYPOINT的参数
语法如下:
ENTRYPOINT ["ls","-l"]
ENTRYPOINT ls -al
注意: 如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会互相覆 盖,谁在最后谁生效 如下:
ENTRYPOINT ["ls","-l"]
CMD ["ps","-ef"]
12.USER
设置启动容器的用户,可以是用户名或UID,所以,只有下面的两种写法是正确的
语法如下:
USER zhangsan
USER UUID
13.WORKDIR
设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次
语法如下:
WORKDIR /tmp
ENTRYPOINT ls -l
14.ARG
语法: ARG [=] 设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg = 来指定参数 如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning 提示如 下:
[Warning] One or more build-args [foo] were not consumed.
我们可以定义一个或多个参数并赋予默认值。如下:
ARG name
ARG age=18
使用场景,当我们需要指定一些软件的版本时,可以使用ARG来指定外部变量,在下载时使用较新的版本,还可以定义默认值
注意:如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值
15.VOLUME
可实现挂载功能,可以将内部文件夹挂载到外部
语法如下:
VOLUME /var/log
使用环境,一般的使用场景为需要持久化数据,当容器被删除后,数据将会被全部删除,当需要把容器内的数据持久化时,可以使用该命令,当容器被删除时,指定的文件,在外部不会丢失。
16.ONBUILD
这个命令只对当前镜像的子镜像生效。 在镜像A的Dockerfile文件中添加,当B镜像的dockerfile中FROM使用的镜像为A,此时当B镜像RUN构建时,就会执行A镜像中添加的ONBUILD指令。
语法如下:
ONBUILD [INSTRUCTION]
比如当前镜像为A,在Dockerfile种添加:
ONBUILD RUN ls -al 这个 ls -al 命令不会在A镜像构建或启动的时候执行
此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。
17.STOPSIGNAL
这个命令的作用是当容器退出时给系统发送什么样的指令
语法如下:
STOPSIGNAL signal
附真实案例:
要求:制作一个httpd服务的centos7镜像
FROM centos:7
LABEL version="httpd v1"
LABEL "emill"="243254384@qq.com"
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /usr/local/src
ADD httpd-2.4.57.tar.gz ./
WORKDIR /usr/local/src/httpd-2.4.57
RUN yum install -y epel-release.noarch && yum makecache fast
RUN yum install -y gcc gcc++ make apr-devel apr apr-util apr-util-devel pcre-devel
RUN ./configure --prefix=/usr/local/apache2 --enable-mods-shared=most --enable-so && make && make install
RUN sed -i 's/#ServerName www.example.com:80/ServerName localhost:80/g' /usr/local/apache2/conf/httpd.conf
RUN /usr/local/apache2/bin/httpd
EXPOSE 80/tcp
CMD /usr/local/apache2/bin/httpd -D FOREGROUND
到此,就把常用的dockerfile指令介绍完毕了,大家在工作中,常用那些指令,欢迎大家进行补充,如果觉得还写的不错,记得点赞+收藏+关注