了解图像层

解释

正如您在 什么是图像?,容器镜像由层组成。这些层中的每一层一旦创建,都是不可变的。但是,这实际上意味着什么?这些层如何用于创建容器可以使用的文件系统?

图像层

映像中的每一层都包含一组文件系统更改 - 添加、删除或修改。让我们看一个理论图像:

  1. 第一层添加基本命令和包管理器,例如 apt。
  2. 第二层安装Python运行时和pip以进行依赖管理。
  3. 第三层复制应用程序的特定requirements.txt 文件。
  4. 第四层安装该应用程序的特定依赖项。
  5. 第五层复制应用程序的实际源代码。

这个例子可能看起来像:

显示图像层概念的流程图的屏幕截图

这是有益的,因为它允许在图像之间重用图层。例如,假设您想要创建另一个 Python 应用程序。由于分层,您可以利用相同的 Python 基础。这将使构建速度更快,并减少分发图像所需的存储量和带宽。图像分层可能类似于以下内容:

显示图像分层的好处的流程图的屏幕截图

图层允许您通过重用其他图像的基础层来扩展图像,从而允许您仅添加应用程序所需的数据。

堆叠各层

内容寻址存储和联合文件系统使分层成为可能。虽然这需要技术性,但它的工作原理如下:

  1. 下载每一层后,它会被提取到主机文件系统上自己的目录中。
  2. 当您从映像运行容器时,会创建一个联合文件系统,其中层彼此堆叠,从而创建一个新的统一视图。
  3. 当容器启动时,它的根目录被设置为这个统一目录的位置,使用chroot.

创建联合文件系统时,除了镜像层之外,还会专门为正在运行的容器创建一个目录。这允许容器进行文件系统更改,同时允许原始图像层保持不变。这使您能够从同一底层映像运行多个容器。

试试看

在本实践指南中,您将使用命令手动创建新的图像层 docker container commit。请注意,您很少会以这种方式创建映像,因为您通常会 使用 Dockerfile。但是,它让我们更容易理解它是如何工作的。

创建基础镜像

在第一步中,您将创建自己的基础映像,然后将其用于以下步骤。

  1. 下载并安装Docker Desktop。

  2. 在终端中,运行以下命令来启动新容器:

    $ docker run --name=base-container -ti ubuntu
    

    下载镜像并启动容器后,您应该会看到一个新的 shell 提示符。它在您的容器内运行。它看起来类似于以下内容(容器 ID 会有所不同):

    root@d8c5ca119fcd:/#
    
  3. 在容器内,运行以下命令来安装 Node.js:

    $ apt update && apt install -y nodejs
    

    当此命令运行时,它会在容器内下载并安装 Node。在联合文件系统的上下文中,这些文件系统更改发生在该容器特有的目录中。

  4. 通过运行以下命令验证 Node 是否已安装:

    $ node -e 'console.log("Hello world!")'
    

    然后你应该看到一个“Hello world!”出现在控制台中。

  5. 现在您已经安装了 Node,您可以将所做的更改保存为新的映像层,您可以从中启动新容器或构建新映像。为此,您将使用该 docker container commit命令。在新终端中运行以下命令:

    $ docker container commit -m "Add node" base-container node-base
    
  6. 使用以下命令查看图像的图层docker image history

    $ docker image history node-base
    

    您将看到类似于以下内容的输出:

    IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
    d5c1fca2cdc4   10 seconds ago   /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG RELEASE                  0B
    

    请注意顶行的“添加节点”注释。该层包含您刚刚安装的 Node.js。

  7. 为了证明您的映像已安装 Node,您可以使用此新映像启动一个新容器:

    $ docker run node-base node -e "console.log('Hello again')"
    

    这样,您应该在终端中得到“Hello Again”输出,表明 Node 已安装并正在运行。

  8. 现在您已经完成了基础映像的创建,您可以删除该容器:

    $ docker rm -f base-container
    

基础图像定义

基础镜像是构建其他镜像的基础。可以使用任何图像作为基础图像。然而,一些图像被有意创建为构建块,为应用程序提供基础或起点。

在此示例中,您可能不会部署此node-base映像,因为它实际上尚未执行任何操作。但它是您可以用于其他构建的基础。

构建应用程序映像

现在您已经有了一个基础映像,您可以扩展该映像来构建其他映像。

  1. 使用新创建的基于节点的映像启动一个新容器:

    $ docker run --name=app-container -ti node-base
    
  2. 在此容器内,运行以下命令来创建 Node 程序:

    $ echo 'console.log("Hello from an app")' > app.js
    

    要运行此 Node 程序,您可以使用以下命令并查看屏幕上打印的消息:

    $ node app.js
    
  3. 在另一个终端中,运行以下命令将此容器的更改保存为新映像:

    $ docker container commit -c "CMD node app.js" -m "Add app" app-container sample-app
    

    该命令不仅创建一个名为 的新镜像sample-app,还向该镜像添加额外的配置以设置启动容器时的默认命令。在本例中,您将其设置为自动运行node app.js

  4. 在容器外部的终端中,运行以下命令来查看更新的层:

    $ docker image history sample-app
    

    然后您将看到如下所示的输出。请注意,顶层注释具有“添加应用程序”,下一层注释具有“添加节点”:

    IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
    c1502e2ec875   About a minute ago   /bin/bash                                       33B       Add app
    5310da79c50a   4 minutes ago        /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago          /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG RELEASE                  0B
    
  5. 最后,使用全新的镜像启动一个新容器。由于您指定了默认命令,因此可以使用以下命令:

    $ docker run sample-app
    

    您应该会看到来自 Node 程序的问候语出现在终端中。

  6. 现在您已经完成了容器的操作,可以使用以下命令删除它们:

    $ docker rm -f app-container
    

其他资源

如果您想更深入地了解所学知识,请查看以下资源:

下一步

正如前面所暗示的,大多数图像构建不使用docker container commit.相反,您将使用 Dockerfile 来自动执行这些步骤。