Connecting to RabbitMQ container with docker-compose
Asked Answered
I

5

33

I want to run RabbitMQ in one container, and a worker process in another. The worker process needs to access RabbitMQ.

I'd like these to be managed through docker-compose.

This is my docker-compose.yml file so far:

version: "3"

services:

  rabbitmq:
    image: rabbitmq
    command: rabbitmq-server
    expose:
      - "5672"
      - "15672"

  worker:
    build: ./worker
    depends_on:
      - rabbitmq
    # Allow access to docker daemon
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

So I've exposed the RabbitMQ ports. The worker process accesses RabbitMQ using the following URL:

amqp://guest:guest@rabbitmq:5672/

Which is what they use in the official tutorial, but localhost has been swapped for rabbitmq, since the the containers should be discoverable with a hostname identical to the container name:

By default Compose sets up a single network for your app. 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.

Whenever I run this, I get an connection refused error:

Recreating ci_rabbitmq_1 ... done                                                                                                                                                    
Recreating ci_worker_1   ... done                                                                                                                                                    
Attaching to ci_rabbitmq_1, ci_worker_1                                                                                                                                              
worker_1    | dial tcp 127.0.0.1:5672: connect: connection refused                                                                                                                   
ci_worker_1 exited with code 1        

I find this interesting because it's using the IP 127.0.0.1 which (I think) is localhost, even though I specified rabbitmq as the hostname. I'm not an expert on docker networking, so maybe this is desired.

I'm happy to supply more information if needed!


Edit

There is an almost identical question here. I think I need to wait until rabbitmq is up and running before starting worker. I tried doing this with a healthcheck:

version: "2.1"

services:

  rabbitmq:
    image: rabbitmq
    command: rabbitmq-server
    expose:
      - "5672"
      - "15672"
    healthcheck:
      test: [ "CMD", "nc", "-z", "localhost", "5672" ]
      interval: 10s
      timeout: 10s
      retries: 5

  worker:
    build: .
    depends_on:
      rabbitmq:
        condition: service_healthy

(Note the different version). This doesn't work, however - it will always fail as not-healthy.

Instructor answered 28/10, 2018 at 12:19 Comment(1)
why you need to expose the ports on the host?Merrell
P
1

The answer here works for me and is more straightforward:

https://devops.stackexchange.com/questions/12092/docker-compose-healthcheck-for-rabbitmq?newreg=614274132fbc4f92a92ba80f6d758a76

You could use the command rabbitmq-diagnostics -q ping in case you just need a basic check.

healthcheck:
  test: rabbitmq-diagnostics -q ping
  interval: 30s
  timeout: 30s
  retries: 3
Prepossessing answered 6/5, 2023 at 9:14 Comment(0)
I
29

Aha! I fixed it. @Ijaz was totally correct - the RabbitMQ service takes a while to start, and my worker tries to connect before it's running.

I tried using a delay, but this failed when the RabbitMQ took longer than usual.

This is also indicative of a larger architectural problem - what happens if the queuing service (RabbitMQ in my case) goes offline during production? Right now, my entire site fails. There needs to be some built-in redundancy and polling.

As described this this related answer, we can use healthchecks in docker-compose 3+:

version: "3"

services:

  rabbitmq:
    image: rabbitmq
    command: rabbitmq-server
    expose:
      - 5672
      - 15672
    healthcheck:
      test: [ "CMD", "nc", "-z", "localhost", "5672" ]
      interval: 5s
      timeout: 15s
      retries: 1

  worker:
    image: worker
    restart: on-failure
    depends_on:
      - rabbitmq

Now, the worker container will restart a few times while the rabbitmq container stays unhealthy. rabbitmq immediately becomes healthy when nc -z localhost 5672 succeeds - i.e. when the queuing is live!

Instructor answered 29/10, 2018 at 2:17 Comment(0)
C
15

