美文网首页Docker容器Java-Python-Django社区程序员
【Docker学习笔记(三)】Dockerfile解析

【Docker学习笔记(三)】Dockerfile解析

作者: 苍云横渡 | 来源:发表于2018-07-31 23:04 被阅读19次

    【Docker 学习笔记目录】


    1 Dockerfile 概述

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

    构建三步骤:

    • 1、编写 Dockerfile 文件
    • 2、docker build
    • 3、docker run

    Dockerfile 指令:

    • 1、大小写不敏感,但是建议全部使用大写
    • 2、指令按照从上到下顺序执行
    • 3、每条指令都会创建一个新的镜像层,并对镜像进行提交

    Dockerfile 构建过程解析:

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

    2 Dockerfile 指令

    1、FROM

    • 必须放在 Dockerfile 的第一行,表示从哪个 baseimage 开始构建

    2、MAINTAINER

    • 可选的,用来标识镜像作者的姓名和邮箱地址

    3、RUN

    • 容器构建时需要运行的命令

    4、EXPOSE

    • 当前容器对外暴露出的端口

    5、WORKDIR

    • 指定在创建容器后终端默认登录进来的工作目录,一个落脚点

    6、ENV

    • 用来在构建镜像过程中设置环境变量
    • 这个环境变量可以在后续的指令中使用
    • eg:
      • ENV MY_PATH /usr/mytest
      • WORKDIR $MY_PATH

    7、ADD

    • 将宿主机目录下的文件拷贝进镜像且 ADD 命令会自动处理 URL 和解压 tar 压缩包

    8、COPY

    • 类似 ADD,拷贝文件或目录到镜像中
      • COPY SRC DEST
      • COPY ["SRC", "DEST"]

    9、VOLUME

    • 容器数据卷,用于数据保存和持久化

    10、CMD

    • 指定容器启动时要运行的命令
      • shell 格式:CMD <命令>
      • exec 格式:CMD ["可执行文件", "参数1", "参数2" ...]
    • Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

    11、ENTRYPOINT

    • 指定容器启动时要运行的命令
      • exec 格式:ENTRYPOINT ["COMMAND","arg1" ...]
    • Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效,ENTRYPOINT 不会被 docker run 之后的参数替换
      • 不过,docker run的--entrypoint可以覆盖Dockerfile中ENTRYPOINT设置的命令

    12、ONBUILD

    • 当构建一个被继承的 Dockerfile 时运行命令,父镜像在被子继承后,父镜像的 ONBUILD 会被触发

    3 案例

    3.1 Base镜像(scratch)

    Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的,即 FROM scratch

    3.2 自定义镜像 mycentos

    (1)编写 Dockerfile。因为默认 centos 镜像不包含 vim 和 ifconfig,且默认路径为根目录。所以我们自定义 mycentos 镜像具备功能:vim编辑器、查看网络配置 ifconfig、登录后的默认路径

    FROM centos
    MAINTAINER haha<haha@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
    

    (2)构建镜像。执行命令 docker build -f <DockerfilePath> -t <新镜像名>[:TAG] .

    [root@localhost mydocker]# docker build -f /mydocker/Dockerfile -t mycentos:1.3 .
    Sending build context to Docker daemon  2.048kB
    Step 1/10 : FROM centos
     ---> 49f7960eb7e4
    Step 2/10 : MAINTAINER haha<haha@163.com>
     ---> Running in abba9b25097a
    Removing intermediate container abba9b25097a
     ---> 6b31565e745c
    ...
    ...
    ...
    Step 9/10 : CMD echo "SUCCESS----------------OK"
     ---> Running in ec3732fd9697
    Removing intermediate container ec3732fd9697
     ---> f85df2928359
    Step 10/10 : CMD /bin/bash
     ---> Running in 8c690565ae88
    Removing intermediate container 8c690565ae88
     ---> 9fa354c5af84
    Successfully built 9fa354c5af84
    Successfully tagged mycentos:1.3
    [root@localhost mydocker]# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    mycentos            1.3                 9fa354c5af84        3 minutes ago       429MB
    

    (3)运行。执行命令 docker run -it mycentos:1.3,并测试 vim 和 ifconfig

    [root@localhost mydocker]# docker run -it mycentos:1.3
    [root@c4c9780e9bd2 local]# vim hi.txt
    [root@c4c9780e9bd2 local]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet ***********  netmask ***********  broadcast ***********
            ether ***********  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 ***********  netmask ***********
            loop  txqueuelen 1000  (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
    

    (4)查看镜像变更历史,使用命令 docker history <镜像ID>

    [root@localhost mydocker]# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    mycentos            1.3                 769456b1e3b6        5 minutes ago       429MB
    [root@localhost mydocker]# docker history 769456b1e3b6
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    769456b1e3b6        5 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B                  
    9d471d49e890        5 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
    d8af111f35dc        5 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
    478098996ebd        5 minutes ago       /bin/sh -c #(nop)  EXPOSE 80                    0B                  
    5e4dd31fa027        5 minutes ago       /bin/sh -c yum -y install net-tools             87.2MB              
    bea7db715bc2        6 minutes ago       /bin/sh -c yum -y install vim                   142MB               
    5fd476dce352        8 minutes ago       /bin/sh -c #(nop) WORKDIR /usr/local            0B                  
    c1463e67e0b3        16 minutes ago      /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B                  
    6b31565e745c        16 minutes ago      /bin/sh -c #(nop)  MAINTAINER haha<haha@163.…   0B                  
    49f7960eb7e4        8 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
    <missing>           8 weeks ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
    <missing>           8 weeks ago         /bin/sh -c #(nop) ADD file:8f4b3be0c1427b158…   200MB  
    

    3.3 CMD/ENTRYPOINT 镜像

    CMD:Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

    我们可以查看到官方 tomcat 的 Dockerfile 中最后一个 CMD 命令为:CMD ["catalina.sh", "run"],则表示直接 docker run tomcat会输出 tomcat 运行日志

    [root@localhost mydocker]# docker run tomcat
    31-Jul-2018 13:15:09.738 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.5.32
    31-Jul-2018 13:15:09.741 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Jun 20 2018 19:50:35 UTC
    31-Jul-2018 13:15:09.741 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number:         8.5.32.0
    31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
    31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            3.10.0-862.9.1.el7.x86_64
    31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
    31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/lib/jvm/java-8-openjdk-amd64/jre
    

    当我们执行命令 docker run -it -p 7777:8080 tomcat ls -l,可以注意到,CMD 被 docker run 后面的参数替换了

    [root@localhost mydocker]# docker run -it -p 7777:8080 tomcat ls -l
    total 92
    -rw-r-----. 1 root root  57092 Jun 20 19:53 LICENSE
    -rw-r-----. 1 root root   1723 Jun 20 19:53 NOTICE
    -rw-r-----. 1 root root   7138 Jun 20 19:53 RELEASE-NOTES
    -rw-r-----. 1 root root  16246 Jun 20 19:53 RUNNING.txt
    drwxr-x---. 2 root root   4096 Jul 17 18:16 bin
    drwx--S---. 2 root root    238 Jun 20 19:53 conf
    drwxr-sr-x. 3 root staff    19 Jul 17 18:16 include
    drwxr-x---. 2 root root   4096 Jul 17 18:15 lib
    drwxr-x---. 2 root root      6 Jun 20 19:50 logs
    drwxr-sr-x. 3 root staff   151 Jul 17 18:16 native-jni-lib
    drwxr-x---. 2 root root     30 Jul 17 18:15 temp
    drwxr-x---. 7 root root     81 Jun 20 19:51 webapps
    drwxr-x---. 2 root root      6 Jun 20 19:50 work
    

    ENTRYPOINT:docker run 之后的参数会被当做参数传递给 ENTRYPOINT ,之后形成新的命令组合

    首先创建一个新的镜像 myip,其 Dockerfile 如下:

    FROM centos
    RUN yum install -y curl
    CMD "curl", "-s", "https://ip.cn"
    
    [root@localhost mydocker]# vim Dockerfile2
    [root@localhost mydocker]# docker build -f /mydocker/Dockerfile2 -t myip .
    Sending build context to Docker daemon  3.072kB
    Step 1/3 : FROM centos
     ---> 49f7960eb7e4
    Step 2/3 : RUN yum install -y curl
     ---> Using cache
     ---> 8e148a68fc86
    Step 3/3 : CMD ["curl", "-s", "https://ip.cn"]
     ---> Running in 7be857257291
    Removing intermediate container 7be857257291
     ---> 6a341f6d2b42
    Successfully built 6a341f6d2b42
    Successfully tagged myip:latest
    [root@localhost mydocker]# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    myip                latest              036adbaf59cb        13 seconds ago      286MB
    

    接着执行命令 docker run -it myip

    [root@localhost mydocker]# docker run -it myip
    当前 IP:********* 来自:***省***市 ***
    [root@localhost mydocker]# 
    

    如果我们想显示更多的信息,比如 HTTP 头信息,则需要加上参数 -i (即 curl -s -i https://ip.cn)。那么是不是执行 docker run myip -i 呢?我们可以试试

    [root@localhost mydocker]# docker run myip -i
    docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"-i\": executable file not found in $PATH": unknown.
    

    可以看到 executable file not found 。因为跟在镜像名后面的是 command ,运行时会替换 CMD 的默认值。在这里的 -i 替换了原来的 CMD ,而不是添加在原来的 curl -s https://ip.cn 后面。而 -i 根本不是命令,所以自然找不到啦

    那么要如何加这个 -i 参数才能运行呢?答案就是 docker run myip curl -s https:ip.cn -i

    [root@localhost lycai]# docker run myip curl -s https://ip.cn -i
    HTTP/1.1 200 OK
    Date: Tue, 31 Jul 2018 13:50:12 GMT
    Content-Type: text/html; charset=UTF-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Set-Cookie: __cfduid=************************; expires=Wed, 31-Jul-19 13:50:11 GMT; path=/; domain=.ip.cn; HttpOnly
    Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    Server: cloudflare
    CF-RAY: 4430885bdd39aa50-SIN
    
    当前 IP:******** 来自:***省***市 ***
    

    现在我们再编写一个 Dockerfile3,制作 ENTRYPOINT 版查询 IP 信息的镜像 myip_new

    FROM centos
    RUN yum install -y curl
    ENTRYPOINT ["curl", "-s", "https://ip.cn"]
    

    最后就可以用 docker run myip_new -i

    [root@localhost mydocker]# docker run myip_new -i
    HTTP/1.1 200 OK
    Date: Tue, 31 Jul 2018 13:55:06 GMT
    Content-Type: text/html; charset=UTF-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Set-Cookie: __cfduid=************************; expires=Wed, 31-Jul-19 13:55:05 GMT; path=/; domain=.ip.cn; HttpOnly
    Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    Server: cloudflare
    CF-RAY: 44308f897c6831ec-SIN
    
    当前 IP:********* 来自:***省***市 ***
    

    其相当于原来的 myip 镜像的 Dockerfile 中最后一行变成了 CMD ["curl", "-s", "-i", "https://ip.cn"],而这个 -i 是作为参数传进去的

    4 总结

    相关文章

      网友评论

        本文标题:【Docker学习笔记(三)】Dockerfile解析

        本文链接:https://www.haomeiwen.com/subject/cwyhvftx.html