Docker 的核心思想就是如何将应用整合到容器中,并且能在容器中实际运行。
将应用整合到容器中并且运行起来的这个过程,称为“容器化”(Containerizing),有时也叫作“Docker化”(Dockerizing)。
容器是为应用而生的,具体来说,容器能够简化应用的构建、部署和运行过程。
完整的应用容器化过程主要分为以下几个步骤。
编写应用代码。
创建一个 Dockerfile,其中包括当前应用的描述、依赖以及该如何运行这个应用。
对该 Dockerfile 执行 docker image build 命令。
等待 Docker 将应用程序构建到 Docker 镜像中。
一旦应用容器化完成(即应用被打包为一个 Docker 镜像),就能以镜像的形式交付并以容器的方式运行了。
下图展示了上述步骤。
单体应用容器化
接下来我们会逐步展示如何将一个简单的单节点 Node.js Web 应用容器化。
如果是 Windows 操作系统的话,处理过程也是大同小异。
应用容器化的过程大致分为如下几个步骤:
获取应用代码。
分析 Dockerfile。
构建应用镜像。
运行该应用。
测试应用。
容器应用化细节。
生产环境中的多阶段构建。
最佳实践。
1) 获取应用代码
应用代码可以从网盘获取(https://pan.baidu.com/s/150UgIJPvuQUf0yO3KBLegg 提取码:pkx4)。
$ cd psweb
$ ls -l
total 28
-rw-r--r-- 1 root root 341 Sep 29 16:26 app.js
-rw-r--r-- 1 root root 216 Sep 29 16:26 circle.yml
-rw-r--r-- 1 root root 338 Sep 29 16:26 Dockerfile
-rw-r--r-- 1 root root 421 Sep 29 16:26 package.json
-rw-r--r-- 1 root root 370 Sep 29 16:26 README.md
drwxr-xr-x 2 root root 4096 Sep 29 16:26 test
drwxr-xr-x 2 root root 4096 Sep 29 16:26 views
该目录下包含了全部的应用源码,以及包含界面和单元测试的子目录。这个应用结构非常简单。
应用代码准备就绪后,接下来分析一下 Dockerfile 的具体内容。
2) 分析 Dockerfile
在代码目录当中,有个名称为 Dockerfile 的文件。这个文件包含了对当前应用的描述,并且能指导 Docker 完成镜像的构建。
在 Docker 当中,包含应用文件的目录通常被称为构建上下文(Build Context)。通常将 Dockerfile 放到构建上下文的根目录下。
另外很重要的一点是,文件开头字母是大写 D,这里是一个单词。像“dockerfile”或者“Docker file”这种写法都是不允许的。
接下来了解一下 Dockerfile 文件当中都包含哪些具体内容。
$ cat Dockerfile
FROM alpine
LABEL maintainer="nigelpoulton@hotmail.com"
RUN apk add --update nodejs nodejs-npm
COPY . /src
WORKDIR /src
RUN npm install
EXPOSE 8080
ENTRYPOINT ["node", "./app.js"]
Dockerfile 主要包括两个用途:
对当前应用的描述。
指导 Docker 完成应用的容器化(创建一个包含当前应用的镜像)。
不要因 Dockerfile 就是一个描述文件而对其有所轻视!Dockerfile 能实现开发和部署两个过程的无缝切换。
同时 Dockerfile 还能帮助新手快速熟悉这个项目。Dockerfile 对当前的应用及其依赖有一个清晰准确的描述,并且非常容易阅读和理解。
因此,要像重视你的代码一样重视这个文件,并且将它纳入到源控制系统当中。
下面是这个文件中的一些关键步骤概述:以 alpine 镜像作为当前镜像基础,指定维护者(maintainer)为“nigelpoultion@hotmail.com”,安装 Node.js 和 NPM,将应用的代码复制到镜像当中,设置新的工作目录,安装依赖包,记录应用的网络端口,最后将 app.js 设置为默认运行的应用。
具体分析一下每一步的作用。
每个 Dockerfile 文件第一行都是 FROM 指令。
FROM 指令指定的镜像,会作为当前镜像的一个基础镜像层,当前应用的剩余内容会作为新增镜像层添加到基础镜像层之上。
本例中的应用基于 Linux 操作系统,所以在 FROM 指令当中所引用的也是一个 Linux 基础镜像;如果要容器化的应用是一个基于 Windows 操作系统的应用,就需要指定一个像 microsoft/aspnetcore-build 这样的 Windows 基础镜像了。
截至目前,基础镜像的结构如下图所示。
接下来,Dockerfile 中通过标签(LABLE)方式指定了当前镜像的维护者为“nigelpoulton@hotmail. com”。
每个标签其实是一个键值对(Key-Value),在一个镜像当中可以通过增加标签的方式来为镜像添加自定义元数据。
备注维护者信息有助于为该镜像的潜在使用者提供沟通途径,这是一种值得提倡的做法。
RUN apk add --update nodejs nodejs-npm 指令使用 alpine 的 apk 包管理器将 nodejs 和 nodejs-npm 安装到当前镜像之中。
RUN 指令会在 FROM 指定的 alpine 基础镜像之上,新建一个镜像层来存储这些安装内容。当前镜像的结构如下图所示。
COPY. / src 指令将应用相关文件从构建上下文复制到了当前镜像中,并且新建一个镜像层来存储。COPY 执行结束之后,当前镜像共包含 3 层,如下图所示。
下一步,Dockerfile 通过 WORKDIR 指令,为 Dockerfile 中尚未执行的指令设置工作目录。
该目录与镜像相关,并且会作为元数据记录到镜像配置中,但不会创建新的镜像层。
然后,RUN npm install 指令会