简体   繁体   English

如何在没有 Dockerfile 的情况下设置 Docker 组合?

[英]How to setup Docker Compose without a Dockerfile?

I have spend the last few hours trying to setup 2 default images of nodejs 14 and rethinkdb 2.3.5, so sorry if the tone is a little frustrated but I am currently frustrated.我花了过去几个小时尝试设置 nodejs 14 和 rethinkdb 2.3.5 的 2 个默认图像,如果语气有点沮丧,我很抱歉,但我目前很沮丧。

My requirements are seemingly super simple.我的要求看似超级简单。

I want to:我想要:

  1. download the default images for nodejs 14 and rethinkdb 2.3.5下载 nodejs 14 和 rethinkdb 2.3.5 的默认图像
  2. copy everything from my current directory into the nodejs 14 image.将我当前目录中的所有内容复制到 nodejs 14 映像中。
  3. I want the nodejs image to depend on the RethinkDB image.我希望 nodejs 图像依赖于 RethinkDB 图像。
  4. run 2 commands in the nodejs 14 image;在 nodejs 14 镜像中运行 2 个命令; npm ci and npm test . npm cinpm test
  5. see the stdout from the tests.从测试中查看标准输出。

I do not need:我不需要:

  1. any ports to be accessible to the host machine.主机可以访问的任何端口。
  2. to customize any Dockerfile or make any changes to the default images.自定义任何 Dockerfile 或对默认图像进行任何更改。
  3. any updates from the host machine file-system to the containers.从主机文件系统到容器的任何更新。
  4. to copy any data from the host machine to the RethinkDB container.将任何数据从主机复制到 RethinkDB 容器。

Why?为什么?

I want the tests to be reproducible across all developer machines - currently no CI.我希望测试能够在所有开发人员机器上重现——目前没有 CI。 Regardless of where the developer has the project on their hard drive.无论开发人员将项目放在硬盘上的哪个位置。

I have a single docker-compose.yml file.我有一个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

The point of this answer is not to give the must succinct explanation (briefly and clearly expressed) as possible but to highlight all the confusion that the current documentation at docs.docker.com and hub.docker.com create. The point of this answer is not to give the must succinct explanation (briefly and clearly expressed) as possible but to highlight all the confusion that the current documentation at docs.docker.com and hub.docker.com create. Eventually I/we will get it right and a succinct answer can be written.最终我/我们会做对,并且可以写出简洁的答案。

The corrected docker-compose.yml :更正后的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

The frustrating part!令人沮丧的部分!

Right off the bat, the documentation at docs.docker.com and hub.docker.com is arguably the worse documentation ever written, since it is a) wrong , b) assumes prior knowledge . Right off the bat, the documentation at docs.docker.com and hub.docker.com is arguably the worse documentation ever written, since it is a) wrong , b) assumes prior knowledge .

If any of the following is wrong - blame the horrible documentation.如果以下任何一项是错误的 - 归咎于可怕的文档。

在此处输入图像描述

No, you do not need a Dockerfile unless you plan to built your own image.不,您不需要Dockerfile ,除非您计划构建自己的映像。

So after wasting an hour or so on different outdated examples , you might be lucky to discover that everything you have tried with context to get around the absolute path examples... does not matter at all unless you are creating your own image from scratch (which 90% of docker users, do not need).因此,在浪费了一个小时左右的不同过时示例之后,您可能会幸运地发现您尝试使用context来绕过绝对路径示例的所有内容......根本不重要,除非您从头开始创建自己的图像(其中 90% 的 docker 用户,不需要)。

Tip use docker system prune to delete all those unfortunate useless docker containers you've creating by following example.提示使用docker system prune来删除您通过以下示例创建的所有那些不幸的无用 docker 容器。

Next up, find the correct docker containers.接下来,找到正确的 docker 容器。

Presenting: nodejs official docker image!赠送: nodejs官方docker镜像! 在此处输入图像描述 在此处输入图像描述

Did you see the image name that we need?您看到我们需要的图像名称了吗?

在此处输入图像描述

Not one place does it say image .没有一个地方说image You just have to know.你只需要知道。

Line by line explanation to docker-compose.yml逐行解释docker-compose.yml

version: "3"

Uses version 3.x of the syntax.使用 3.x 版本的语法。 The syntax varies from Docker engine versions as listed at Compose and Docker compatibility matrix .语法与Compose 和 Docker 兼容性矩阵中列出的 Docker 引擎版本不同。

services:

