zoukankan      html  css  js  c++  java
  • Docker的Dockerfile

    参考资料:B站狂神教程
    https://www.bilibili.com/video/BV1og4y1q7M4?p=26

    Dockerfile是什么

    Dockerfile是一个构建Docker镜像的命令参数脚本。

    构建镜像的步骤:

    1. 编写一个Dockerfile文件
    2. docker build 构建镜像
    3. docker run 运行镜像
    4. docker push 发布镜像

    Dockerfile的构建过程

    构建Dockerfile需要了解很多能写在Dockerfile里的命令:
    https://docs.docker.com/engine/reference/builder/#from

    这是官方文档,里面有部分命令,不知道全不全,肯定是够用了。

    还有这张图片,很有意思:

    UTOOLS1593876365844.png

    每个指令都会创建提交一个新的镜像层,并提交。最后跑起来的时候再加一层可写层:

    UTOOLS1593876549281.png

    Dockerfile的指令

    还是这个文档:https://docs.docker.com/engine/reference/builder/#from

    看一下命令大概的分类:

    UTOOLS1593876871230.png

    从左到右依次是构建的命令,连接工作目录等的命令和启动执行的命令。常用命令就是上面那张铁锈红色的图。

    FROM        # 基础镜像,一切从这里开始构建
    MAINTAINER  # 镜像是谁写的,姓名+邮箱
    RUN         # 镜像构建的时候需要运行的命令
    ADD         # 步骤,比如要构建tomcat镜像,这里就放tomcat压缩包
    WORKDIR     # 镜像的工作目录
    VOLUME      # 挂载目录
    EXPOSE      # 暴露端口配置
    CMD         # 指定这个容器启动的时候要运行的命令
                # 只有最后一个会生效,而且可被替代
                # 比如自己构建centos,指定/bin/bash来直接进入命令行交互模式
    ENTRYPOINT  # 指定这个容器启动的时候要运行的命令,可以追加命令
    ONBUILD     # 触发指令。当构建一个被继承的Dockerfile,这时候就会运行ONBUILD的指令
    COPY        # 类似ADD,将我们的文件拷贝到镜像中
    ENV         # 构建的时候设置环境变量
    

    区分一下CMD和ENTRYPOINT。比如我们在Dockerfile里CMD ls -a,然后run的时候在后面跟上命令ls -l,就会替换掉-a,变成-l。但如果ENTRYPOINT ls -a,run的时候-l,就会变成ls -a -l

    CMD与ENTRYPOOINT的区别

    实践一下CMD,写一个最简单的dockerfile:

    FROM centos
    CMD ["ls","-a"]
    

    用CMD加命令可以通过中括号来构建,就跟上面代码一样。把它build起来:

    root@KitDevVps:/home/dockerfiles# docker build -f cmd-dockerfile -t cmdtest .
    Sending build context to Docker daemon  3.072kB
    Step 1/2 : FROM centos
     ---> 831691599b88
    Step 2/2 : CMD ["ls","-a"]
     ---> Running in 21e24114cf28
    Removing intermediate container 21e24114cf28
     ---> 9ca8e41f3bf4
    Successfully built 9ca8e41f3bf4
    Successfully tagged cmdtest:latest
    

    直接run这个镜像:

    root@KitDevVps:/home/dockerfiles# docker run 9ca8e41f3bf4
    .
    ..
    .dockerenv
    bin
    dev
    etc
    home
    lib
    lib64
    lost+found
    media
    mnt
    opt
    proc
    root
    run
    sbin
    srv
    sys
    tmp
    usr
    var
    

    发现它直接就执行了ls -a这个命令。我们知道CMD是无法追加命令的,只能替换,我们run一下这个容器,然后加上-l这个option:

    root@KitDevVps:/home/dockerfiles# docker run 9ca8e41f3bf4 -l
    docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: "-l": executable file not found in $PATH": unknown.
    

    发现报了一个Error。这是因为-l直接替换了整个CMD,连ls都替换掉了,由本来的ls -a变成了-l。没有-l这种命令,所以报错。我们现在想执行ls -al命令,就只能再run出容器时直接加上这个命令,以替换原来的ls -a

    root@KitDevVps:/home/dockerfiles# docker run 9ca8e41f3bf4 ls -al
    total 56
    drwxr-xr-x   1 root root 4096 Jul  5 02:33 .
    drwxr-xr-x   1 root root 4096 Jul  5 02:33 ..
    -rwxr-xr-x   1 root root    0 Jul  5 02:33 .dockerenv
    lrwxrwxrwx   1 root root    7 May 11  2019 bin -> usr/bin
    drwxr-xr-x   5 root root  340 Jul  5 02:33 dev
    drwxr-xr-x   1 root root 4096 Jul  5 02:33 etc
    drwxr-xr-x   2 root root 4096 May 11  2019 home
    lrwxrwxrwx   1 root root    7 May 11  2019 lib -> usr/lib
    lrwxrwxrwx   1 root root    9 May 11  2019 lib64 -> usr/lib64
    drwx------   2 root root 4096 Jun 11 02:35 lost+found
    drwxr-xr-x   2 root root 4096 May 11  2019 media
    drwxr-xr-x   2 root root 4096 May 11  2019 mnt
    drwxr-xr-x   2 root root 4096 May 11  2019 opt
    dr-xr-xr-x 104 root root    0 Jul  5 02:33 proc
    dr-xr-x---   2 root root 4096 Jun 11 02:35 root
    drwxr-xr-x  11 root root 4096 Jun 11 02:35 run
    lrwxrwxrwx   1 root root    8 May 11  2019 sbin -> usr/sbin
    drwxr-xr-x   2 root root 4096 May 11  2019 srv
    dr-xr-xr-x  13 root root    0 Jul  5 02:33 sys
    drwxrwxrwt   7 root root 4096 Jun 11 02:35 tmp
    drwxr-xr-x  12 root root 4096 Jun 11 02:35 usr
    drwxr-xr-x  20 root root 4096 Jun 11 02:35 var
    

    再实践一下ENTRYPOINT,写一个dockerfile,依然用中括号写命令:

    FROM centos
    ENTRYPOINT ["ls","-a"]
    

    build起镜像来:

    root@KitDevVps:/home/dockerfiles# docker build -f entrypoint-dockerfile -t entrypointtest .
    Sending build context to Docker daemon  4.096kB
    Step 1/2 : FROM centos
     ---> 831691599b88
    Step 2/2 : ENTRYPOINT ["ls","-a"]
     ---> Running in e4fdc1c58ec7
    Removing intermediate container e4fdc1c58ec7
     ---> 52b32cc2192c
    Successfully built 52b32cc2192c
    Successfully tagged entrypointtest:latest
    

    run一下:

    root@KitDevVps:/home/dockerfiles# docker run 52b32cc2192c 
    .
    ..
    .dockerenv
    bin
    dev
    etc
    home
    lib
    lib64
    lost+found
    media
    mnt
    opt
    proc
    root
    run
    sbin
    srv
    sys
    tmp
    usr
    var
    

    加个option-l

    root@KitDevVps:/home/dockerfiles# docker run 52b32cc2192c -l
    total 56
    drwxr-xr-x   1 root root 4096 Jul  5 02:38 .
    drwxr-xr-x   1 root root 4096 Jul  5 02:38 ..
    -rwxr-xr-x   1 root root    0 Jul  5 02:38 .dockerenv
    lrwxrwxrwx   1 root root    7 May 11  2019 bin -> usr/bin
    drwxr-xr-x   5 root root  340 Jul  5 02:38 dev
    drwxr-xr-x   1 root root 4096 Jul  5 02:38 etc
    drwxr-xr-x   2 root root 4096 May 11  2019 home
    lrwxrwxrwx   1 root root    7 May 11  2019 lib -> usr/lib
    lrwxrwxrwx   1 root root    9 May 11  2019 lib64 -> usr/lib64
    drwx------   2 root root 4096 Jun 11 02:35 lost+found
    drwxr-xr-x   2 root root 4096 May 11  2019 media
    drwxr-xr-x   2 root root 4096 May 11  2019 mnt
    drwxr-xr-x   2 root root 4096 May 11  2019 opt
    dr-xr-xr-x 107 root root    0 Jul  5 02:38 proc
    dr-xr-x---   2 root root 4096 Jun 11 02:35 root
    drwxr-xr-x  11 root root 4096 Jun 11 02:35 run
    lrwxrwxrwx   1 root root    8 May 11  2019 sbin -> usr/sbin
    drwxr-xr-x   2 root root 4096 May 11  2019 srv
    dr-xr-xr-x  13 root root    0 Jul  5 02:33 sys
    drwxrwxrwt   7 root root 4096 Jun 11 02:35 tmp
    drwxr-xr-x  12 root root 4096 Jun 11 02:35 usr
    drwxr-xr-x  20 root root 4096 Jun 11 02:35 var
    

    可以成功执行。这个时候如果直接写ls -al

    root@KitDevVps:/home/dockerfiles# docker run 52b32cc2192c ls -al
    ls: cannot access 'ls': No such file or directory
    

    注意,如果dockerfile文件直接命名为"Dockerfile",build的时候就不需要加-f来指定对应的dockerfile文件了,它可以自动寻找到。

    实践一个dockerfile

    看一下centos7的dockerfile:

    UTOOLS1593878458487.png

    首先,几乎所有镜像都是FROM scratch,然后配置需要的软件和配置来进行构建。

    然后ADD上centos的压缩包。

    看一下ubuntu的dockerfile:

    UTOOLS1593879318200.png

    我们注意到用docker镜像run起来的ubuntu没有vim和ifconfig命令:

    root@KitDevVps:~# docker run -d -it --name ubuntu01 ubuntu
    daec7691f786dffa97ae5f757212da17da2c7591aeaa7a5c215217d0904f3089
    root@KitDevVps:~# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
    daec7691f786        ubuntu              "/bin/bash"              4 seconds ago       Up 3 seconds                             ubuntu01
    1cdd55fd90c5        nginx               "/docker-entrypoint.…"   36 hours ago        Up 32 hours         0.0.0.0:80->80/tcp   nginx1
    root@KitDevVps:~# docker attach ubuntu01
    root@daec7691f786:/# vim
    bash: vim: command not found
    root@daec7691f786:/# ifconfig
    bash: ifconfig: command not found
    

    我们自己构建一个ubuntu:

    编写dockerfile文件

    FROM centos
    MAINTAINER Kit<xxxxxx@xx.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    RUN apt-get update
    RUN apt-get install -y vim
    RUN apt-get install -y net-tools
    
    EXPOSE 8888
    
    CMD echo $MYPATH
    CMD echo "build succeed"
    CMD /bin/bash
    

    其中环境变量ENV是键值对的形式,MYPATH是key,/usr/local是值。

    WORKDIR是用$号引用了环境变量。

    使用RUN来update,然后安装了vim和net-tools。实际上执行三条命令不需要写三个RUN,这样会生成三层,太浪费,可以像上面ubuntu的Dockerfile那样,用&&等符号连接起来,要换行就用上,不换行可以一直用&&来拼接,只写一个RUN

    最后一行CMD /bin/bash是运行起来之后启动bash命令行。

    注意,有一个常用的ADD指令这里没有用到,ADD是添加压缩文件的,可以自动解压,压缩文件包名之后可以跟一个地址,选择解压的位置。这个位置当然是容器内的目录。看上面ubuntu镜像的ADD后面的压缩包名后加了个/,表示解压在根目录。

    通过dockerfile构建镜像

    使用docker build命令。-f后面跟dockerfile名字,-t后面跟自己给镜像取的名字,也可以加上tag。最后的.是镜像生成的位置:

    root@KitDevVps:/home/dockerfiles# docker build -f centos-dockerfile -t myubuntu:1.0 .
    Sending build context to Docker daemon  2.048kB
    Step 1/11 : FROM centos
     ---> 831691599b88
    Step 2/11 : MAINTAINER Kit<xxxxxx@xx.com>
     ---> Running in f1f196999014
    Removing intermediate container f1f196999014
     ---> 67670905b570
    Step 3/11 : ENV MYPATH /usr/local
     ---> Running in 017f52d55537
    Removing intermediate container 017f52d55537
     ---> 82b77bd524e0
    Step 4/11 : WORKDIR $MYPATH
     ---> Running in a50c62fe9048
    Removing intermediate container a50c62fe9048
     ---> 292ddb55bacb
    Step 5/11 : RUN apt-get update
     ---> Running in 3d6d1e0ef4ce
    /bin/sh: apt-get: command not found
    The command '/bin/sh -c apt-get update' returned a non-zero code: 127
    

    很尴尬,镜像竟然不能运行apt-get,不过一部分的过程可以看到。我就不再搞了,基本用不到生成ubuntu镜像这种需求,不折腾了。dockerfile里的命令是没有错的。

    我们修改一下dockerfile,将apt指令改为普通的echo:

    FROM centos
    MAINTAINER Kit<xxxxxx@xx.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    RUN echo "step 1"
    RUN echo "step 2"
    RUN echo "step 3"
    
    CMD echo $MYPATH
    CMD echo "build succeed"
    CMD /bin/bash
    

    build镜像

    build一下:

    root@KitDevVps:/home/dockerfiles# docker build -f centos-dockerfile -t myubuntu:1.0 .
    Sending build context to Docker daemon  2.048kB
    Step 1/10 : FROM centos
     ---> 831691599b88
    Step 2/10 : MAINTAINER Kit<xxxxxx@xx.com>
     ---> Running in 1dedfc7bd7cd
    Removing intermediate container 1dedfc7bd7cd
     ---> b810f07548a3
    Step 3/10 : ENV MYPATH /usr/local
     ---> Running in 5f8ce5a07590
    Removing intermediate container 5f8ce5a07590
     ---> 578eab12c981
    Step 4/10 : WORKDIR $MYPATH
     ---> Running in b371dc06fd20
    Removing intermediate container b371dc06fd20
     ---> 7abf094e042e
    Step 5/10 : RUN echo "step 1"
     ---> Running in 0c65382a6491
    step 1
    Removing intermediate container 0c65382a6491
     ---> 04bf696c460e
    Step 6/10 : RUN echo "step 2"
     ---> Running in 1276c444e36c
    step 2
    Removing intermediate container 1276c444e36c
     ---> d005e474c20c
    Step 7/10 : RUN echo "step 3"
     ---> Running in 02de174de709
    step 3
    Removing intermediate container 02de174de709
     ---> 8f7f565d2061
    Step 8/10 : CMD echo $MYPATH
     ---> Running in 028888e7f8c8
    Removing intermediate container 028888e7f8c8
     ---> 7535a914d720
    Step 9/10 : CMD echo "build succeed"
     ---> Running in b8eb3004dc32
    Removing intermediate container b8eb3004dc32
     ---> f416fc8cb156
    Step 10/10 : CMD /bin/bash
     ---> Running in b531285dbe9d
    Removing intermediate container b531285dbe9d
     ---> dc3664ede0fc
    Successfully built dc3664ede0fc
    Successfully tagged myubuntu:1.0
    

    这次成功了,其中输出的三次step123都输出了。

    可以通过docker history 镜像id来查看这个镜像是怎么一步一步构建起来的。看一下我们新构建的镜像:

    root@KitDevVps:/home/dockerfiles# docker history dc3664ede0fc
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    dc3664ede0fc        2 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B                  
    f416fc8cb156        2 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
    7535a914d720        2 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
    8f7f565d2061        2 minutes ago       /bin/sh -c echo "step 3"                        0B                  
    d005e474c20c        2 minutes ago       /bin/sh -c echo "step 2"                        0B                  
    04bf696c460e        2 minutes ago       /bin/sh -c echo "step 1"                        0B                  
    7abf094e042e        2 minutes ago       /bin/sh -c #(nop) WORKDIR /usr/local            0B                  
    578eab12c981        2 minutes ago       /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B                  
    b810f07548a3        2 minutes ago       /bin/sh -c #(nop)  MAINTAINER Kit<xxxxxx@xx.…   0B                  
    831691599b88        2 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
    <missing>           2 weeks ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
    <missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:84700c11fcc969ac0…   215MB               
    

    比较全面的Dockerfile展示

    上面写的Dockerfile都很儿戏,下面是狂神视频教程里写的一段tomcat的Dockerfile:

    UTOOLS1593918821757.png

    我不搞JAVA,不太懂,但是这一段Dockerfile里很全面。

    1. 先是FROM,基于centos镜像来构建。
    2. MAINTAINER,构建者的信息。
    3. COPY了一个readme文件进去,并指定了目录,可以写一些基本的使用文档在里面。
    4. ADD了两个必须的压缩包,并且指定了解压位置。
    5. RUN了一条命令,安装了vim。
    6. ENV设置一个环境变量,取名MYPATH。
    7. WORKDIR设置当前的工作目录,直接使用上面设置的环境变量MYPATH。如果用exec进入镜像,默认会在这个目录下。
    8. 连用几个ENV设置了一些必须的环境变量,都是JAVA和tomcat的,我看不懂。.NET Core的官方示例Dockerfile中也没有ENV,我推测ENV可以用来设置数据库连接字符串等。
    9. EXPOSE暴露8080端口。
    10. CMD指定运行的指令,这里应该是启动tomcat的指令。
  • 相关阅读:
    Java IO流
    博客园禁止pc端以及手机端选中复制粘贴
    eclipse debug模式出现 source not found
    Winform之跨线程访问控件(在进度条上显示字体)
    WPF中DataGrid的ComboBox的简单绑定方式(绝对简单)
    WPF制作QQ列表(仿qq列表特效)
    WPF柱状图(支持数据库动态更新)之组件的数据动态化
    WPF柱状图(支持数据库动态更新)
    WPF仿微软事件和属性窗体,效果更炫!
    DataGrid缓冲加载数据
  • 原文地址:https://www.cnblogs.com/Kit-L/p/13238619.html
Copyright © 2011-2022 走看看