灵虚御风
醉饮千觞不知愁,忘川来生空余恨!

导航

 

3.1镜像的内部结构

  3.1.1 hello-world --- 最小的镜像

  3.1.2 base 镜像

  3.1.3 镜像的分层结构

3.2构建镜像

  3.2.1 docker commit

  3.2.2 Dockerfile

3.3RUN vs CMD vs ENTRYPOINT

  3.3.1 Shell 和 Exec格式

  3.3.2 RUN

  3.3.3 CMD

  3.3.4 ENTRYPOINT

  3.3.5 最佳实践

3.4分发镜像

  3.4.1 为镜像命名

  3.4.2 使用公共Registry

  3.4.3 搭建本地 Registry

3.5小结

 

详情

1.典型镜像 2.分析镜像内部结构 3.学习构建自己镜像 4.管理和分发镜像

第3章 Docker 镜像(26-54)

  镜像是Docker容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。

  本章内容安排如下:首先通过研究几个典型的镜像,分析镜像的内部结构;然后学习如何构建自己的镜像;最后介绍怎样管理和分发镜像。

3.1镜像的内部结构:(理解Docker 为什么是轻量级的)

  3.1.1 hello-world --- 最小的镜像

    hello-world 官方提供的一个镜像,用来验证 Docker 是否安装成功。 

    我们先通过 docker pull 从Docker hub 下载他,如图 3-1

    

    用docker image 查看镜像命令的信息,如图 3-2

    

    hello-world 镜像竟然还不到 2KB 通过 docker run 运行 ,如图3-3

    

    其实我们更关心hello-world 镜像包含哪些内容:

    Dockerfile 是镜像的描述文件,定义如何构建 Docker 镜像 。 Dockerfile 语法简洁,可读性强

    hello-world 的 Dockerfile 的内容 如图3-4所示。

    只有短短三条指令:

    (1) FROM scrach 镜像是从白手起家,从0开始构建

    (2) COPY hello/  将文件 ”hello" 复制到镜像的更目录

    (3) CMD ["/hello"]  容器启动时执行 /hello

    镜像 hello_world 中就只有 一个 可执行文件 “hello", 其功能就是打印出  ”Hello from Docker ......." 等信息

    /hello 就是系统文件的全部内容, 连最基本的 /bin.   /usr.  /lib.  /dev 都没有

    hello-world 虽然是一个完整的镜像。 但它并没有什么实际用途,通常来说,我们希望镜像 能提供一个基本的操作系统环境,用户可以根据 需要 安装 和 配置软件

    这样的镜像我们称之为 base 镜像 。

  3.1.2 base 镜像

    base 镜像 有两层含义:

      (1)不依赖其他镜像,从 scratch 构建

      (2)其他镜像可以以此为基础进行扩展

    故: 能称为 base 镜像的 通常都是 各种 linux 发行版 Docker 镜像,比如Ubuntu, Debian,Centos 等

    以 Centos 为例,考察 base 镜像 包含哪些内容

      下载: docker pull centos

      查看镜像信息: docker image centos

        

      镜像大小不到 200MB

        

        1.rootfs:  内核是kernel,linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。

          用户的 空间系统 时rootfs ,包含我们熟悉的  /dev, /proc, /bin 等目录

          对于base 镜像 来说 底层直接用 Host 的 kernel, 自己只需要提供rootfs 就行了

          对于一个 精简的 OS  rootfs 可以很小 ,只要包括最基本的 命令,工具和 程序库就可以了

        2. base 镜像提供的时最小安装的linux 发行版

          

          第二行 ADD 指令添加到镜像的 tar包 就是 CentOS 7 的 rootfs。 在制作镜像时,这个 tar 包 会自动解压到 / 目录下,生成 /dev , /proc,  /bin等目录

          注: 可在Docker Hub 的镜像描述页面 查看 Dockerfile

              

     3. 支持运行多种 linux OS : 不同Linux 发行版的区别主要 就是rootfs

        

          (1) base 镜像只时在 用户空间 于 发行版 一致,kernel 版本与发行版是不同的

          

          (2)容器只能 使用 Host 的 kernel ,并不能修改

              所有容器都公用 host 的 kernel 在容器中 没有办法对 kernel 升级,如果容器对 kernel 版本有要求(例:应用只能在某个kernel 版本下运行),则不建议用容器,推荐使用虚拟机 

  3.1.3 镜像的分层结构

    docker 支持通过扩展现有镜像,创建新的镜像

    实际上,Docker Hub 中 99% 的镜像 都是通过 Base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像, Dockerfile 如图3-10所示

     

    (1)新镜像不再是从 scratch 开始,而是直接在Debian base 镜像上构建

    (2)安装emacs 编辑器

    (3)安装apache2

    (4)容器启动时运行 bash

    构建过程如图3-11所示

      

     可以看到,新镜像是从 base 镜像 一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

     为什么 Docker 镜像要采用这种分层结构?

        最大的好处就是: 共享资源

     例如: 有多个镜像都从相同的base 镜像构建而来,那么Docker Host 只需在磁盘上保存一份base 镜像,同时内存中也只需加载一份base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被 共享

     问题:

        如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如  /etc 下的文件,这时其他容器的  /etc 是否也会被修改

      答案:不会

        修改会被限制在单个容器内,即 容器的 Copy-on-Write 特性

    可写的容器层

      当容器启动时,一个新的可写层被加载到镜像的顶部

      这一层通常被称作 "容器层", ”容器层“ 之下的都叫”镜像层“ 如图3-12 所示

      

      所有对容器的改动,无论如何添加,删除,还是修改文件都只会发生在容器层中,只有容器层是可写的, 容器层下面所有镜像层都只是可读的

      容器细节:

        镜像层数量可能会很多,所有的镜像层联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件, 比如 /a, 上层的 /a 会覆盖下层的 /a , 也就是用户只能访问到上层中的文件 /a , 在容器层中,用户看到的是一个叠加之后的文件系统

        (1)添加文件,在容器中创建文件时,新文件被添加到容器层中

        (2)读取文件, 在容器中读取某个文件时,Docker 会从上往下 依次在各镜像层中查找此文件。 一旦找到,打开并读入内存

        (3) 修改文件, 在容器中修改已存在的文件时,Docker 会依次从上往下查找此文件,一旦找到,立即复制到容器层,然后修改之

        (4)删除容器, 在容器中删除文件时, Docker 也是从上往下依次查找此文件,找到后,会在容器层中记录下此删除操作

        只有当需要修改时才复制一份数据,这种特性被称为 Copy-on-Write. 可见,容器层保存是镜像变化的部分,不会对镜像本身进行任何的修改

        结论:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享

