1. Dockerfile 是什么。

Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本文件。

2. Dockerfile 的作用。

使用 docker build 命令指定Dockerfile ,可以根据Dockerfile创建一个镜像。

Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;

3. Dockerfile的一个例子。

centos的docker镜像地址 hub.docker.com/_/centos/ 可以在上面看到构建centos镜像的Dockerfile。如下:

FROM scratch
ADD centos-7-docker.tar.xz /

LABEL org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20181205"

CMD ["/bin/bash"]

centos镜像的Dockerfile里面有一个 FROM scratch 指令,scratch镜像是所有docker镜像的基础镜像,其他的镜像直接或间接继承scratch。

4. Dockerfile的一些规范。

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数。
  2. 指令按照从上到下,顺序执行。
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层,并对镜像进行提交。

5. Docker build 执行Dockerfile的大致流程。

  1. docker从基础镜像运行一个容器。
  2. 执行一条指令并对容器作出修改。
  3. 执行类似docker commit的操作提交一个新的镜像层。
  4. docker再基于刚提交的镜像运行一个新容器。
  5. 执行dockerfile中的下一条指令直到所有指令都执行完成。

也就是docker每次执行一条dockfile的指令都会形成一个新的镜像层,直到所有指令都执行完成

6. Dockerfile的一些保留字指令。

每条保留字指令都必须为大写字母且后面要跟随至少一个参数。

  • FROM 当前新镜像是基于哪个镜像的。
  • MAINTAINER 镜像维护者的姓名和邮箱地址。
  • RUN 容器构建时需要运行的命令。也就是执行RUN后面的命令。
  • EXPOSE 当前容器对外暴露出的端口,比如:tomcat对外暴露的8080端口。
  • WORKDIR 指定在创建容器后,终端默认登陆的进来工作目录。也就是我们进入docker容器的目录。
  • ENV 用来在构建镜像过程中设置环境变量。也就是声明一个变量。方便后面引用。比如:ENV MY_PATH /usr/mytest。这个环境变量MY_PATH 可以在后续的任何指令中使用。比如:WORKDIR $MY_PATH。
  • ADD 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包。

  • COPY 类似ADD,拷贝文件和目录到镜像中。但是不会解压,也不会处理URL,单纯的拷贝。

  • VOLUME 容器数据卷,用于数据保存和持久化工作。

  • CMD 指定一个容器启动时要运行的命令。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。CMD 指令支持三种格式:

        在/bin/sh 中执行,提供给需要交互的应用:  CMD <命令 参数> 
        使用 exec 执行,推荐方式: CMD ["可执行文件","参数1","参数2"] 
        在指定了ENTRYPOINT指令后,用CMD指定默认参数: CMD ["参数1","参数2"]
    
  • ENTRYPOINT 指定一个容器启动时要运行的命令。ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。

  • ONBUILD 父镜像在被子镜像继承后父镜像的onbuild被触发。也就是docker build运行Dockerfile时,如果这个Dockerfile继承某个父Dockerfile,那父Dockerfile的ONBUILD后面的指令会被执行。

6.1. 例子1:使用Dockerfile创建自己的centos镜像。

Dockerfile的内容如下:

FROM centos
MAINTAINER wk<wk@163.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash

上面的内容表示:

  • FROM centos 表示这个镜像从centos派生出来的。
  • MAINTAINER wk<wk@163.com> 表示镜像维护人创建人的名字和邮箱。
  • ENV MYPATH /usr/local 表示定义一个变量MYPATH的值是/usr/local。

  • WORKDIR $MYPATH 表示登录这个镜像运行的容器后,初始目录是/usr/local。$MYPATH是引用上面的MYPATH变量。

  • RUN yum -y install vim 表示在镜像里面运行命令yum -y install vim 安装vim命令工具。

  • RUN yum -y install net-tools 表示在镜像里面运行命令yum -y install net-tools 安装ifconfig命令工具。

  • EXPOSE 80 表示容器对外暴露 80端口。

  • CMD echo $MYPATH 表示在镜像里面运行命令echo $MYPATH 打印$MYPATH到控制台。

  • CMD echo "success--------------ok" 表示在镜像里面运行命令echo "success--------------ok" 打印success--------------ok到控制台。

  • CMD /bin/bash 表示在镜像里面运行命令/bin/bash。这个是最后一层镜像,也就是最终的镜像层。容器启动的时候也会运行 /bin/bash 命令。

使用上面的dockerfile生成镜像,命令格式如下:最后一个点表示当前目录。

docker build -f Dockerfile文件的位置 -t 新的镜像名:TAG .

运行的命令如下:表示使用当前目录下的Dockerfile文件创建了一个镜像mycentos,TAG是1.2。

docker build -f ./Dockerfile  -t mycentos:1.2 .

查看镜像,可以看到刚刚创建的镜像。