Each container image is a service in Docker Compose terminology.每个容器镜像都是 Docker Compose 术语中的一个服务。 tests and rethinkdb are my names for 2 images. testsrethinkdb是我的 2 张图片的名字。 You can name them as you want but we will use this name later to create a dependency between the 2 images (one needs to be online before the other).您可以根据需要命名它们,但稍后我们将使用此名称在 2 个图像之间创建依赖关系(一个需要在另一个之前在线)。

services:
  tests:
    ...
  rethinkdb:
    ...

tests and rethinkdb are the two services that we will get Docker Compose to run for us. testsrethinkdb是我们将让 Docker Compose 为我们运行的两个服务。

Fix: 1. download the default images for nodejs 14 and rethinkdb 2.3.5修复:1.下载nodejs 14和rethinkdb 2.3.5的默认镜像

    image: "node:14"

Luckily the nodejs Docker developers included extremely nice documentation in lieu of proper standard documentation at hub.docker.com/_/node .幸运的是,nodejs Docker 开发人员在hub.docker.com/_/node上提供了非常好的文档来代替适当的标准文档。

Image variants: The defacto image node:<version> and node:<version>-alpine node:<version>-alpine image is based on the popular Alpine Linux project, which is much smaller than most distribution base images (~5MB), and thus leads to much slimmer images in general..镜像变体:事实上的镜像node:<version>node:<version>-alpine node:<version>-alpine镜像基于流行的 Alpine Linux 项目,它比大多数发行版基础镜像 (~5MB) 小得多,因此通常会导致图像更苗条..

    image: rethinkdb:2.3.5

Unfortunately, the less funded RethinkDB project, Docker Hub page不幸的是,资金较少的 RethinkDB 项目, Docker Hub 页面does not have such information.没有这样的信息。 Actually if you scroll all the way down to the bottom of the page, you will find Image Variants (sorry, I can not link to headings on hub.docker.com since they do not have an id or name attribute).实际上,如果您一直向下滚动到页面底部,您会发现Image Variants (抱歉,我无法链接到 hub.docker.com 上的标题,因为它们没有idname属性)。 The 2 versions you will want to use is either rethinkdb:<version> or rethinkdb:<version>-slim .您将要使用的 2 个版本是rethinkdb:<version>rethinkdb:<version>-slim

Q: So what about the much more dominant Supported tags and respective Dockerfile links section?问:那么更占主导地位的支持标签和相应的 Dockerfile 链接部分呢?

A: They are less frequently needed and are specialized docker images.答:它们不太常用,是专门的 docker 映像。 In the RethinkDB case, it is the RethinkDB database install on Debian Buster and CentOS.在 RethinkDB 案例中,它是安装在 Debian Buster 和 CentOS 上的 RethinkDB 数据库。 There is also a link to some versions but not all.还有一些版本的链接,但不是全部。 So it's a selected list of images, you probably do not want.所以这是一个选定的图像列表,你可能不想要。 Remember you have to click on Tags or the small grey link;请记住,您必须单击标签或灰色的小链接; View Available Tags (see the image above with the red squares - sorry no anchor linking support on SO either).查看可用标签(见上图红色方块 - 抱歉,SO 上也没有锚链接支持)。

Fix: 2. copy everything from my current directory into the nodejs 14 image.修复: 2. 将我当前目录中的所有内容复制到 nodejs 14 映像中。

    user: "node"
    working_dir: /home/node/app
    volumes:
      - ./:/home/node/app

If you look up user or working_dir on docs.docker.com , you are out of luck without prior knowledge with docker .如果您在docs.docker.com上查找userworking_dir ,那么在没有docker的先验知识的情况下,您将不走运。 It only states that:它只指出:

Each of these is a single value, analogous to its docker run counterpart.其中每一个都是单个值,类似于其 docker 运行对应项。 Note that mac_address is a legacy option.请注意, mac_address 是一个旧选项。

The goal here is to copy the current directory (where docker-compose.yml is located) to the tests service which pulls the node:14 image.这里的目标是将当前目录( docker-compose.yml所在的位置)复制到提取node:14图像的tests服务。 We need to create a directory in our container where our current directory on our machine will be copied to.我们需要在我们的容器中创建一个目录,我们机器上的当前目录将被复制到该目录中。 Later on, we want to execute some commands in that directory and we do not want to run stuff as sudo , so the natural placement is in our user home directory ( ~/ ).稍后,我们想在该目录中执行一些命令,我们不想以sudo运行东西,所以自然放置在我们的用户主目录( ~/ )中。

