建立您的Node映像
预计阅读时间:12分钟
先决条件
通过入门第1部分中的方向和设置来理解Docker概念。
概述
现在,我们对容器和Docker平台有了一个很好的了解,让我们看一下构建我们的第一个映像。映像包括运行应用程序所需的一切-代码或二进制文件,运行时,依赖项以及所需的任何其他文件系统对象。
要完成本教程,您需要以下内容:
- Node.js版本12.18或更高版本。下载Node.js
- 在本地运行的Docker:按照说明下载并安装Docker。
- IDE或文本编辑器来编辑文件。我们建议使用Visual Studio Code。
样品申请
让我们创建一个简单的Node.js应用程序,以作为示例。在本地计算机上创建一个名为的目录,node-docker
然后按照以下步骤创建一个简单的REST API。
$ cd [path to your node-docker directory]
$ npm init -y
$ npm install ronin-server ronin-mocks
$ touch server.js
现在,让我们添加一些代码来处理我们的REST请求。我们将使用模拟服务器,以便我们专注于对应用程序进行Docker化。
在IDE中打开此工作目录,然后将以下代码添加到server.js
文件中。
const ronin = require( 'ronin-server' )
const mocks = require( 'ronin-mocks' )
const server = ronin.server()
server.use( '/', mocks.server( server.Router(), false, true ) )
server.start()
模拟服务器将被调用,Ronin.js
并且默认情况下将在端口8000上进行侦听。您可以向根(/)端点发出POST请求,并且发送到服务器的所有JSON结构都将保存在内存中。您还可以将GET请求发送到同一端点,并接收先前已过帐的JSON对象数组。
测试应用程序
让我们启动我们的应用程序,并确保它运行正常。打开终端,然后导航到您创建的工作目录。
$ node server.js
为了测试应用程序是否正常运行,我们首先将一些JSON发布到API,然后发出GET请求以查看数据是否已保存。打开一个新终端并运行以下curl命令:
$ curl --request POST \
--url http://localhost:8000/test \
--header 'content-type: application/json' \
--data '{"msg": "testing" }'
{"code":"success","payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}
$ curl http://localhost:8000/test
{"code":"success","meta":{"total":1,"count":1},"payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}
切换回运行我们的服务器的终端。现在,您应该在服务器日志中看到以下请求。
2020-XX-31T16:35:08:4260 INFO: POST /test
2020-XX-31T16:35:21:3560 INFO: GET /test
为Node.js创建一个Dockerfile
Dockerfile是一个文本文档,其中包含用户可以在命令行上调用以组装映像的所有命令。当我们告诉Docker通过执行docker build
命令来构建映像时,Docker读取这些指令并逐个执行它们,并创建一个Docker映像。
让我们逐步为应用程序创建一个Dockerfile的过程。在工作目录的根目录中,创建一个名为的Dockerfile
文件,然后在文本编辑器中打开该文件。
笔记
Dockerfile的名称并不重要,但是许多命令的默认文件名只是
Dockerfile
。因此,在本系列中,我们将其用作文件名。
添加到Dockerfile的第一行是# syntax
解析器指令。虽然可选的,这个指令指示泊坞建设者解析Dockerfile当什么语法使用,并允许旧的码头工人版本的BuildKit启用开始构建之前升级解析器。解析器指令
必须出现在Dockerfile中的任何其他注释,空格或Dockerfile指令之前,应该是Dockerfiles中的第一行。
# syntax=docker/dockerfile:1
我们建议您使用docker/dockerfile:1
,它始终指向版本1语法的最新版本。BuildKit会在构建之前自动检查语法更新,以确保您使用的是最新版本。
接下来,我们需要在Dockerfile中添加一行,以告诉Docker我们想要为应用程序使用什么基本映像。
# syntax=docker/dockerfile:1
FROM node:12.18.1
Docker映像可以从其他映像继承。因此,我们将使用正式的Node.js映像,而不是创建自己的基本映像,该映像已经具有运行Node.js应用程序所需的所有工具和软件包。您可以以与考虑面向对象编程中的类继承相同的方式来考虑这一点。例如,如果我们能够用JavaScript创建Docker映像,则可以编写类似以下内容的代码。
class MyImage extends NodeBaseImage {}
这将创建一个名为的类MyImage
,该类从基类继承功能NodeBaseImage
。
同样,当使用FROM
命令时,我们告诉Docker将映像中的所有功能都包含在node:12.18.1
映像中。
笔记
如果您想了解有关创建自己的基本图像的更多信息,请参阅创建基本图像。
在NODE_ENV
环境变量指定在其中的应用程序运行的环境(通常,开发或生产)。要提高性能,最简单的操作之一就是将设置NODE_ENV
为production
。
ENV NODE_ENV=production
为了使运行其余命令更容易,让我们创建一个工作目录。这指示Docker使用此路径作为所有后续命令的默认位置。这样,我们不必键入完整的文件路径,但可以根据工作目录使用相对路径。
WORKDIR /app
通常,下载完用Node.js编写的项目后,要做的第一件事就是安装npm软件包。这样可以确保您的应用程序将其所有依赖项安装到node_modules
Node运行时可以在其中找到它们的目录中。
在运行之前npm install
,我们需要将package.json
和package-lock.json
文件放入映像中。我们使用COPY
命令来执行此操作。该 COPY
命令有两个参数。第一个参数告诉Docker您要将哪些文件复制到映像中。第二个参数告诉Docker您要将文件复制到哪里。我们将把package.json
和package-lock.json
文件复制到我们的工作目录中/app
。
COPY ["package.json", "package-lock.json*", "./"]
一旦将package.json
文件包含在映像中,就可以使用该RUN
命令执行命令npm install。它的工作原理与我们在计算机上本地运行npm install时完全相同,但是这次这些Node模块将安装到node_modules
映像内的目录中。
RUN npm install --production
至此,我们有了一个基于节点版本12.18.1的映像,并且已经安装了依赖项。我们需要做的下一件事是将源代码添加到图像中。就像package.json
上面的文件一样,我们将使用COPY命令。
COPY . .
COPY命令获取位于当前目录中的所有文件,并将它们复制到映像中。现在,我们要做的就是告诉Docker当我们的镜像在容器内部运行时,我们想运行什么命令。我们使用CMD
命令执行此操作。
CMD [ "node", "server.js" ]
这是完整的Dockerfile。
# syntax=docker/dockerfile:1
FROM node:12.18.1
ENV NODE_ENV=production
WORKDIR /app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install --production
COPY . .
CMD [ "node", "server.js" ]
创建一个.dockerignore文件
要在构建上下文中使用文件,Dockerfile引用指令(例如COPY指令)中指定的文件。为了提高构建的性能,可以通过在上下文目录中添加.dockerignore文件来排除文件和目录。为了缩短上下文加载时间,请创建一个.dockerignore
文件并node_modules
在其中添加目录。
node_modules
建立影像
现在我们已经创建了Dockerfile,让我们构建映像。为此,我们使用docker build
命令。该docker build
命令从Dockerfile和“上下文”构建Docker映像。构建的上下文是位于指定PATH或URL中的文件集。Docker构建过程可以访问上下文中的任何文件。
构建命令可以选择带有--tag
标志。标签用于设置图像名称和格式的可选标签‘name:tag’
。现在,我们将省略可选的“标签”以帮助简化操作。如果您不传递标签,则Docker将使用“最新”作为其默认标签。您将在构建输出的最后一行中看到这一点。
让我们构建我们的第一个Docker映像。
$ docker build --tag node-docker .
Sending build context to Docker daemon 82.94kB
Step 1/7 : FROM node:12.18.1
---> f5be1883c8e0
Step 2/7 : WORKDIR /code
...
Successfully built e03018e56163
Successfully tagged node-docker:latest
查看本地图像
要查看本地计算机上的图像列表,我们有两个选择。一种是使用CLI,另一种是使用Docker Desktop。由于我们当前正在终端中工作,因此让我们看一下使用CLI列出图像。
要列出图像,只需运行images
命令。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc About a minute ago 945MB
node 12.18.1 f5be1883c8e0 2 months ago 918MB
您应该至少看到列出的两个图像。一个用于基础图像node:12.18.1
,另一个用于我们刚刚构建的图像node-docker:latest
。
标记图片
图像名称由斜杠分隔的名称组成。名称部分可能包含小写字母,数字和分隔符。分隔符定义为一个句点,一个或两个下划线或一个或多个破折号。名称组件不能以分隔符开头或结尾。
图像由清单和图层列表组成。简而言之,“标签”指向这些工件的组合。一个图像可以有多个标签。让我们为构建的图像创建第二个标签,并查看其图层。
要为我们上面构建的图像创建一个新标签,请运行以下命令。
$ docker tag node-docker:latest node-docker:v1.0.0
Docker tag命令为图像创建一个新标签。它不会创建新图像。标签指向相同的图像,并且是引用图像的另一种方法。
现在,运行docker images
命令以查看我们的本地图像列表。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc 24 minutes ago 945MB
node-docker v1.0.0 3809733582bc 24 minutes ago 945MB
node 12.18.1 f5be1883c8e0 2 months ago 918MB
您会看到我们有两个以开头的图像node-docker
。我们知道它们是同一张图像,因为如果您查看“图像ID”列,则可以看到两个图像的值相同。
让我们删除刚刚创建的标签。为此,我们将使用rmi命令。rmi命令代表“删除图像”。
$ docker rmi node-docker:v1.0.0
Untagged: node-docker:v1.0.0
请注意,Docker的响应告诉我们,该映像尚未删除,只是“未标记”。通过运行images命令来验证这一点。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc 32 minutes ago 945MB
node 12.18.1 f5be1883c8e0 2 months ago 918MB
带有标记的图像:v1.0.0
已被删除,但我们node-docker:latest
的机器上仍具有可用的标记。
下一步
在本模块中,我们看了如何设置示例Node应用程序,并将在本教程的其余部分中使用该应用程序。我们还创建了一个Dockerfile,用于构建Docker映像。然后,我们看了一下标记图像和删除图像的过程。在下一个模块中,我们将研究如何:
反馈
通过提供您的反馈帮助我们改善此主题。通过在Docker Docs GitHub存储库中创建问题,让我们知道您的想法。或者,创建PR以建议更新。