Home > OS >  econnrefused rabbitMQ between docker containers
econnrefused rabbitMQ between docker containers

Time:09-04

I am trying to set up a simple docker-compose file which includes a rabbitmq container and a simple express server which connects to rabbitmq. I'm getting the following error when trying to connect to rabbitmq from my express application:

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
}

I checked the IP-adress of the docker network manually to verify that 172.19.0.2 is indeed the rabbitmq process, which it is.

Here is my 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

and the express app and its docker file:

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:[email protected]: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:[email protected]:5672

EXPOSE 3000

CMD ["npm", "start"]

This is my first time using docker compose and all the fixes I found on here seem to suggest I did everything correctly. What am I missing?

CodePudding user response:

TL;DR
The depends_on guarantes the order in which the services will start up, but that doesn't guarante anything for the processes they inititate.

In these cases, you should expand the depends_on statement in order to take into account the health status of the process of interest


Firstly, you should avoid making the communication of cointainers depend on their IP address but instead rely on their service names, since you are using docker compose.

Meaning, instead of amqp://admin:[email protected]:5672

You should use amqp://admin:pass@rabbitmq:5672


Moving on to the core issue, your producerexpress relies on to rabbitmq in order to function.

As a result, you added the depends_on statement to producerexpress to resolve this. But this is not enough, quotting from 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.

As a result, you need to add a health check in order to guarantee that the rabbitmq process has started successfully, not just the container.

In order to achieve that you should alter your compose file

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

In order to make the healthcheck, we need the curl package in the rabbitmq image, so add the following Dockerfile

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

Finally, to make this change compatible create the following directory structure

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