美文网首页Docker
S2:创建镜像

S2:创建镜像

作者: 睦月MTK | 来源:发表于2020-01-07 20:40 被阅读0次

    声明:所有的实验示例大部分来自《learn-docker-in-a-month-of-lunches》的作者Elton Stoneman,但运行结果并不都是照搬,大部分实验结果可能与原书不同


    一、基础概念
    1. Q:什么是镜像?
      A:镜像就是一系列只读的命令,这些命令被用来指导如何创建一个容器。一般来说,镜像一般会基于在别的镜像上,然后再此基础上添加用户的个性化内容。
    2. Q:什么是镜像层?
      A:在Dockerfile中的每一行命令都会使得Docker创建一个对应的镜像层,所以镜像就相当一堆镜像层的集合。镜像实际上是一个个只读的文件,被存储在Docker的本地缓存中。Docker在根据Dockerfile创建镜像时,会自动识别可复用的镜像层,这样就避免了重复创建的开销,这也时为什么Docker如此便捷、轻量化并且快速的原因。
    3. Q:什么是Dokcerfile?
      A:Dockerfile就是一个脚本,该脚本定义了如何打包你的应用,如何去生成一个对应的镜像。

    二、编写Dockerfile

    附:Dockerfile的官方文档

    1. 克隆Elton Stoneman在github上的代码(点颗星应该不算白嫖了吧,咳咳...)
    $ git clone https://github.com/sixeyed/diamol
    
    1. 进入到项目目录下
    $ cd diamol/ch03/exercises/web-ping
    
    1. 查看分析Dockerfile
    • 查看项目目录下的Dockerfile
    $ cat Dockerfile
    
    • 分析Dockerfile
    FROM diamol/node
    

    基于diamol/node镜像

    ENV TARGET="blog.sixeyed.com"
    ENV METHOD="HEAD"
    ENV INTERVAL="3000"
    

    设置容器的环境变量

    WORKDIR /web-ping
    

    设置容器的文件系统上的项目文件夹

    COPY app.js .
    

    哪些数据需要从本地文件系统复制到容器的文件系统里,dot代表容器的项目目录

    CMD ["node", "/web-ping/app.js"]
    

    当Docker运行一个容器时,执行这个命令


    三、分析镜像的创建过程
    1. 根据Dockerfile创建镜像(确保你自己在项目的目录下,即Dockerfile所在的目录下)
    $ docker image build --tag web-ping .
    

    注意最后面还有个dot!!!

    1. 分析镜像创建时输出的日志信息
    Sending build context to Docker daemon  4.096kB
    Step 1/7 : FROM diamol/node
     ---> 9dfa73010b19
    

    step1/7说明执行的是Dockerfile里面的第1条命令“FROM diamol/node”,并且一共有7步
    ---> 9dfa73010b19说明执行完第一条命令之后生成的镜像id为9dfa73010b19

    Step 2/7 : ENV TARGET="blog.sixeyed.com"
     ---> Running in caa76a3bbee5
    Removing intermediate container caa76a3bbee5
     ---> 641e96bf92c8
    Step 3/7 : ENV METHOD="HEAD"
     ---> Running in 72f20ca7c727
    Removing intermediate container 72f20ca7c727
     ---> b638ad06534b
    Step 4/7 : ENV INTERVAL="3000"
     ---> Running in db6d5653dfac
    Removing intermediate container db6d5653dfac
     ---> e20424bc0a05
    Step 5/7 : WORKDIR /web-ping
     ---> Running in 840065185c08
    Removing intermediate container 840065185c08
     ---> 4591d6e9216f
    

    ---> Running in caa76a3bbee5
    Removing intermediate container xxx
    说明执行类的命令,会先运行一个临时的容器,然后根据更改后的容器创建一个新的镜像

    Step 6/7 : COPY app.js .
     ---> 7fea8227d6f0
    Step 7/7 : CMD ["node", "/web-ping/app.js"]
     ---> Running in d169d4bb485c
    Removing intermediate container d169d4bb485c
     ---> df5c3f2e5d42
    Successfully built df5c3f2e5d42
    Successfully tagged web-ping:latest
    

    Successfully built说明创建镜像成功,镜像id为df5c3f2e5d42

    1. 查看本地缓存的镜像

      • 查看镜像
      $ docker image ls
      REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
      web-ping                       latest              df5c3f2e5d42        23 minutes ago      75.3MB
      diamol/node                    latest              9dfa73010b19        7 months ago        75.3MB
      
      • 查看所有的镜像,包括临时镜像(即上一步骤中的那些临时镜像)
      $ docker image ls --all
      REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
      web-ping                       latest              df5c3f2e5d42        7 minutes ago       75.3MB
      <none>                         <none>              7fea8227d6f0        7 minutes ago       75.3MB
      <none>                         <none>              4591d6e9216f        7 minutes ago       75.3MB
      <none>                         <none>              e20424bc0a05        7 minutes ago       75.3MB
      <none>                         <none>              b638ad06534b        7 minutes ago       75.3MB
      <none>                         <none>              641e96bf92c8        7 minutes ago       75.3MB
      diamol/node                    latest              9dfa73010b19        7 months ago        75.3MB
      
      • 模糊搜索本地的镜像
      $ docker image ls w*
      REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
      web-ping            latest              df5c3f2e5d42        31 minutes ago      75.3MB
      
    2. 根据这个镜像创建一个容器,并查看输出的日志

      • 直接运行
      $ docker container run web-ping
      ** web-ping ** Pinging: blog.sixeyed.com; method: HEAD; 3000ms intervals
      Making request number: 1; at 1578388826200
      Got response status: 200 at 1578388828160; duration: 1960ms
      

      ping的地址为blog.sixeyed.com ,方法为HEAD ,间隔为3s ,可以发现,这些都被设置在Dockerfile的环境变量里

      • 自定义环境变量创建容器
      $ docker container run --env TARGET=baidu.com --name wt1 web-ping
      ** web-ping ** Pinging: baidu.com; method: HEAD; 3000ms intervals
      Making request number: 1; at 1578389292540
      Got response status: 302 at 1578389292703; duration: 163ms
      

      --name指的是为该容器命个名,以后操作该容器就可以通过该名字了,不必通过容器ID了
      可以看到ping的地址已经变成了baidu.com

    3. 修改app.js,然后重新创建一个镜像,并分析创建过程的变化

      • 重新创建一个镜像,命名为web-ping-modappjs
      //随便修改一下app.js,加个空行也行
      $ docker image build --tag web-ping-modappjs .
      
      • 分析新镜像的创建过程
      Step 1/7 : FROM diamol/node
       ---> 9dfa73010b19
      Step 2/7 : ENV TARGET="blog.sixeyed.com"
       ---> Using cache
       ---> 641e96bf92c8
      Step 3/7 : ENV METHOD="HEAD"
       ---> Using cache
       ---> b638ad06534b
      Step 4/7 : ENV INTERVAL="3000"
       ---> Using cache
       ---> e20424bc0a05
      Step 5/7 : WORKDIR /web-ping
       ---> Using cache
       ---> 4591d6e9216f
      

      ---> Using cache说明Docker识别出这个镜像层可以被复用,所以会自动使用本地镜像缓存中已有的镜像

      Step 6/7 : COPY app.js .
       ---> ef985b5a110e
      Step 7/7 : CMD ["node", "/web-ping/app.js"]
       ---> Running in 84847a3f59f2
      Removing intermediate container 84847a3f59f2
       ---> 5720186d593f
      Successfully built 5720186d593f
      Successfully tagged web-ping-modappjs:latest
      

      可以看到第6步和第7步都没有使用镜像,因为第6步中的app.js确实被更改了,第七步没有使用缓存的镜像是因为第7步的镜像是建立在第6步的基础上的,如果之前某个镜像发生过变化,则接下来的所有镜像都会被强制重新生成,所以根据这个原理,优化Dockerfile就势在必行了

    4. 查看指定镜像的镜像层信息(镜像层大小、ID、创建时间、创建的命令)

    $ docker image history web-ping-modappjs
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    5720186d593f        23 minutes ago      /bin/sh -c #(nop)  CMD ["node" "/web-ping/ap…   0B
    ef985b5a110e        23 minutes ago      /bin/sh -c #(nop) COPY file:f56993489cc9d376…   766B
    4591d6e9216f        About an hour ago   /bin/sh -c #(nop) WORKDIR /web-ping             0B
    //...
    
    1. 查看本地镜像的占用的空间大小、数量、正在使用的镜像(不只包括正在运行的容器,还包括处于停止状态的容器)数量等信息
    $ docker system df | grep "image"
    TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
    Images              10                  0                   933.2MB             933.2MB (100%)
    

    注意:这里显示的镜像数量有10个是因为实验的机器上有许多原有的镜像,不过即便如此,细心的你也应该发现所有的镜像加起来的实际的占用容量和步骤三.3显示的不同,这正是因为镜像复用的原因docker container ls显示的镜像大小是逻辑上的大小,包含所有镜像层的逻辑上的大小,并不是实际上的大小


    四、Dockerfile的优化规则
    1. Dockerfile的优化规则
      • 同一种类型的命令尽量写成一个命令
      • 不经常变动的命令往前写
      • 经常变动的命令往后写
    2. 修改本项目中的Dockerfile(修改后的结果在diamol/ch03/exercises/web-ping-optimized中),并重新创建镜像
      • 修改后的Dockerfile
      FROM diamol/node
      
      CMD ["node", "/web-ping/app.js"]
      
      ENV TARGET="blog.sixeyed.com" \
          METHOD="HEAD" \
          INTERVAL="3000"
      
      WORKDIR /web-ping
      COPY app.js .
      

      这样创建步骤就只剩5步了,且就算修改了app.js,需要重新生成的镜像层也只有最后一步而已,CMD命令只需要放在FROM后面就可以了,结果都是一样的。


    五、通过容器创建镜像
    • 其实Docker还可以通过容器来创建镜像,使用docker container commit <容器ID> [镜像名]命令可以把修改过后的容器作为一个新的镜像进行生成
    $ docker container commit 0b7 c3lab
    sha256:0be745068f061ab1812ee12712b515f8e18b40fce7aada731fe2c5472badbc80
    $ docker image history c3lab
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    0be745068f06        6 minutes ago       /bin/sh                                         108B
    c46f210501ad        6 months ago        /bin/sh -c #(nop) COPY file:6a4b948f094c8555…   18B
    <missing>           6 months ago        /bin/sh -c #(nop) WORKDIR /diamol               0B
    <missing>           8 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
    <missing>           8 months ago        /bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6a…   5.53MB
    

    c46f210501ad就是原来镜像的ID,0be745068f06就是根据容器重建后的镜像ID


    参考文档:
    [1] learn-docker-in-a-month-of-lunches
    [2] 官方文档


    附:
    [1] Elton Stoneman的github项目

    相关文章

      网友评论

        本文标题:S2:创建镜像

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