构建 Docker 镜像

Dockerfile 就像一个编译文件。它以层的形式构建,从包含基本设置的基础层开始。这通常是我们使用 FROM 指令的层。每个后续层都添加到前一个层之上,进行小的调整或添加。这些层堆叠在另一个层之上,每个层都会构建前一层所做的更改。

创建 Docker 映像后,其所有层都变为只读。但是,当你从此映像启动 Docker 容器时,Docker 会在它们之上添加一个新层。这个新层是容器操作期间所做的任何更改或更新的存储位置。它就像一个薄的可写层,可以捕获对容器文件系统所做的所有修改。

本质上,Docker 镜像提供了创建一致环境的蓝图,而容器允许你在该环境中工作并根据需要进行更改,而不会影响原始镜像。

此镜像构建过程由 Docker CLI 初始化并由 Docker 守护程序执行。 要生成 Docker 镜像,Docker 守护程序需要访问 Dockerfile、任何源代码以及该 Dockerfile 中引用的文件。 这些文件存储在称为构建上下文的目录中。 执行 docker image build 命令时需要指定此上下文目录。

docker image build 命令采用以下格式:

1
docker image build <context>

如果我们想指定当前目录作为上下文,我们可以使用点(.)作为目录:

1
docker image build .

我们来创建一个简单的 Dockerfile 来演示 Docker 镜像的构建过程:

1
2
3
FROM ubuntu:latest
LABEL maintainer="webape@example.com"
CMD ["echo", "Hello World"]

Dockerfile 执行以下操作。它以 FROM 命令开头,指定应在 Docker Hub 存储库中提供的最新版本的 Ubuntu 之上构建映像。此基础映像是我们自定义映像的起点。

LABEL 命令用于提供有关映像的元数据。在本例中,它分配维护者标签,指示谁维护或负责此特定映像。提供的电子邮件地址 (webape@example.com) 用作联系信息。

最后,CMD 命令设置从此映像启动容器时要执行的默认命令。在这里,它指定当容器启动时,它应该执行命令 echo “Hello World”。此命令只是将“Hello World”打印到容器的标准输出。

导航到你创建 Dockerfile 的目录,并使用以下命令:

1
docker image build .

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

1
2
3
4
5
6
7
8
9
10
11
12
[+] Building 3.5s (6/6) FINISHED                                                                         docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 143B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 3.4s
=> [auth] library/ubuntu:pull token for registry-1.docker.io 0.0s
=> CACHED [1/1] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd905 0.0s
=> => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f14484d3185f92d2d7896904300502be4f3c6d0df4ebba61b127d630d74b6f0d 0.0s

现在,让我们使用 docker image list 命令访问本地可用的 Docker 镜像:

1
docker image list

该命令应返回以下输出:

1
2
REPOSITORY                                      TAG       IMAGE ID       CREATED       SIZE
<none> <none> f14484d3185f 11 days ago 78.1MB

请注意,我们的自定义 Docker 映像没有名称。这是因为我们在构建过程中没有指定任何存储库或标记。我们可以使用 docker image tag 命令标记现有映像。

让我们将 IMAGE ID 为 f14484d3185f 的映像标记为 my-tagged-image:v1.0:

1
docker image tag f14484d3185f my-tagged-image:v1.0

现在,如果我们再次列出我们的镜像,我们可以在 REPOSITORYTAG 列下看到 Docker 镜像名称和标签:

1
2
REPOSITORY                                      TAG       IMAGE ID       CREATED       SIZE
my-tagged-image v1.0 f14484d3185f 11 days ago 78.1MB

我们还可以通过指定 -t 标志在构建过程中标记图像:

1
docker image build -t my-tagged-image:v2.0 .

上述命令将打印以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
[+] Building 5.8s (6/6) FINISHED                                                                         docker:default
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 143B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 5.6s
=> [auth] library/ubuntu:pull token for registry-1.docker.io 0.0s
=> CACHED [1/1] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd905 0.0s
=> => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f14484d3185f92d2d7896904300502be4f3c6d0df4ebba61b127d630d74b6f0d 0.0s
=> => naming to docker.io/library/my-tagged-image:v2.0 0.0s

这次,除了写入 image sha256:f14484d3185f92d2d7896904300502be4f3c6d0df4ebba61b127d630d74b6f0d 行之外,我们还可以看到 naming to docker.io/library/my-tagged-image:v2.0 行,这表示我们的 Docker 镜像上有标记。

总结

在这篇文章中,我们讨论了如何从 Dockerfile 构建 Docker 镜像。我们还讨论了 DockerfileDocker 镜像之间的区别。然后,我们讨论了 Docker 镜像是如何由多个层组成的。最后,我们标记了 Docker 镜像。