dot*_*ter 13 node.js rethinkdb docker-compose
我花了过去几个小时尝试设置 Nodejs 14 和 rethinkdb 2.3.5 的 2 个默认映像,如果语气有点沮丧,我很抱歉,但我目前很沮丧。
我的要求看似非常简单。
npm ci
和npm test
。我希望测试能够在所有开发人员机器上重现 - 目前没有 CI。无论开发人员将项目保存在硬盘上的哪个位置。
我有一个docker-compose.yml
文件。
version: "3"
services:
tests:
image: node:14
ports:
- "3000:3000"
# command:
# - npm ci
# - npm test
volumes:
- ".:/cli-app"
depends_on:
- rethinkdb
rethinkdb:
image: rethinkdb
ports:
- "28015:28015"
- "8080:8080"
volumes:
- "./data: /data"
command: rethinkdb --bindall --data /data
Run Code Online (Sandbox Code Playgroud)
dot*_*ter 26
\n\n这个答案的目的不是给出尽可能简洁的解释(简短而清晰地表达),而是强调 docs.docker.com 和 hub.docker.com 上当前文档造成的所有混乱。最终我/我们会做对并且可以写出一个简洁的答案。
\n
更正后的docker-compose.yml
:
version: "3"\nservices:\n tests:\n image: "node:14"\n user: "node"\n working_dir: /home/node/app\n volumes:\n - ./:/home/node/app\n container_name: nodejs\n depends_on:\n - rethinkdb\n command: bash -c "npm ci && npm test"\n\n rethinkdb:\n image: rethinkdb:2.3.5\n container_name: rethinkdb\n
Run Code Online (Sandbox Code Playgroud)\n立刻,docs.docker.com 和 hub.docker.com 上的文档可以说是有史以来最糟糕的文档,因为它 a)错误,b)假设先验知识。
\n如果以下任何一个是错误的 - 归咎于可怕的文档。
\n\n不,除非您打算构建自己的映像,否则您不需要 Dockerfile 。
\n因此,在不同的过时 示例上浪费了一个小时左右之后,您可能会幸运地发现,您为context
绕过绝对路径示例而尝试过的所有操作都无关紧要,除非您从头开始创建自己的图像(这90%的docker用户,不需要)。
\n\n提示使用
\ndocker system prune
以下示例删除您创建的所有不幸的无用 docker 容器。
接下来,找到正确的 docker 容器。
\n展示:nodejs官方 docker 镜像!\n\n
没有一处提到image
。你只需要知道。
docker-compose.yml
version: "3"\n
Run Code Online (Sandbox Code Playgroud)\n使用 3.x 版本的语法。语法与Compose 和 Docker 兼容性矩阵中列出的 Docker 引擎版本不同。
\nservices:\n
Run Code Online (Sandbox Code Playgroud)\n每个容器镜像都是 Docker Compose 术语中的一个服务。tests
和rethinkdb
是我的两张图片的名字。您可以根据需要命名它们,但我们稍后将使用此名称来创建两个图像之间的依赖关系(一个需要在另一个之前上线)。
services:\n tests:\n ...\n rethinkdb:\n ...\n
Run Code Online (Sandbox Code Playgroud)\ntests
和rethinkdb
是我们将让 Docker Compose 为我们运行的两个服务。
image: "node:14"\n
Run Code Online (Sandbox Code Playgroud)\n幸运的是,nodejs Docker 开发人员在hub.docker.com/_/node上提供了非常好的文档来代替适当的标准文档。
\n\n\n镜像变体:事实上的镜像
\nnode:<version>
和镜像基于流行的 Alpine Linux 项目,该项目比大多数发行版基础镜像(约 5MB)小得多,因此通常会导致镜像更薄。node:<version>-alpine
node:<version>-alpine
image: rethinkdb:2.3.5\n
Run Code Online (Sandbox Code Playgroud)\n不幸的是,资金较少的 RethinkDB 项目,Docker Hub 页面 没有这样的信息。实际上,如果你一直滚动到页面底部,你会发现图像变体(抱歉,我无法链接到 hub.docker.com 上的标题,因为它们没有id
orname
属性)。您要使用的 2 个版本是rethinkdb:<version>
或rethinkdb:<version>-slim
。
问:\n那么更占主导地位的Supported 标签和相应的 Dockerfile 链接部分又如何呢?
\n答:\n它们的使用频率较低,并且是专门的 docker 镜像。在 RethinkDB 案例中,它是 Debian Buster 和 CentOS 上安装的 RethinkDB 数据库。还有一些版本的链接,但不是全部。所以这是一个选定的图像列表,您可能不想要。请记住,您必须单击标签或灰色小链接;查看可用标签(请参见上面带有红色方块的图像 - 抱歉,SO 上也没有锚链接支持)。
\n user: "node"\n working_dir: /home/node/app\n volumes:\n - ./:/home/node/app\n
Run Code Online (Sandbox Code Playgroud)\n如果您查找docs.docker.comuser
或在docs.docker.comworking_dir
上查找,那么您在没有事先了解的情况下就不走运了docker
. 它仅指出:
\n\n其中每个都是单个值,类似于其 docker run 对应项。请注意,mac_address 是一个旧选项。
\n
这里的目标是将当前目录(所在docker-compose.yml
目录)复制到tests
拉取node:14
映像的服务。我们需要在容器中创建一个目录,将机器上的当前目录复制到其中。稍后,我们想要在该目录中执行一些命令,但我们不想将其运行为sudo
,因此自然放置在我们的用户主目录 ( ~/
) 中。
我们需要:
\nnodejs
。nodejs
。nodejs
容器中的新目录。阅读完Nodejs 开发人员编写的如何使用此镜像后,我们可以在示例中看到node
镜像中有一个用户。\n该示例还显示了我们需要哪些 Docker Compose 配置。
user: "node"\n
Run Code Online (Sandbox Code Playgroud)\n大概使用 中定义的节点image: "node:14"
用户。
working_dir: /home/node/app\n
Run Code Online (Sandbox Code Playgroud)\n在用户的主目录中创建一个应用程序目录。node
volumes:\n - ./:/home/node/app\n
Run Code Online (Sandbox Code Playgroud)\n将机器上的当前目录映射到容器内的/home/node/apptests
目录(使用image: "node:14"
)。
container_name: nodejs\n
Run Code Online (Sandbox Code Playgroud)\n事实证明,定义container_name
纯粹是装饰性的。它不能帮助您链接网络或在另一个容器之前启动一个容器。这只是一个名字。当容器运行时,您可以用来docker ps
查看它们或docker ps -a
查看所有容器,甚至是已关闭的容器。在NAMES列中container_name
写入。如果您没有定义container_name
,那么它们将被称为您的目录名称和服务名称,并后缀有增量数字。
docker ps
运行时container_name
:
CONTAINER ID IMAGE PORTS NAMES\n5272576f8555 node:14 nodejs\nfb11d5ce049b rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp rethinkdb\n
Run Code Online (Sandbox Code Playgroud)\ndocker ps
container_name
运行时没有:
CONTAINER ID IMAGE PORTS NAMES\n528e5ee37956 node:14 data_access_layer_tests_1\ne80682b806fc rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp data_access_layer_rethinkdb_1\n
Run Code Online (Sandbox Code Playgroud)\nCONTAINER ID IMAGE PORTS NAMES\n5272576f8555 node:14 nodejs\nfb11d5ce049b rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp rethinkdb\n
Run Code Online (Sandbox Code Playgroud)\ndepends_on
是神奇的!它告诉 Docker Composerethinkdb
容器必须是在线的在此容器之前开始。
在极少数情况下,Docker Compose 文档 ( depends_on
)实际上很好。
不幸的是,depends_on
不能保证依赖的图像在线,正如您所期望的那样,但在这种情况下,文档也非常清楚,并提供了另一种解决方案。在我们的例子中,这并不重要,因为rethinkdb
容器启动得足够快(npm ci
innodejs
将比 的启动时间长得多rethinkdb
)。
CONTAINER ID IMAGE PORTS NAMES\n528e5ee37956 node:14 data_access_layer_tests_1\ne80682b806fc rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp data_access_layer_rethinkdb_1\n
Run Code Online (Sandbox Code Playgroud)\n现在我们可以在 docker 容器中运行一些命令,就好像我们在我们的机器上的项目目录中运行它们一样。 当然不是。上面只会执行npm ci
. 请参阅SO答案Using Docker-Compose, how to执行多个命令。Docker 使用一种晦涩难懂的 shell 脚本变体,它可以执行一个且仅一个带参数的命令。文档说它与docker key类似,但两个网站都没有解释为什么某些 POSIX shell 命令有效而其他命令无效,但我们认为它让 Docker 开发人员的生活更轻松:)CMD
执行多个命令的正确方法是:
\n depends_on:\n - rethinkdb\n
Run Code Online (Sandbox Code Playgroud)\n请参阅《使用Docker-Compose,如何执行多个命令》。
\nnpm ci
安装package-lock.json中的所有 npm 包并npm test
运行package.json"test"
中的脚本。
您可能认为您可以在 YAML 数组中编写多个命令,但在这种情况下,这样做显然会告诉节点require
它们作为容器内的模块,您将收到如下错误:
nodejs | internal/modules/cjs/loader.js:883\nnodejs | throw err;\nnodejs | ^\nnodejs |\nnodejs | Error: Cannot find module \'/home/node/app/npm ci\'\nnodejs | at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)\nnodejs | at Function.Module._load (internal/modules/cjs/loader.js:725:27)\nnodejs | at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)\nnodejs | at internal/main/run_main_module.js:17:47 {\nnodejs | code: \'MODULE_NOT_FOUND\',\nnodejs | requireStack: []\nnodejs | }\n
Run Code Online (Sandbox Code Playgroud)\n command: "npm ci && npm test"\n
Run Code Online (Sandbox Code Playgroud)\n上面的方法不行!
\n而是使用通常的方式再次强调,使用 Docker-Compose,如何执行多个命令是正确的文档。&&
执行一系列成功的命令。
实际上,忘记上面的内容并使用entrypoint
指向您编写所有命令的 bash 文件。
不使用docker-compose up -d
!
您无需在这里执行任何操作。尽管每个 Docker Compose 教程都会告诉您以分离模式运行。您将看不到标准输出或标准错误。只要松开-d
.
docker-compose up
是要走的路!
如果您确实必须在分离模式下运行,您可以通过或来查看输出docker logs [container id]
并获取容器 ID 。如果您的容器当前未运行,则使用后者。docker ps
docker ps -a
docker-compose.yml
看起来像是需要的钥匙事实证明,Docker 附带了许多合理的默认设置,除非确实必要,否则您不应该弄乱这些默认设置。
command: bash -c "npm ci && npm test"\n
Run Code Online (Sandbox Code Playgroud)\n您不需要公开 a 中的端口,docker-compose.yml
除非您需要将端口公开到本地计算机或外部网络,即使那里的每个示例都这样做。例如,如果您需要访问localhost:8080
(在 RethinkDB 中是仪表板),那么您必须添加:
nodejs | internal/modules/cjs/loader.js:883\nnodejs | throw err;\nnodejs | ^\nnodejs |\nnodejs | Error: Cannot find module \'/home/node/app/npm ci\'\nnodejs | at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)\nnodejs | at Function.Module._load (internal/modules/cjs/loader.js:725:27)\nnodejs | at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)\nnodejs | at internal/main/run_main_module.js:17:47 {\nnodejs | code: \'MODULE_NOT_FOUND\',\nnodejs | requireStack: []\nnodejs | }\n
Run Code Online (Sandbox Code Playgroud)\n您的其他服务/容器将可以使用服务名称作为主机名来访问端口28015
和8080
,而无需在docker-compose.yml
. 例如在这种情况下rethinkdb:28015
。请参阅下面的详细信息。
command:\n - "npm ci"\n - "npm test"\n
Run Code Online (Sandbox Code Playgroud)\nlinks
似乎是连接两个不同容器的一种方法,但事实证明所有容器共享网络,因此您不必这样做。官方文档中带有一个大红色的WARNING,建议你使用用户自定义的网络。反过来说:
\n\n默认情况下,Compose 会为您的应用程序设置一个网络。服务的每个容器都会加入默认网络,并且可以被该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现。
\n
这是一种复杂的说法,在 Docker Compose 容器内,您可以像在本地计算机上一样连接到端口和 IP 地址。
因此,如果容器 A 的映像公开,刮掉那个!暴露的IP地址不稳定。Docker 会出于各种(未知)原因更改它们。172.18.0.2:28015
那么您可以使用该确切地址从容器 B 进行连接。Ei IP:172.18.0.2
和端口: 28015
。
\n\n服务的每个容器都会加入默认网络,并且可以被该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现。
\n
意味着您的服务名称将用作主机名,就像您在/etc/hosts文件中定义它一样。或者类似于 DNS 如何将 stackoverflow.com 链接到 151.101.193.69。
\n因此,如果容器rethinkdb
公开端口28015
,则可以nodejs
通过容器访问该端口rethinkdb:28015
。
请注意文档说:
\n ports:\n - "28015:28015"\n - "8080:8080"\n
Run Code Online (Sandbox Code Playgroud)\n\n\n现在,每个容器都可以查找主机名
\nweb
或db
获取相应的容器\xe2\x80\x99s IP 地址。例如,web
\xe2\x80\x99s 应用程序代码可以连接到 URLpostgres://db:5432
并开始使用 Postgres 数据库。
在Compose 中的网络示例 中,@jonrsharpe 指出该协议(postgres
是服务名称,是端口号。根据我的经验,这是行不通的。您需要使用服务名称,而不是名称。所以从to连接的正确方法是使用 URL 。image
db
5432
image
web
db
db:5232
postgres://
) 恰好与图像名称匹配。
下面是我之前对例子的理解的修正。
\n在Compose 中的 Networking 示例 postgres
中, 是协议(类似于https
),db
是服务名称,5432
是端口号。您需要使用服务名称来获取正确的 IP 地址。web
所以从to连接的正确方法db
是使用 URL [protocol]://db:5232
。哪里protocol
可以http
,,,等等https
。progres
由于所有容器都位于同一网络内,因此除非需要向本地计算机(或外部网络)公开服务,否则不需要密钥。ports
ports:\n - "8080:8080"\n
Run Code Online (Sandbox Code Playgroud)\n每个 RethinkDBDockerfile
都有这个,但只有当您想将文件从本地计算机复制到容器中时才需要这个。在这种情况下,我们不想向数据库预加载任何内容,因此我们没有任何文件来为数据库提供种子,因此volumes
不需要密钥。
归档时间: |
|
查看次数: |
10011 次 |
最近记录: |