We need:我们需要:

  1. A user in our nodejs container.我们的nodejs容器中的用户。
  2. Create a directory in the user home directory in our nodejs container.在我们的nodejs容器的用户主目录中创建一个目录。
  3. Map our current directory on our machine to the new directory in our nodejs container. Map 我们机器上的当前目录到我们的nodejs容器中的新目录。

After reading How to use this image that the nodejs developers wrote, we can see in the example that there is a node user in the image.在阅读了nodejs开发者写的How to use this image之后,我们可以在示例中看到图像中有一个node用户。 The example also shows which Docker Compose configurations we need.该示例还显示了我们需要哪些 Docker Compose 配置。

    user: "node"

Presumably use the node user defined in image: "node:14" .大概使用image: "node:14"中定义的节点用户。

    working_dir: /home/node/app

Create an app directory inside the node user's home directory.node用户的目录中创建一个app目录。

    volumes:
      - ./:/home/node/app

Map our current directory on our machine to the /home/node/app directory inside the tests container (which uses image: "node:14" ). Map 我们机器上的当前目录到tests容器内的/home/node/app目录(使用image: "node:14" )。

Fix: 3. I want the nodejs image to depend on the RethinkDB image.修复: 3. 我希望 nodejs 图像依赖于 RethinkDB 图像。

    container_name: nodejs

Turns out that defining container_name is purely cosmetic.事实证明,定义container_name纯粹是装饰性的。 It does not help you to link network or start one container before the other.它不能帮助您链接网络或先启动一个容器。 It is just a name.这只是一个名字。 While your containers are running you can use docker ps to see them or docker ps -a to see all containers, even shut downed ones.当您的容器正在运行时,您可以使用docker ps查看它们或使用docker ps -a查看所有容器,甚至是关闭的容器。 In the NAMES column the container_name is written.NAMES列中写入了container_name If you do not define container_name , then they will be called your directory name and the service name, post-fixed with a incremental number.如果您没有定义container_name ,那么它们将被称为您的目录名称和服务名称,后缀为增量编号。

docker ps with container_name while running: 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 without container_name while running: docker ps运行时没有container_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 is the magic one! depends_on是神奇的! It tells Docker Compose that the rethinkdb container must be它告诉 Docker Compose rethinkdb容器必须是online在线的started before this container.这个容器之前开始。

This in a rare case of the Docker Compose documentation ( depends_on ) actually being good.这在Docker Compose 文档( depends_on的极少数情况下实际上很好。

Unfortunately depends_on does not guarantee that the depending image is online, as you would expect, but the documentation is also very clear in this case and offer another solution.不幸的是, depends_on不能保证依赖图像在线,如您所料,但在这种情况下,文档也非常清楚,并提供了另一种解决方案。 In our case, it does not matter much since the rethinkdb container starts fast enough ( npm ci in nodejs will take way longer than the startup time of rethinkdb ).在我们的例子中,这并不重要,因为rethinkdb容器启动得足够快(nodejs 中的nodejs npm ci将花费比rethinkdb的启动时间更长的时间)。

Fix: 4. run 2 commands in the nodejs 14 image;修复:4.在nodejs 14镜像中运行2条命令; npm ci and npm test. npm ci 和 npm 测试。

    command: "npm ci && npm test"

Now we can run some commands inside our docker container,现在我们可以在 docker 容器中运行一些命令, as if we where running them on our machine in our project directory.就好像我们在我们的项目目录中的机器上运行它们一样。 Of course not.当然不是。 The above will only execute npm ci .以上只会执行npm ci See the SO answer Using Docker-Compose, how to execute multiple commands .请参阅使用 Docker-Compose 的 SO 答案,如何执行多个命令 Docker uses an obscure difficult to fathom variant of shell script that can execute one, and only one command, with parameters. Docker 使用了 shell 脚本的一种晦涩难懂的变体,该脚本可以执行一个且只有一个带有参数的命令。 The documentation says it is similar to the docker CMD key but neither sites explain why some POSIX shell commands work and others don't but we assume that it made life easier for Docker developers:) The documentation says it is similar to the docker CMD key but neither sites explain why some POSIX shell commands work and others don't but we assume that it made life easier for Docker developers:)

The correct way to execute multiple commands, is:执行多个命令的正确方法是:

    command: bash -c "npm ci && npm test"

Please see "Using Docker-Compose, how to execute multiple commands" .请参阅“使用 Docker-Compose,如何执行多个命令”

npm ci installs all npm packages from package-lock.json and npm test runs our "test" script in package.json . npm ci installs all npm packages from package-lock.json and npm test runs our "test" script in package.json .