[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mycentos            1.2                 737ea05543bb        2 minutes ago       414MB

运行这个镜像之后,使用pwd命令可以看到当前目录是镜像文件定义的WORKDIR目录/usr/local ;也可以使用ifconfig命令了。镜像定义成功。

[root@localhost ~]# docker run -it mycentos:1.2
[root@25e927bac0b7 local]# pwd
/usr/local
[root@25e927bac0b7 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 648 (648.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

6.2. 例子2:查看镜像的变更历史。

查看镜像的变更历史,命令如下:

docker history 镜像名:TAG

运行如下,可以看到docker是每运行一个dockerfile命令就生成一个镜像层。

[root@localhost ~]# docker history mycentos:1.2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
737ea05543bb        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B                  
557b24a936f4        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
d40c270936e0        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
bd2ffd3ab0f6        9 minutes ago       /bin/sh -c #(nop)  EXPOSE 80                    0B                  
d176bcd23491        9 minutes ago       /bin/sh -c yum -y install net-tools             78.5MB              
bb75e3370010        9 minutes ago       /bin/sh -c yum -y install vim                   133MB               
341b26a9810c        20 minutes ago      /bin/sh -c #(nop) WORKDIR /usr/local            0B                  
9411d0c4629a        20 minutes ago      /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B                  
07524018ec26        20 minutes ago      /bin/sh -c #(nop)  MAINTAINER wk<wk@163.com>    0B                  
1e1148e4cc2c        3 months ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           3 months ago        /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>           3 months ago        /bin/sh -c #(nop) ADD file:6f877549795f4798a…   202MB

6.3. CMD/ENTRYPOINT指令的区别。

我们运行一个容器的命令如下:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

其中[COMMAND] [ARG...] 表示容器启动之后要运行的命令和参数。

Dockerfile中CMD和ENTRYPOINT的区别如下:

  • CMD/ENTRYPOINT 都是指定一个容器启动时要运行的命令。也就是使用docker run 运行容器的时候。要执行的命令[COMMAND] [ARG...] 可以由Dockerfile中CMD或者ENTRYPOINT 指定。比如:tomcat镜像就指定运行其容器的时候启动tomcat。

  • Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。如果运行容器docker run 的时候 [COMMAND] [ARG...] 存在,那Dockerfile中CMD会被这个命令替换。就不会执行Dockerfile中的CMD指定的命令。

  • docker run 之后的参数[COMMAND] [ARG...]会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合 。

    例子:如果centos镜像Dockerfile 中ENTRYPOINT指定的命令是 ls ,运行centos容器的命令是docker run -it centos -l,也就是[COMMAND] [ARG...]是-l 。结果运行centos容器之后执行的命令是 ls -l。就是把docker run中的[COMMAND] [ARG...]传递的值作为命令参数传递给ENTRYPOINT。

6.3.1. 示例如下:

  • 新建一个cmd命令的Dockerfile 。
FROM centos
CMD [ "ls"]
  • 新建一个ENTRYPOINT命令的Dockerfile 。
FROM centos
ENTRYPOINT ["ls"]
  • 以上面的2个Dockerfile 创建2个镜像。mycentoscmd 和mycentosentrypoint。
[root@localhost ~]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mycentosentrypoint   latest              0a7cbb21686b        20 seconds ago      202MB
mycentoscmd          latest              7fc40a4ef1eb        3 minutes ago       202MB
  • 运行容器。可以看到文件。相当于登录centos运行命令ls。如下:
[root@localhost ~]# docker run -it mycentoscmd
anaconda-post.log  dev    home  lib64  mnt  proc    run   srv  tmp    var
bin           etc    lib   media  opt  root    sbin  sys  usr
[root@localhost ~]# docker run -it mycentosentrypoint
anaconda-post.log  dev    home  lib64  mnt  proc    run   srv  tmp    var
bin           etc    lib   media  opt  root    sbin  sys  usr
  • 加 -l 参数运行容器。也就是[COMMAND] [ARG...]的值是-l。这时候mycentoscmd镜像会把-l当做一个命令,会报错;mycentosentrypoint会列出文件相当于登录centos运行命令ls -l。如下:
[root@localhost ~]# docker run -it mycentosentrypoint -l
total 12
-rw-r--r--.   1 root root 12076 Dec  5 01:37 anaconda-post.log
lrwxrwxrwx.   1 root root     7 Dec  5 01:36 bin -> usr/bin
drwxr-xr-x.   5 root root   360 Mar 16 17:32 dev
drwxr-xr-x.   1 root root    66 Mar 16 17:32 etc
drwxr-xr-x.   2 root root     6 Apr 11  2018 home
lrwxrwxrwx.   1 root root     7 Dec  5 01:36 lib -> usr/lib
lrwxrwxrwx.   1 root root     9 Dec  5 01:36 lib64 -> usr/lib64
drwxr-xr-x.   2 root root     6 Apr 11  2018 media
drwxr-xr-x.   2 root root     6 Apr 11  2018 mnt
drwxr-xr-x.   2 root root     6 Apr 11  2018 opt
dr-xr-xr-x. 205 root root     0 Mar 16 17:32 proc
dr-xr-x---.   2 root root   114 Dec  5 01:37 root
drwxr-xr-x.  11 root root   148 Dec  5 01:37 run
lrwxrwxrwx.   1 root root     8 Dec  5 01:36 sbin -> usr/sbin
drwxr-xr-x.   2 root root     6 Apr 11  2018 srv
dr-xr-xr-x.  13 root root     0 Mar 12 02:00 sys
drwxrwxrwt.   7 root root   132 Dec  5 01:37 tmp
drwxr-xr-x.  13 root root   155 Dec  5 01:36 usr
drwxr-xr-x.  18 root root   238 Dec  5 01:36 var
[root@localhost ~]# docker run -it mycentoscmd -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.

results matching ""

    No results matching ""