3.2构建镜像

    对于Docker 用户来说,最好的情况是不需要自己创建镜像,几乎所有常用的数据库,中间件,应用软件都有现成的 Docker 官方镜像或者其他人和组织创建的镜像,我们只需稍作配置即可使用

    使用现成镜像的好处:

      (1)省去自己自己做镜像的工作量

      (2)更重要的是利用前人的经验

        特别是官方镜像,因为Docker 的工程师知道如何更好的在容器中运行软件

    必须自己构建镜像的几种情况

      (1)找不到现成的镜像,例如:自己开发的应用程序

      (2)需要在镜像中加入特定的功能,比如官方镜像都不提供 ssh

    构建镜像的两种方法

      (1)docker commit 命令

      (2)Dockerfile 构建文件

  3.2.1 docker commit-方法一

    docker commit 命令是创建镜像最直观的方法:步骤分三步

      (1)运行容器(2)修改容器 (3)将容器保存为新的镜像

    (1)运行容器 如图3-13:docker run -it ubuntu

        

      实例:

        -it 参数的作用是以交互模式进入容器,并打开终端。412把0588f4a 是容器内部 ID

     (2) 安装 vi

        确认 vi 没有安装,如图3-14

        

        安装vi, 如图3-15 所示:apt-get install -y vim

         

      (3)保存为新镜像

        在新窗口中查看当前运行的容器, 如图3-16所示

        

      silly_goldberg 是 Docker 为我们容器随机分配的名字

      执行 docker commit 命令将容器保存为镜像,如图3-17所示

        docker commit silly_goldberg ubuntu-with-vi

       

      新镜像 命名为 ubuntu-with-vi 查看新镜像的属性,如图3-18

      docker images

      

      从size 上 看到镜像应为安装软件而变大了

      从新镜像启动容器,验证vi 已经可以使用了如图3-19

      docker run -it ubuntu-with-vi

      

      以上演示如何用 docker commit 创建新镜像,然而,Docker 并不建议用户通过这种方法构建镜像,原因如下

      (1)这是一种手工创建镜像的方法,容易出错,效率低且重复性弱。比如要在 debian base镜像中也加入 vi 还得重复前面所有的步骤

      (2)更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说,无法对镜像进行审计,存在安全隐患

      既然 docker commit 不是推荐的方法,我们为什么还要花时间学习呢?

      原因:即便是用Dockerfile(推荐方法)构建镜像,底层也是docker commit 一层一层构建新镜像的,学习docker commit 能够帮助我们更加深入的理解构建过程和镜像的分层结构

  3.2.2 Dockerfile

    Dockerfile 是一个文本文件,记录了镜像构建的所有步骤

    1.第一个 Docker

      用Dockerfile创建上节的ubuntu-with-vi 其内容如图3-20 所示

        FROM ubuntu

        RUN apt-get update && apt-get install -y vim

        

      下面我们运行 docker build 命令构建镜像,并详细分析每个细节

      

      (1)当前目录为 /root

      (2)Dockerfile 准备就绪

      (3)运行docker build 命令,-t 将新镜像命名为ubuntu-with-vi-dockerfile,命名末尾指明 build context 为当前目录,Docker默认会从 build context 中查找Dockerfile文件,我们也可以通过 -f 参数指定 Dockerfile 位置 

      (4)从这步开始就是镜像真正的构建过程,首先Docker 将build context 中所有的文件发送给Docker daemon. build context 为镜像构建提供所需要的文件或者目录

       Dockerfile 中的 ADD ,COPY 等命令可以将build context 中文件添加到镜像。此例中 build context 为当前目录 /root,该目录下的所有文件和子目录都会被发送给 Docker daemon.

       所以,使用 build context 注意不要把多余的文件放到 build context, 特别不要把 /, /usr 作为usr,否则构建过程会相当缓慢甚至失败

      (5)step1: 执行FROM,将ubuntu作为base镜像

        ubuntu 镜像ID为 

      (6)step2: 执行RUN,安装vim,具体步骤为789

      (7)启动ID为 9f....e3的零时容器,在容器中通过 apt-get 安装vim

      (8)安装成功后,将容器保存为镜像,其id为 35ca....37.

        这一步底层使用的步骤类似于docker commit ,命令

      (9)删除零时容器 9f....e3

      (10)镜像构建成功

       ps:重点步骤,789,类似docker commit

        

    2.查看镜像分层结构

      ubuntu-with-vi-dockerfile 是通过在base 镜像顶部添加一个新的镜像层而得到的,如图3-22所示 :

      

      这个镜像层由RUN apt-get update && apt-get install -y vim 生成。可以通过 docker history 命令验证,如图3-23

      docker history ubuntu 

      docker history 会显示镜像的构建历史,也就是 Dockerfile的执行过程

      ubuntu-with-vi-dockerfile 与 Ubuntu 镜像相比,确实多了顶部一层,35ca.....37,由apt-get 命令创建。大小为97.07 MB. docker history 也向我们展示了镜像的分层结构,每一层由上至下排列

      ps:missing 表示无法获取 IMAGRE ID ,通常从 Docker Hub 下载的镜像会有这个问题

    3.镜像的缓存特性

      Docker 会缓存已有镜像的镜像层,构建镜像时,如果某镜像层已经存在,就直接使用,无需重新创建

      例如:

        

        

        (1) 确保 testfile已存在

        (2)重点:之前运行过的RUN 指令,这次直接采用缓存镜像层35ca.....37

        (3)执行 COPY 命令

        过程:启动零时容器,复制testfile,提交新的镜像层8d.....f4 ,删除临时容器

        

        不使用缓存构建镜像命令: docker build 中加 --no-cache 参数

        Docker 中每一个指令都会创建一个镜像层,上层时依赖下层的,无论何时,只要某一层改变,其上面所有层的缓存都失效

        即:

        虽然逻辑上这种改动对镜像的内容没有影响,但由于分层的结构性, Docker 必须重建受影响的镜像层

       docker build -t ubuntu-with-vi-dockerfile-3 .

       

        从上面的输出可以看到生成了新的镜像层 bc87.....40,缓存已经失效

        除了构建时使用缓存,Docker 在下载镜像时也会使用,例如下载httpd镜像,如图3-27:

        

        docker pull 命令输出的第一层(base镜像)已经存在,不需要下载

        由 Dockerfile 可知 httpd 的base 镜像debian,正好之前已经下载过debian 镜像,所以有缓存可以用。通过docker history 可以进一步验证,如图3-28

        

    4.调试Dockerfile

      总结Dockerfile构建镜像的过程:

        (1)从base镜像运行一个容器

        (2)执行一条指令,对容器做修改

        (3)执行类似 docker commit 操作,生成一个新的镜像层

        (4)Docker 再基于刚刚提交的镜像运行一个新容器

        (5)重复2-4步,知道Dockerfile 中所有指令执行完毕

      从这个过程中可以看出,如果Dockerfile由于某种原因执行到某个指令失败了,我们也将能够的到前一个指令成功构建出的镜像,这对调试 Dockerfile 非常有帮助,我们可以运行最新的这个镜像定位指令失败的原因

      例如:

            

      执行 docker build 如图3-30:

          

      Dockerfile 在执行第三步 RUN 指令时失败。 我们可以利用第二步创建的镜像 22d.....b3e 进行调试,方法是通过docker run -it 启动镜像的一个容器,如图3-31

            

      手工执行 RUN 指令 很容易 定位失败的原因是 busybox 镜像中没有bash.虽然这是个简单的例子,但很好的展示调试Dockerfile的方法

    5.Dockerfile 常用指令

      Dockerfile 完整列表和说明可参看官方文档

      *  FROM: 指定base镜像

      *  MAINTAINER 设置镜像的作者,可以是任意字符串

      *  COPY 将文件从build context 复制到镜像

      COPY 支持的两种形式: COPY src dest 与 COPY["src","dest"].

      ps:src 只能指定 build context 中的文件或目录

      *  ADD 与COPY类似,从build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar,zip,tgz,xz),文件会被自动解压到dest

      *  ENV 设置环境变量,环境变量可被后面指令使用,例: ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION

      

      *  EXPOSE: 指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来,详情: 容器网络部分

      *  VOLUME 将文件或目录声明为 volume. 详情:容器存储部分

      *  RUN 在容器中运行指定的命令

      *  CMD: 容器启动时运行指定的命令

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

      *  ENTRYPOINT 设置容器启动时运行的命令

      Dockerfile 中 可以有多个 ENTRYPOINT 指令,但只有最后一个生效,CMD 或 docker run 之后的参数,会被当做参数传递给 ENTRYPOINT(entrypoint)

      一个较为全面的 Dockerfile,如图3-32

      

      # my dockerfile

      FROM busybox

      MAINTAINER cloudman@example.net

      WORKDIR /testdir

      RUN touch tmpfile1

      COPY  ["tmpfile2","."]

      ADD ["bunch.tar.gz", "."]

      ENV WELCOME "you are in my container, welcome!"

      ps: Dockerfile 支持“#”开头的注释。

      构建镜像 如图3-33

          

      (1) 构建前确保 build context 中存在需要的文件

      (2) 依次执行 Dockerfile 完成构建

      运行容器,验证镜像内容,如图3-34(docker run -it my-image)

        

      (1)进入容器,当前目录 即为 WORKDIR. 如果WORKDIR 不存在,Docker 会自动为我们创建

      (2)WORKDIR 中保存了我们希望的文件或者目录

        目录 bunch: 由ADD 指令从 build context 复制的归档文件 bunch.tar.gz. 已经自动解压。

        目录tmpfile1: 由RUN 指令创建

        目录tmpfile2: 由COPY 指令从build context 复制

      (3)ENV 指令定义的环境变量已经生效