You might think that you can write multiple commands in an YAML array but doing so will, in this case apparently, tell node to require them as modules inside the container and you will get errors like:您可能认为您可以在 YAML 数组中编写多个命令,但在这种情况下,这样做显然会告诉节点require它们作为容器内的模块,您将收到如下错误:

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"

The above will not work!以上是不行的!

Instead use the usual && to execute a series of successful commands.而是使用通常的&&来执行一系列成功的命令。 Again, Using Docker-Compose, how to execute multiple commands is the correct documentation.同样,使用 Docker-Compose,如何执行多个命令是正确的文档。

Actually, forget the above and use entrypoint to point to a bash file where you write all of your commands.实际上,忘记上面的内容并使用entrypoint点指向您编写所有命令的 bash 文件。

Fix: 5. see the stdout from the tests.修复: 5. 从测试中查看标准输出。

DO NOT USE docker-compose up -d !不要使用docker-compose up -d

You do not have to do anything here.您不必在这里做任何事情。 Even though every Docker Compose tutorial will tell you to run in detached mode.即使每个 Docker Compose 教程都会告诉您以分离模式运行。 You will not see stdout or stderr.您将看不到 stdout 或 stderr。 Just loose the -d .只需松开-d

docker-compose up is the way to go! docker-compose up是要走的路!

If you really have to run in detached mode, you can see the output via docker logs [container id] and get the container id via docker ps or docker ps -a . If you really have to run in detached mode, you can see the output via docker logs [container id] and get the container id via docker ps or docker ps -a . The latter is used if your containers are not currently running.如果您的容器当前未运行,则使用后者。

docker-compose.yml keys that look like they are needed看起来像是需要的docker-compose.yml密钥

Turns out that Docker comes with a lot of sane defaults which you should not mess with unless you really have to.事实证明,Docker 带有很多正常的默认值,除非你真的必须这样做,否则你不应该乱用它们。

    ports:
      - "28015:28015"
      - "8080:8080"

You do not need to expose ports in a docker-compose.yml unless you need to expose the ports to your local machine or outside network, even though every example out there does it.您不需要在docker-compose.yml中公开端口,除非您需要将端口公开给本地计算机或外部网络,即使那里的每个示例都这样做。 For example, if you need access to localhost:8080 (in RethinkDB that is the dashboard), then you have to add:例如,如果您需要访问localhost:8080 (在 RethinkDB 中,即仪表板),那么您必须添加:

ports:
  - "8080:8080"

Your other services/containers will have access to both port 28015 and 8080 , using the service name as hostname, without you have to specify anything in your docker-compose.yml .您的其他服务/容器将可以访问端口280158080 ,使用服务名称作为主机名,而无需在docker-compose.yml中指定任何内容。 Eg in this case rethinkdb:28015 .例如在这种情况下rethinkdb:28015 See below for more information.请参阅下面的详细信息。

You do not need to expose ports in a `docker-compose.yml` even though every example out there does it.您不需要在 `docker-compose.yml` 中公开端口,即使那里的每个示例都这样做。 Chances are that the image you use, already exposes the default ports used by the containerized software you need.您使用的映像可能已经公开了您需要的容器化软件使用的默认端口。 The above example is the default ports that RethinkDB uses and they are exposed without you having to write them.上面的示例是 RethinkDB 使用的默认端口,无需您编写它们即可公开。
    links:
      - rethinkdb

links seems like a way to connect two distinct containers but it turns out that all containers share network, so you do not have to. links似乎是一种连接两个不同容器的方法,但事实证明所有容器共享网络,所以你不必这样做。 The official documentation comes with a big red WARNING, which suggest that you use user-defined networks . 官方文档附带一个大大的红色WARNING,建议你使用用户自定义网络 Which in turn says that:反过来说:

By default Compose sets up a single network for your app.默认情况下,Compose 会为您的应用程序设置一个网络 Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.服务的每个容器都加入默认网络,并且可以被该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现。

That's a convoluted way of saying that inside your Docker Compose containers, you can connect to ports and IP address just as you would, had it been on your local machine.这是一种令人费解的说法,在 Docker Compose 容器中,您可以像在本地计算机上一样连接到端口和 IP 地址。

So if container A's image exposes 172.18.0.2:28015 then you can connect from container B using that exact address.因此,如果容器 A 的图像暴露172.18.0.2:28015 ,那么您可以使用该确切地址从容器 B 连接。 Ei IP: 172.18.0.2 and port: 28015 . Ei IP: 172.18.0.2和端口: 28015 Scratch that!刮那个! The exposed IP addresses are not stable.暴露的 IP 地址不稳定 Docker will change them, for various (unknown) reasons.由于各种(未知)原因,Docker 将更改它们。

Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.服务的每个容器都加入默认网络,并且可以被该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现。

