V1nci 的博客

Docker 学习系列(二): Building images

如何使用 Docker 构建镜像并发布?

镜像的相关概念

从官方文档可以得到如下信息:

Container images are composed of layers. And each of these layers, once created, are immutable.

可知,我们这里说构建镜像实际的就是对 layer 进行操作。这里的 layer 是什么?我们继续浏览官方文档。文档中给出了定义如下:

Image Layers: Each layer in an image contains a set of filesystem changes - additions, deletions or modifications.

为了说明该定义官网还举了一个示例说明,以下是我的理解: example_image 它的构建过程如下:

  1. 第一层添加些基本工具如 ls, cat,apt(包管理工具)。
  2. 第二层安装编程语言的运行时环境和依赖管理工具。如果是 Python 项目,既需要安装 Python 的运行时环境以及对应的依赖管理工具 pip。
  3. 第三层从应用程序的工作目录下复制一些必要的配置文件。如 Python 项目需要使用 requirements.txt 来指定当前应用程序需要用到的依赖库。
  4. 第四层根据第三层复制的配置文件为应用程序安装必要的依赖文件。
  5. 第五层将应用程序的源代码拷贝到当前的镜像中。

这五层可以分为两个阶段: 一是开发环境/运行环境搭建;二是安装应用程序源码及构建应用程序。 而这样分层存储的好处是使 layers 可以在不同的镜像中复用。例如, Image1 和 Image2 同为Python项目,它们使用的开发环境(主要指操作系统和 Python 版本)一致。如果 Image1 又先于 Image2 在本机上测试。 Image2 可以复用 Image1 中关于描述开发环境的 layer。

官方文档中描述原理的部分请看 Stacking the layers

有关 docker commit 的实践部分就不在这里详述了,具体请跟着官方文档操作一遍即可理解。

Dockerfile 是什么?

有了解过 CI/CD 这一工程实践的经验。在看 Dockerfile 就会轻松许多。Dockerfile 本身就是一个指令的集合。其中 Docker 会根据当前 Dockerfile 中定义的指令按顺序执行。具体我们来看官方的描述:

A Dockerfile is a text-based document that’s used to create a container image. It provides instructions to the image builder on the commands to run, files to copy, startup command, and more.

Dockerfile 的构成元素 - 指令

以下是 Dockerfile 中比较常见的指令,更详细的请浏览官方的 reference

  • From <image> - this sepcifiex the base image that build will extend.
  • WORKDIR <path> - this instruction specifies the “working directory” or the path in the image where files will be copied and commands will be executed.
  • COPY <host-path> <image-path> - this instruction tells the builder to copy files from the host and put them into the container image.
  • RUN <command> - this instruction tells the builder ot run the specified command.
  • ENV <name> <value> - this instruction sets an environment variable that a running container will use.
  • EXPOSE <port-number> - this instruction sets configuration on the image that indicates a port the image would like to expose.
  • USER <user-or-uid> - this instruction sets the default user for all subsequent instructions.
  • CMD ["<command>", "<arg1>"] - this instruction sets the default command a container using this image will run.

Dockfile 使用

下面我们根据官方提供的示例来看看 Dockerfile 的使用。

1
2
3
4
5
FROM node:20-alpine
WORKDIR /usr/local/app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

后在终端中定位到 Dockerfile 的同级目录下使用 docker build . 命令会得到以下输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
=> [internal] load build context         0.1s
 => => transferring context: 4.59MB       0.0s 
 => [2/4] WORKDIR /usr/local/app          0.3s
 => [3/4] COPY . .                        0.0sd
 => [4/4] RUN yarn install --production  55.3s
 => => # yarn install v1.22.22                l
 => => # warning package.json: No license fiel
 => => # warning [email protected]: No license fie 
 => => # [1/4] Resolving packages...          
 => => # [2/4] Fetching packages...            
 => => # [3/4] Linking dependencies...        
 ...
 => [3/4] COPY . .                        0.0s
 => [4/4] RUN yarn install --production  59.8s
 => exporting to image                    0.5s
 => => exporting layers                   0.5s
 => => writing image sha256:9a78dcad9342  0.0s

最后会得到 sha256 的标识码,使用 docker run SHA256:.... 即可运行该镜像。

运行效果:run result

更为复杂的例子可以参考Docker 从入门到实践的这一个部分。

镜像发布

在前文中我们已经知道如何构建一个镜像,如若我们想把构建好的镜像发布到互联网上该如何做呢?我们继续浏览官方文档。在之前的实践中我们知道使用 docker build . 最后 Docker 会输出一串 sha256 的字符串用于标识我们构建的镜像。显然记忆 sha256 的字符是复杂的, 但在使用过程中我们必须能区分镜像,Docker 使用标签机制来解决这个问题。

Tagging images is the method to provide an image with a memorable name.

单一的标签可能会出现歧义的,为了减少歧义, Docker 采用了较为复杂的命名结构。结构如下:

[HOST[:PORT_NUMBER]/]PATH[:TAG]

  • HOST: The optional registry hostname where the image is located. If no host is specified, Docker’s public registry at docker.io is used by defatult.
  • PORT_NUMBER: The registry port numbers if a hostname is provided.
  • PATH: The path of image, consisting of slash-separated components. For Docker Hub, the format follows [NAMESPACE/]REPOSITORY, where namespace is either a user’s or organization’s name. If no namespace is specified, library is used, which is the namespace for Docker Official Images.
  • TAG: A custom, human-readable identifier that’s typically used to identify different versions or variants of an image. If no tag is specified, latest is used by default.

如果想在镜像构建的前中标记镜像,可以使用如下命令:

docker build -t my-username/my-image .

如果镜像已经构建完成后想要标记镜像。则可以使用如下命令:

docker image tag my-username/my-image another-username/another-image:V1

至此,我们已经为镜像的发布做好了所有的准备工作。使用命令

docker push my-username/my-imgae

即可将我们构建好的镜像发送到指定的 Registery。 这里只是将镜像构建发布的流程记录下来,实际操作过程中还涉及到一些细节如身份验证等问题。详情请参考官方的小例子

参考

Docker 官方文档: click

Docker 从入门到实践: click