node.js - docker 容器之间的 econnrefusedrabbitMQ

标签 node.js docker docker-compose rabbitmq dockerfile

我正在尝试设置一个简单的docker-compose文件,其中包括一个rabbitmq容器和一个连接到rabbitmq的简单express服务器。当我尝试从我的express应用程序连接到rabbitmq时,出现以下错误:

Error: connect ECONNREFUSED 172.19.0.2:5672
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1247:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '172.19.0.2',
  port: 5672
}

我手动检查了docker网络的IP地址,以验证172.19.0.2确实是rabbitmq进程,确实如此。

这是我的 docker-compose:

version: '3'
services:
  rabbitmq:
    image: rabbitmq:3-management-alpine
    container_name: 'rabbitmq'
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=pass
    ports:
      - 5672:5672
      - 15672:15672
  producerexpress:
    build: ./service1
    container_name: producerexpress
    ports:
      - 3000:3000
    environment:
      - PORT=3000
    depends_on:
      - rabbitmq

以及 Express 应用程序及其 docker 文件:

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const amqp = require('amqplib');

const amqpUrl = process.env.AMQP_URL || 'amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c5b5a4b6b685f4f2f7ebf4fcebf5ebf7" rel="noreferrer noopener nofollow">[email protected]</a>:5672';

let channel;
let connection;

connect();

async function connect(){
  try{
    connection = await amqp.connect(amqpUrl);
    channel = await connection.createChannel();

    await channel.assertQueue('chatExchange', {durable: false});
  } catch (err) {
    console.log(err);
  }
}

function sendRabbitMessage(msg) {
  channel.sendToQueue('chatExchange', Buffer.from(msg));
}


app.get('/', (req, res) => {
  let msg = 'Triggered by get request';
  sendRabbitMessage(msg);
  res.send('Sent rabbitmq message!');
});


app.listen(port, () => {
    console.log(`Server started on port ${port}`);
} );
FROM node:16

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

ENV PORT=3000

ENV AMQP_URL=amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b4c4d5c7c7f48583869a858d9a849a86" rel="noreferrer noopener nofollow">[email protected]</a>:5672

EXPOSE 3000

CMD ["npm", "start"]

这是我第一次使用 docker compose,我在这里找到的所有修复似乎都表明我做的一切都是正确的。我错过了什么?

最佳答案

TL;DR
depends_on保证服务启动的顺序,但这并不能保证它们启动的进程的任何内容。

在这些情况下,您应该展开 depends_on按顺序声明to take into account the health status感兴趣的过程


首先,您应该避免使 cointainers 的通信依赖于它们的 IP 地址,而是依赖于它们的服务名称,因为您使用的是 docker compose。

含义,而不是amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a5d5c4d6d6e59492978b949c8b958b97" rel="noreferrer noopener nofollow">[email protected]</a>:5672

您应该使用amqp://admin:pass@rabbitmq:5672


继续讨论核心问题,您的producerexpress依赖rabbitmq以便发挥作用。

因此,您添加了 depends_onproducerexpress的声明来解决这个问题。但这还不够,引用https://docs.docker.com/compose/startup-order/

You can control the order of service startup and shutdown with the depends_on option. Compose always starts and stops containers in dependency order, .... However, for startup Compose does not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running.

因此,您需要添加 health check为了保证rabbitmq process has started成功,not just the container .

为了实现这一目标,您应该更改您的 compose文件

version: '3'
services:
  rabbitmq:
    build: ./rabbitmq
    container_name: 'rabbitmq'
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=pass
    ports:
      - 5672:5672
      - 15672:15672
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:15672"]
      interval: 30s
      timeout: 10s
      retries: 5

  producerexpress:
    build: ./service1
    restart: on-failure
    container_name: producerexpress
    ports:
      - 3000:3000
    environment:
      - PORT=3000
    depends_on:
      rabbitmq:
        condition: service_healthy

为了进行健康检查,我们需要 curl打包到rabbitmq镜像中,所以添加以下Dockerfile

FROM rabbitmq:3-management-alpine
RUN apk update
RUN apk add curl
EXPOSE 5672 15672

最后,为了使此更改兼容,创建以下目录结构

./docker-compose.yml
./rabbitmq/
 --- Dockerfile
./service1/
 --- Dockerfile

关于node.js - docker 容器之间的 econnrefusedrabbitMQ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73588664/

相关文章:

docker - 从正在运行的容器中获取 docker-compose.yml 文件位置?

node.js - Node.js 集群上的 SocketIO

javascript - 与 Webpack 捆绑后的模块功能无法识别

javascript - 如何更新 mongoose 中查询前或查询后 Hook 的文档?

azure - 在Azure子域上通过https访问docker容器

docker - docker-compose如何在kafka容器上安装kafkacat

django - PermissionError:[Errno 13]尝试使用docker-compose创建项目时,权限被拒绝: '/app/manage.py'

docker - 如果 DockerHub 上存在新版本的镜像,则自动更新 docker 镜像

docker - Windows10上的Docker卷权限 “a STORAGE ENGINE failed.”

javascript - 将 git 存储库重新安装为 React 包