Means that your service name is used as hostname, in the same way you would define it in your /etc/hosts file.意味着您的服务名称用作主机名,就像您在/etc/hosts文件中定义它一样。 Or similar to how DNS links stackoverflow.com to 151.101.193.69.或类似于 DNS 如何将 stackoverflow.com 链接到 151.101.193.69。

So if container rethinkdb exposes port 28015 then it will be accessible from the nodejs container via rethinkdb:28015 .因此,如果容器rethinkdb暴露了端口28015 ,那么它将可以从nodejs容器通过rethinkdb:28015访问。

BEWARE that the documentation says:注意文档中说:

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres
    ports:
      - "8001:5432"

Each container can now look up the hostname web or db and get back the appropriate container's IP address.每个容器现在可以查找主机名webdb并取回相应容器的 IP 地址。 For example, web 's application code could connect to the URL postgres://db:5432 and start using the Postgres database.例如, web的应用程序代码可以连接到 URL postgres://db:5432并开始使用 Postgres 数据库。

In the example for Networking in Compose postgres is the image , db is the service name and 5432 is the port number.Compose 中的网络示例中, postgresimagedb是服务名称, 5432是端口号。 This is does not work in my experience.根据我的经验,这是行不通的。 You need to use the service name and never the image name.您需要使用服务名称,而不是image名称。 So the correct way to connect from web to db is to use the URL db:5232 .因此,从web连接到db的正确方法是使用 URL db:5232 @jonrsharpe points out that the protocol ( postgres:// ) just happens to match the image name. @jonrsharpe 指出协议( postgres:// )恰好与图像名称匹配。

The following is a correction of my previous understanding of the example.以下是我之前对例子理解的修正

In the example for Networking in Compose postgres is the protocol (similar to https ), db is the service name and 5432 is the port number.Compose 中的 Networking 示例中, postgres是协议(类似于https ), db是服务名称, 5432是端口号。 You need to use the service name, to get the correct IP address.您需要使用服务名称来获取正确的 IP 地址。 So the correct way to connect from web to db is to use the URL [protocol]://db:5232 .所以从web连接到db的正确方法是使用 URL [protocol]://db:5232 Where protocol can be http , https , progres , etc.其中protocol可以是httphttpsprogres等。

Since all containers are within the same network, you do not need the ports key unless you need to expose a service to your local machine (or outside network).由于所有容器都在同一个网络中,因此您不需要ports密钥,除非您需要向本地计算机(或外部网络)公开服务。


    volumes:
      - "./data: /data"

Every RethinkDB Dockerfile has this but this is only needed if you want to copy files from your local machine into the container.每个 RethinkDB Dockerfile都有此功能,但仅当您要将文件从本地计算机复制到容器中时才需要此功能。 In this case we do not want to preload the database with anything, so we do not have any files to seed the database with, hence the volumes key is not needed.在这种情况下,我们不想用任何东西预加载数据库,所以我们没有任何文件来为数据库播种,因此不需要volumes键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将Dockerfile转换为docker compose图像? - How to convert a Dockerfile to a docker compose image? 如何设置 nginx 与 docker 组合 - How to setup nginx with docker compose 如何从 Dockerfile 或 docker-compose 运行 knex 迁移 - How to run knex migrations from Dockerfile or docker-compose 如何在不使用 Dockerfile 的情况下仅使用 Docker-compose.yml 文件启动 Node.js 应用程序的容器 - How to start the container for the Node.js application using just Docker-compose.yml file without using the Dockerfile 如何使用 docker-compose 设置节点 - how to setup node with docker-compose 使用 SSH 代理与 Docker 组合和 Dockerfile - Using SSH agent with Docker Compose and Dockerfile 如何使用 Docker Compose 设置 Node.js 开发环境 - How setup a Node.js development environment using Docker Compose 如何使用 nodejs 在 docker-compose 上的 mongoDB 上设置身份验证? - How to setup authentication on mongoDB on docker-compose with nodejs? 如何使用 docker-compose 文件中的命名图像和指定图像的 Dockerfile 启动命名 NodeJS 容器? - How to start a named NodeJS container with a named image from a docker-compose file and and a Dockerfile specifying the image? 使Dockerfile VOLUME的行为类似于docker-compose卷 - Make Dockerfile VOLUME behave like docker-compose volumes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM