我花了过去几个小时试图设置2默认图像的nodejs 14和rethinkdb 2.3.5,所以很抱歉,如果语气有点沮丧,但我目前感到沮丧。
我的要求似乎超级简单。
npm测试
我希望测试能够在所有开发人员机器上重复-目前没有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
这个答案的重点不是尽可能给出必须简洁的解释(简要而清晰地表达),而是强调当前 docs.docker.com 和 hub.docker.com 文档造成的所有混乱。最终,我/我们会做对,并可以写一个简洁的答案。
更正后的 docker-compose.yml
:
version: "3"
services:
tests:
image: "node:14"
user: "node"
working_dir: /home/node/app
volumes:
- ./:/home/node/app
container_name: nodejs
depends_on:
- rethinkdb
command: bash -c "npm ci && npm test"
rethinkdb:
image: rethinkdb:2.3.5
container_name: rethinkdb
马上,docs.docker.com和hub.docker.com的文档可以说是有史以来最糟糕的文档,因为它a)是错误的,b)假设了先验知识。
如果下面的任何一个是错误的——那就归咎于可怕的文档。
不,除非您计划构建自己的映像,否则您不需要Dockerfile。
因此,在浪费了一个小时左右的时间在不同的过时示例上之后,您可能会幸运地发现,您尝试使用上下文
来绕过绝对路径示例的所有内容......这根本不重要,除非你从头开始创建自己的镜像(90%的 docker 用户不需要)。
提示:使用<code>docker system prune</code>删除您通过以下示例创建的所有不幸无用的docker容器。
接下来,找到正确的docker容器。
没有一个地方写着<code>图像</code>。你只需要知道。
version: "3"
使用语法的3. x版本。语法与Compose和Docker兼容性矩阵中列出的Docker引擎版本不同。
services:
每个容器映像都是Docker Compose术语中的服务。test
和rethinkdb
是我对2个映像的名称。您可以根据需要命名它们,但我们稍后将使用此名称来创建2个映像之间的依赖关系(一个需要在另一个之前在线)。
services:
tests:
...
rethinkdb:
...
test
和rethinkdb
是我们将让Docker Compose为我们运行的两个服务。
image: "node:14"
幸运的是,nodejs Docker开发人员在 hub.docker.com/_/node 中提供了非常好的文档,而不是适当的标准文档。
图像变体:事实图像<代码>节点:
image: rethinkdb:2.3.5
不幸的是,资金较少的RethinkDB项目Docker Hub页面
没有这样的信息。
实际上,如果您一直向下滚动到页面底部,您会发现图像变体(抱歉,我无法链接到 hub.docker.com 的标题,因为它们没有id
或name
属性)。您要使用的2个版本是rethinkdb:
问:那么更主要的支持标签和各自的docker文件链接部分呢?
A: 它们的使用频率较低,是专门的docker映像。在RejectDB的例子中,它是Debian Buster和CentOS上的RejectDB数据库安装。还有一些版本的链接,但不是全部。因此,这是一个选定的图像列表,您可能不想要。记住,你必须点击标签或小的灰色链接;查看可用的标签(请参见上面带有红色方块的图像-抱歉,也没有锚链接支持)。
user: "node"
working_dir: /home/node/app
volumes:
- ./:/home/node/app
如果您在docs.docker.com上查找
user
或working_dir
,那么您在没有事先了解docker
的情况下就倒霉了。它只声明:
每一个都是一个单独的值,类似于docker运行的对应值。请注意,mac_ address是一个传统选项。
这里的目标是将当前目录(即< code>docker-compose.yml
所在的目录)复制到< code>tests服务,该服务提取< code>node:14图像。我们需要在容器中创建一个目录,我们机器上的当前目录将被复制到这个目录中。稍后,我们希望在该目录中执行一些命令,并且我们不希望以< code>sudo的身份运行,所以自然的位置是在我们的用户主目录(< code>~/)中。
我们需要:
nodejs
容器中的用户。nodejs
容器的用户主目录中创建一个目录。nodejs
容器中的新目录。在阅读了nodejs开发人员编写的如何使用此图像后,我们可以在示例中看到图像中有一个节点
用户。该示例还显示了我们需要哪些Docker组合配置。
user: "node"
大概使用图像中定义的节点用户:“node: 14”
。
working_dir: /home/node/app
在< code>node用户的主目录中创建一个应用程序目录。
volumes:
- ./:/home/node/app
将我们机器上的当前目录映射到< code>tests容器(使用< code>image: "node:14")中的/home/node/app目录。
container_name: nodejs
事实证明,定义container_name
纯粹是装点门面。它不能帮助您链接网络或在另一个容器之前启动一个容器。它只是一个名称。当您的容器运行时,您可以使用docker ps
来查看它们或docker ps-a
来查看所有容器,甚至是关闭的容器。在NAMES列中,写入了container_name
。如果您没有定义container_name
,那么它们将被称为您的目录名和服务名,后用增量号固定。
docker-ps
与container_name
,同时运行:
CONTAINER ID IMAGE PORTS NAMES
5272576f8555 node:14 nodejs
fb11d5ce049b rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp rethinkdb
docker ps
运行时不带容器_name
:
CONTAINER ID IMAGE PORTS NAMES
528e5ee37956 node:14 data_access_layer_tests_1
e80682b806fc rethinkdb:2.3.5 8080/tcp, 28015/tcp, 29015/tcp data_access_layer_rethinkdb_1
depends_on:
- rethinkdb
depends_on
是神奇的!它告诉 Docker Compose,在此容器之前,rethinkdb
容器必须
联机
启动。
这是Docker Compose文档(depends_on
)的一个罕见案例,它实际上很好。
不幸的是,depends_on
并不能保证相关图像是在线的,正如您所期望的那样,但是在这种情况下,文档也非常清晰,并提供了另一种解决方案。在我们的例子中,这并不重要,因为rethinkdb
容器的启动速度足够快(nodejs
中的npm ci
将比rethinkdb
的启动时间长得多)。
command: "npm ci && npm test"
现在我们可以在docker容器中运行一些命令,
就好像我们在项目目录中的机器上运行它们一样
npm ci。请参阅使用Docker Compose的SO答案,以及如何执行多个命令。Docker使用了一种晦涩难懂的shell脚本变体,它可以执行一个命令,而且只能执行一个带有参数的命令。文档中说它类似于docker<code>CMD</code>键,但这两个站点都没有解释为什么某些POSIX shell命令可以工作,而其他命令不能工作,但我们认为这让docker开发人员的生活更轻松:)
执行多个命令的正确方法是:
command: bash -c "npm ci && npm test"
请参见“使用Docker-Compose,如何执行多个命令”。
npm ci
从package-lock.json安装所有npm包,并且npm test
在package.json.中运行我们的"test"
脚本
您可能认为可以在一个YAML数组中编写多个命令,但在这种情况下,这样做显然会告诉node将<code>作为容器中的模块要求<code>这些命令,并且会出现如下错误:
nodejs | internal/modules/cjs/loader.js:883
nodejs | throw err;
nodejs | ^
nodejs |
nodejs | Error: Cannot find module '/home/node/app/npm ci'
nodejs | at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
nodejs | at Function.Module._load (internal/modules/cjs/loader.js:725:27)
nodejs | at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
nodejs | at internal/main/run_main_module.js:17:47 {
nodejs | code: 'MODULE_NOT_FOUND',
nodejs | requireStack: []
nodejs | }
command:
- "npm ci"
- "npm test"
上述方法将不起作用!
而是使用通常的
实际上,忘记上述内容,使用
entrypoint
指向一个bash文件,您可以在其中编写所有命令。
不要使用< code>docker-compose up -d
!
您不必在这里做任何事情。即使每个Docker Compose教程都会告诉您以分离模式运行。您不会看到stdout或stderr。只需松开-d
。
docker-compose up
是要走的路!
如果您真的必须在分离模式下运行,您可以通过docker日志[container id]
查看输出,并通过docker ps
,或docker ps-a
获取容器id。如果容器当前未运行,则使用后者。
原来Docker有很多合理的默认值,除非你真的必须这样做,否则你不应该乱动这些默认值。
ports:
- "28015:28015"
- "8080:8080"
您不需要在docker-compose.yml
中公开端口,除非您需要将端口公开给本地计算机或外部网络,即使每个示例都这样做。例如,如果您需要访问localhost:8080
(在RethinkDB中是仪表板),那么您必须添加:
ports:
- "8080:8080"
您的其他服务/容器将可以访问端口28015
和8080
,使用服务名称作为主机名,而无需在docker compose.ymlDB:28015
。有关更多信息,请参见下文。
links:
- rethinkdb
链接
似乎是连接两个不同容器的一种方式,但事实证明,所有容器都共享网络,因此您不必这样做。官方文档中有一个大红色警告,建议您使用用户定义的网络。这又表明:
默认情况下,“合成”会为您的应用程序设置一个网络。服务的每个容器都加入默认网络,并且对于该网络上的其他容器都是可到达的,并且可以通过与容器名称相同的主机名被它们发现。
这是一种复杂的说法,在Docker Compose容器中,您可以像在本地机器上一样连接端口和IP地址。
因此,如果容器A的图像暴露了
172.18.0.2:28015
,那么您可以使用该确切地址从容器B连接。E、 i.IP:
172.18.0.2
和端口:
28015
服务的每个容器都加入默认网络,并且可以由该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现。
意味着您的服务名被用作主机名,就像您在/etc/hosts文件中定义它一样。或者类似于DNS将stackoverflow.com链接到151.101.193.69。
因此,如果容器<code>RejectDB</code>公开了端口<code>28015</code>则可以通过<code>RejectDB:28015nodejs</code>容器访问该端口。
注意文件上说:
version: "3.9"
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres
ports:
- "8001:5432"
每个容器现在都可以查找主机名web
或db
并获取相应容器的IP地址。例如,web
的应用程序代码可以连接到URLpostgres://db: 5432
并开始使用Postgres数据库。
在Compose
@jonrshape指出协议(postgres
中的网络示例中是
image
,
db
是服务名称,
5432
是端口号。这在我的经验中不起作用。您需要使用服务名称,而不是
image
名称。因此,从
web
连接到
db
的正确方法是使用URL
db: 5232
。
postgres://
)恰好与图像名称匹配。
以下是我之前对该示例理解的更正。
在Composepostgres
中的网络示例中是协议(类似于https
),db
是服务名称,5432
是端口号。您需要使用服务名称,才能获得正确的IP地址。因此,从web
连接到db
的正确方法是使用URL[协议]://db: 5232
。其中协议
可以是超文本传输协议
、https
、prores
等。
因为所有容器都在同一个网络中,所以不需要< code>ports键,除非您需要向本地机器(或外部网络)公开服务。
volumes:
- "./data: /data"
每个RethinkDB < code > docker file 都有这个,但是只有当您想要将文件从本地机器复制到容器中时才需要这个。在这种情况下,我们不想预加载任何数据库,所以我们没有任何文件来作为数据库的种子,因此不需要< code>volumes键。
问题内容: 我正在尝试设置spring xml配置,而不必创建进一步的。但是,即使我将数据库属性包括在 spring.xml: 我在这里想念什么? 问题答案: 在entityManagerFactory bean定义中指定“ packagesToScan”和“ persistenceUnitName”属性。 请注意,这适用于Spring版本> 3.1
问题内容: 我目前正在使用不带Spring配置文件的CXF在Web Service客户端上工作。 它工作得很好,但是我不知道如何使用Java Api设置绑定的SoapVersion。使用Spring文件,可以按以下步骤完成: 你们知道如何在Java代码中执行此操作(在Port上,在SOAPBinding上…)? 在此先感谢您的帮助! 编辑 - - - - - - - - - - - 我仍然遇到这个
问题内容: 我在一个项目中工作,我需要为每个对象添加一个快捷键,同时查找另一个类似的问题,并且在使用其他自定义s时,我决定在每个s 上使用该方法,但是这需要我按- “触发” 我班上的方法。 我如何修改此类以仅按- 并获得相同的行为? 这是我编写的用于演示此问题的代码: 问题答案: 您如何将任何键绑定到Swing中的组件?按键绑定:按键绑定教程。 等一下,我看看您的代码… 例如 因为通常JRadio
我正在尝试设置SpringXML配置,而不必创建进一步的。但是我经常遇到以下异常,即使我在 spring.xml: 我错过了什么?
问题内容: 我正在学习使用Selenium(v2.20)来领先一些 即将使用它创建浏览器测试的程序员。我想在 陷阱到达之前发现它们,而我却跌入了一个陷阱。 当我创建ChromeDriver时,它始终会弹出“ Google Chrome EULA”并 显示两个按钮:“接受并运行”和“取消”。因为我希望这是一个 自动化测试,所以让用户单击按钮是不可能的。 我查看了Chromium CommandSwi
我已经安装了Android SDK最新版本和Eclipse。但我也想试试Android Studio。 我看过这个和这个帖子,但是那些解决方案改变了Android Studio(一旦下载并安装)使用的SDK实例。我想要的不是下载另一个SDK,当我已经在我的机器上安装了它。