Here is the correct working example :

    version: "3.8"

    services:

    rabbitmq:
        image: rabbitmq:3.7.28-management
        #container_name: rabbitmq
        volumes:
            - ./etc/rabbitmq/conf:/etc/rabbitmq/
            - ./etc/rabbitmq/data/:/var/lib/rabbitmq/
            - ./etc/rabbitmq/logs/:/var/log/rabbitmq/
        environment:
            RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE:-secret_cookie}
            RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER:-admin}
            RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS:-admin}
        ports:
            - 5672:5672    #amqp
            - 15672:15672  #http
            - 15692:15692  #prometheus
        healthcheck:
        test: [ "CMD", "rabbitmqctl", "status"]
        interval: 5s
        timeout: 20s
        retries: 5

    mysql:
        image: mysql
        restart: always
        volumes:
        - ./etc/mysql/data:/var/lib/mysql
        - ./etc/mysql/scripts:/docker-entrypoint-initdb.d
        environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: mysqldb
        MYSQL_USER: ${MYSQL_DEFAULT_USER:-testuser}
        MYSQL_PASSWORD: ${MYSQL_DEFAULT_PASSWORD:-testuser}
        ports:
        - "3306:3306"
        healthcheck:
        test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
        timeout: 20s
        retries: 10

    trigger-batch-process-job:
        build: .
        environment:
        - RMQ_USER=${RABBITMQ_DEFAULT_USER:-admin}
        - RMQ_PASS=${RABBITMQ_DEFAULT_PASS:-admin}
        - RMQ_HOST=${RABBITMQ_DEFAULT_HOST:-rabbitmq}
        - RMQ_PORT=${RABBITMQ_DEFAULT_PORT:-5672}
        - DB_USER=${MYSQL_DEFAULT_USER:-testuser}
        - DB_PASS=${MYSQL_DEFAULT_PASSWORD:-testuser}
        - DB_SERVER=mysql
        - DB_NAME=mysqldb
        - DB_PORT=3306
        depends_on:
        mysql:
            condition: service_healthy
        rabbitmq:
            condition: service_healthy
Confidential answered 29/5, 2021 at 15:53 Comment(4)
No, it's wrong. Compose 3+ does not support condition: service_healthy under depends onUbangi
Test this out: github.com/mnadeem/lob-proj-job-trigger-batch-process/blob/main/…Confidential
Your example did not run on my machine after running docker-compose up -d, but i managed to figure out why condition: service_healthy was not working for me in the first place thanks to you. So you are right. Thanks!Ubangi
this is actually the correct answerCalesta
M
3

Maybe you dont need to expose/map the ports on the host if you are just accessing the service from another container.

From the documentation:

Expose Expose ports without publishing them to the host machine - they’ll only be accessible to linked services. Only the internal port can be specified.

expose:
 - "3000"
 - "8000"

So it should be like this:

version: "3"

services:

  rabbitmq:
    image: rabbitmq
    command: rabbitmq-server
    expose:
      - "5672"
      - "15672"

  worker:
    build: ./worker
    depends_on:
      - rabbitmq
    # Allow access to docker daemon
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

also make sure to connect to rabitmq only when its ready to server on port.

Merrell answered 28/10, 2018 at 13:16 Comment(2)
You're definitely right - I don't need to expose the ports on the host, but only to other containers. Unfortunately this doesn't fix the connection problem, but I still learned something new :)Instructor
@Instructor the connection problem maybe related to the fact the the rabitmq service doesnt start fast enough for the worker to connect , put some delay in worker , you can also test using some dummy container and see if you can connect from that insteadMerrell
O
2

Most clean way for docker compose v3.8

version: "3.8"

services:

  worker:
    build: ./worker
    rabbitmq:
        condition: service_healthy

  rabbitmq:
    image: library/rabbitmq
    ports:
    - 5671:5671
    - 5672:5672
    healthcheck:
      test: [ "CMD", "nc", "-z", "localhost", "5672" ]
      interval: 5s
      timeout: 10s
      retries: 3
Oneself answered 29/6, 2021 at 6:57 Comment(2)
Do you not need the "rabbitmq" line to be nested under another field? I'm getting an error with this solution that says the keyword is not definedItself
@HarrisonCramer you are right. there is a "services" keyword missing. thanks, answer modifiedOneself
P
1

The answer here works for me and is more straightforward:

https://devops.stackexchange.com/questions/12092/docker-compose-healthcheck-for-rabbitmq?newreg=614274132fbc4f92a92ba80f6d758a76

You could use the command rabbitmq-diagnostics -q ping in case you just need a basic check.

healthcheck:
  test: rabbitmq-diagnostics -q ping
  interval: 30s
  timeout: 30s
  retries: 3
Prepossessing answered 6/5, 2023 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.