3.3RUN vs CMD vs ENTRYPOINT

  RUN,CMD,ENTRYPOINT 这三个Dockerfile相似于区别案例:

  简单说:(1)RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包

      (2)CMD:设置容器启动后默认执行的命令及其参数,但CMD 能被 docker run 后面跟的命令行参数替换

      (3)ENTRYPOINT: 配置容器启动时运行的命令

  3.3.1 Shell 和 Exec格式

      两种方式指定 RUN,CMD,ENTRYPOINT 要运行的命令: shell 格式和Exec 格式,二者在使用上由细微差别

      Shell 格式: <instruction> <command>

      例如:RUN apt-get install python3

         CMD echo "Hello world"

         ENTRYPOINT echo "Hello world"

      当执行时,shell 格式底层会调用 /bin/sh -c [command]. 例如下面的Dockerfile片段:

        ENV name Cloud Man ENTRYPOINT echo "Hello, $name"

      执行docker run [image] 将输出:Hello, Cloud Man

      ps: 环境变量 name已经被值 Cloud Man 替换

      Exec 格式:<instruction> ["executable", "param1", "param2", ...]

      例如:RUN ["apt-get", "install", "python3"]

         CMD ["/bin/echo", "Hello world"]

         ENTRYPOINT ["/bin/echo", "Hello world"]

      当执行 指令时,会直接调用 【command】,不会被 shell 解析

      例如下面Dockerfile片段

      ENV name Cloud Man ENVRYPOINT ["/bin/sh", "-c", "Hello, $name"]

      运行容器将输出:Hello, $name

      ps: 环境变量name 没有被替换

      如果希望使用环境变量,做如下修改

         ENV name Cloud Man ENVRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

      运行容器将输出:Hello, Cloud Man

      CMD,ENTRYPOINT 推荐Exec 格式,原因:指令可读性更强,跟容易理解

      RUN 则两种格式都可

  3.3.2 RUN

    RUN 指令通常用于安装应用和软件包

    RUN 在当前镜像的顶部执行命令,并创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令

    RUN 有两种格式(1)Shell 格式 RUN (2)Exec 格式 RUN ["executable", "param1", "param2"]

    下面是使用RUN安装多个包的例子:

    RUN apt-get update && apt-get install-y\bzr\cvs\git\mercurial\

    subversion

    ps:apt-get update 和 apt-get install 被放在一个 RUN 指令里面执行,这样能保证每次安装都是最新的包。如果apt-get install 在单独的RUN 中执行,则会使用apt-get update 创建镜像层,而这一层可能是很久以前的的缓存

  3.3.3 CMD

    CMD 指令,允许用户指定容器的默认执行的命令

    此命令会在容器启动且 docker run 没有指定其他命令时运行

    *  如果docker run 指定了其他命令,CMD 指定的默认命令将被忽略

    *  如果Dockerfile 中有多个CMD 指令,只有最后一个CMD有效

    CMD 三种形式

    (1)Exec 格式:CMD ["executable", "param1", "param2"] 这也是CMD推荐格式

    (2)CMD ["param1", "param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用Exec格式 

    (3)Shell格式:CMD command param1 param2

    第二种格式 CMD ["param1", "param2"] 要与Exec 格式的ENTRYPOINT 指令配合使用,其用途:为ENTRYPOINT 设置默认参数。

    下面看CMD 如何工作,Dockerfile 片段如下

      CMD echo "Hello world"

      运行容器docker run -it [image] 将输出: Hello world

      但当后面加上一个命令,比如 docker run -it [image] /bin/bash, CMD 会被忽略掉, bash 将被执行

      root@10a32dc7d3d3:/#

  3.3.4 ENTRYPOINT

    ENTRYPOINT 指令可以让容器以应用程序或者服务的形式运行

    ENTRYPOINT 看上去于CMD 很像,他们都可以指定要执行的命令及其参数。不同的地方在于ENTRYPOINT 不会被忽略,一定会被执行,即使docker run 运行时指定了其他命令

    ENTRYPOINT 有两种格式

    (1)Exec格式: ENTRYPOINT ["exectuble", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式

    (2)Shell格式:ENTRYPOINT command param1 param2

    在ENTRYPOINT 选择格式时要注意,因为这两种格式效果差异很大

    1.Exec格式:ENTRYPOINT 的Exec 格式用于设置要执行的命令以及参数,同时可通过 CMD 提供额外参数

    ENTRYPOINT 中参数始终会被使用,而CMD 的额外参数可以在容器启动时动态替换掉

    比如下面 Dockerfile片段:

    ENTRYPOINT ["/bin/echo", "Hello"]  CMD ["world"]

    当容器通过docker run -it [image]启动,输出为: Hello world

    而通过docker run -it [image] CloudMan 启动,则输出为: Hello CloudMan

    2.Shell 格式: ENTRYPOINT 的Shell格式会忽略任何 CMD 或 Docker run 提供的参数

  3.3.5 最佳实践

    (1)使用RUN 指令安装应用和软件包,构建镜像

    (2)如果 Docker 镜像的用途是运行应用程序或者服务,比如运行一个 MySQL,应该优先使用Exec 格式的ENTRYPOINT 指令,CMD 可为ENTRYPOINT 提供额外的默认参数,同时可利用docker run 命令行替换默认参数

    (3)如果想为容器设置默认的启动命令,可使用CMD指令,用户可以在docker run 命令行中替换此默认命令

3.4分发镜像

  在多个Docker Host 上使用镜像,的几种方法,如下

    (1)用相同的Dockerfile在其他host上构建镜像

    (2)将镜像上传到公共 Registry(比如Docker Hub),Host直接下载使用

    (3)搭建私有的Registry 供本地 Host 使用

  3.4.1 为镜像命名

    无论采用何种方式保存和分发镜像,首先都得给镜像命名

    当我们执行 docker build 命令时已经为镜像取了名字,例如前面:

      docker build -t ubuntu-with-vi

    这里的ubuntu-with-vi 就是镜像的名字,通过docker images 可以查看镜像的信息,如图3-35所示

    

    这里注意到ubuntu-with-vi 对应的REPOSITORY,而且还有一个叫latest 的TAG

    实际上一个特定镜像的名字由两部分组成,repository 和 tag 

    [image name] = [repository]:[tag]

    如果执行docker build 时没有指定tag,会使用默认值latest,其效果相当于:

    docker build -t ubuntu-with-vi:latest

    tag 常用于描述镜像的版本信息,比如httpd镜像,如图3-36所示

    

    当然 tag 可以是任意字符串,比如ubuntu 镜像如图3-37所示:

    

    1.小心latest tag

      千万别被latest tag 给误导了,latest 其实并没有什么特殊含义,当没指明tag时 ,Docker会使用默认值latest ,仅此而已

      虽然Docker Hub 上很多 repository 将latest 作为最新稳定版本的别名,但这只是一种约定,而不是强制归定

      所以我们在使用镜像时最好还是避免使用latest,明确指定某个 tag,比如httpd:2.3, ubuntu:xenial

    2.tag 使用最佳实例

      借鉴软件版本命名方式能够让用户很好的使用镜像

      一个高效的版本命名方案可以让用户清楚的知道当前使用的是哪个镜像,同时还可以保持足够的灵活性

      每个repository 可以有多个tag,而多个tag 可以对应同一个镜像,下面通过例子学习Docker 社区普遍使用tag的方案

      假设我们现在发布了一个镜像 myimage ,版本为v1.9.1那我们可以给镜像打上四个tag: 1.9.1, 1.9, 1 和latest,如图所示3-38

      我们可以通过docker tag 命令方便的为给镜像打tag

      

      docker tag myimage-v1.9.1 myimage:1 docker tag myimage-v1.9.1 myimage:1.9 docker tag myimage-v1.9.1 myimage:1.9.1 docker tag myimage-v1.9.1 myimage:latest

 

      过一段时间我们发布了v1.9.2 这时可以打上 1.9.2的tag,并将1.9,1和latest 从v1.9.1 转移到v1.9.2 如图3-39

 

      

      命令为:

        docker tag myimage-v1.9.2 myimage:1 docker tag myimage-v1.9.2 myimage:1.9 docker tag myimage-v1.9.2 myimage:1.9.2 docker tag myimage-v1.9.2 myimage:latest

        之后v2.0.0发布这时可以打上2.0.0,2.0和2的tag,并将latest 转移到v2.0.0 如图3-40:

        

      命令为:

        docker tag myimage-v2.0.0 myimage:2 docker tag myimage-v2.0.0 myimage:2.0 docker tag myimage-v2.0.0 myimage:2.0.0 docker tag myimage-v2.0.0 myimage:latest

      这种tag 方案使镜像的版本很直观,用户在选择时非常灵活

      (1)myimage:1 始终指向1 这个分支中最新的镜像

      (2)myimage:1.9 始终指向1.9.中最新的镜像

      (3)myimage:latest: 始终指向所有版本中最新镜像

      (4)如果想指向特定版本,可以选择myimage:1.9.1,myimage:1.9.2 或者 myimage:2.0.0

      Docker Hub 上很多的 repository 都采用这种方案,需要熟悉

  3.4.2 使用公共Registry

    保存和分发镜像最直接的方法就是使用 Docker Hub

    Docker Hub 是Docker 公司维护的公共 Registry.用户可以将自己的镜像保存到 Docker Hub 免费的 repository 中如果,不希望别人访问自己的镜像,也可以购买死人的repository

    除了 Docker Hub,quay.io 是另一个公共的Registry,提供与Docker Hub 类似的服务

    下面介绍如何用 Docker Hub 存取我们的镜像

      (1)首先得在Docker Hub 上注册一个账户

      (2)在 Docker Host 上登录,如图3-41

        命令:docker login -u cloudman6

    这里用的是作者账号cloudman6 输入密码后登录成功

      (3)修改镜像的 repository 使之与Docker Hub 账号匹配

      Docker Hub 为了区分不同用户的同名镜像,镜像的repository 中要包含用户名,完整格式为: [username]/xxx:tag.我们通过docker tag 命令重命名镜像 如图3-42

      

      命令: docker tag httpd cloudman6/httpd:v1

        docker image cloudman6/httpd

      ps:Docker 官方自己维护的镜像没有用户名,例如httpd

      通过docker push 将镜像上传到Docker Hub 如图3-43

       

      命令:docker push cloudman6/httpd:v1

      Docker 会上传镜像的每一层. 因为cloudman6/httpd:v1 这个镜像实际上跟官方镜像 httpd 镜像一模一样,Docker Hub 上已经有全部的镜像层,所以真正上传的数据很少。同样的,如果我们的镜像是基于base 镜像的,也只有新增加的镜像层会被上传。如果想上传同一 repository 中所有镜像,省略tag部分就可以了,例如:

      docker push cloudman6/httpd

      (1)登录 https://hub.docker.com 在Public Repository 中就可以看到上传的镜像,如图3-44 所示

      

      如果要删除上传镜像,只能在Docker Hub 界面上操作。

      (2)这个镜像可被其他Docker host 下载使用,如图3-45

      

  3.4.3 搭建本地 Registry

    Docker Hub 虽然方便,但是还是有些限制,例如:

      (1)需要internet 连接,而且下载和上传速度慢

      (2)上传到Docker Hub的镜像任何人都可以访问,虽然可以用私有repository,但不是免费的

      (3)因为安全原因许多组织不允许把镜像放到外网

    解决方法: 搭建本地 Registry

    Docker 已经将Registry 开源,同时在Docker Hub上也有官方的镜像registry,选民我们就在Docker 中运行自己的registry

      1.启动registry容器

      我们使用的镜像是registry:2,如图3-46

      命令:docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2

      

      *  -d 后台启动容器

      *  -p 将容器的5000端口映射到 Host的5000端口,5000是registry 的服务端口

      *  -v 将容器 /var/lib/registry 目录映射到 Host的 /myregistry ,用于存放镜像数据.

      通过 docker tag 重命名镜像,使之与registry 匹配,如图3-47

      命令: docker tag cloudman6/httpd:v1 registry.example.net:5000/cloudman6/httpd:v1

      

      我们在镜像的前面加上了运行registry的主机名称和端口

      镜像名称: registry 与tag 两部分组成

      registry 的完整格式: [registry-host] : [port] / [username]/xxx

      只有Docker Hub上的镜像可以省略registry-host:[port]

      2,通过docker push 上传镜像

      通过docker push 上传镜像如图3-48:

      命令:docker push registry.example.net:5000/cloudman6/httpd:v1

       

      现在可以通过docker pull 从本地下载镜像,如图3-49

      命令:docker pull registry.example.net:5000/cloudman6/httpd:v1

      

      除了镜像名称长一些(包含registry host 和port),使用方式完全一样

      以上是搭建本地registry的简要步骤。当然registry 也支持认证,https安全传输等特性

      参考官方文档:https://docs.docker.com/registry/configuration/

3.5小结

  1.学习docker 镜像

  2.docker 镜像分层结构

  3.如何构建镜像

  4,实践使用Docker Hub 和本地 registry

  下面是镜像操作常用子命令:

  *  images :显示镜像列表

  *  history: 显示镜像构建历史

  *  commit :从容器创建新镜像

  *  build: 从Dockerfile 构建镜像

  *  tag:给镜像打tag

  *  pull :从registry下载镜像

  *  push: 将镜像上传到 registry

  *  rmi: 删除 Docker host 中的镜像

  *  search: 搜索Docker Hub 中的镜像

  *******新

  1.rmi:只能删除 host上的镜像,而不会删除registry的镜像

    如:一个镜像对应多个tag,只有当最后一个tag被删除以后,镜像才真正删除,例如 :host 中的debian 镜像有两个 tag,如图3-50: docker images debian

    

    删除其中的debian :latest,只是删除了latest tag 镜像本身并没有被删除,如图3-51所示:

    命令:docker rmi debian:latest

    

    只有当debian:jessie也被删除时,整个镜像才会被删除,如图3-52

    命令:docker rmi debian:jessie

    

  2.search

    search 让我们无需打开浏览器,在命令行中就可以搜索 Docker Hub中的镜像,如图3-53

    命令:docker search httpd

    

    当然如果想知道都有哪些tag,还得访问 Docker Hub

posted on 2022-06-24 13:54  没有如果,只看将来  阅读(66)  评论(0)    收藏  举报