Home > database >  Unable to reach RabbitMQ broker from Phoenix Elixir App to RabbitMQ Container Docker
Unable to reach RabbitMQ broker from Phoenix Elixir App to RabbitMQ Container Docker

Time:02-25

I built a service orchestration with docker-compose that connects an Elixir app that uses BroadayRabbitMQ to another container that uses RabbitMQ-3-Management Docker image. The problem is, even though these services are on the same network (as in I built a docker network to support them) & set the env variables. I receive "[error] Cannot connect to a RabbitMQ broker: :unknown_host" How do I get RabbitMQ to connect to my Elixir release container?

docker-compose.yml

version: "3.8"

services:
  poll_workers_app:
    container_name: coder_workers_ex
    build:
      context: .
      dockerfile: CoderWorkersProd.Dockerfile
    volumes:
      - .:/app
    depends_on:
      - db
      - rabbitmq
    env_file:
      - config/docker.env
    ports:
      - '4000:4000'
    tty: true
    networks:
      - rabbitmq_network
  db:
    image: 'postgres:12'
    container_name: coder_workers_db
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_HOST_AUTH_METHOD: trust
    restart: always
    volumes:
      - 'pgdata:/var/lib/postgresql/data'
    ports:
      - "5432:5432"
    networks:
      - rabbitmq_network
  rabbitmq:
    hostname: rabbitmq
    image: rabbitmq:3-management
    container_name: coder_workers_rabbitmq
    env_file:
      - config/docker.env
    ports:
      - '5672:5672'
      - '15672:15672'
      - '15692:15692'
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    networks:
      - rabbitmq_network
volumes:
  pgdata:
  rabbitmq-data: {}
networks:
  rabbitmq_network:
    external:
      name: rabbitmq_network

rabbit_report_pipeline.ex

defmodule CoderWorkers.Pipelines.RabbitReportPipeline do
  use Broadway
  require Logger

  alias CoderWorkers.Responses.RabbitResponse
  alias CoderWorkers.Cache.Responses

  @producer BroadwayRabbitMQ.Producer

  @queue "coder.worker.rabbit_report.status"

  @connection [
    username: System.get_env("RABBITMQ_USERNAME"),
    password: System.get_env("RABBITMQ_PASSWORD"),
    host: System.get_env("RABBITMQ_HOST")
  ]

.env

RABBITMQ_DEFAULT_USER=guest
RABBITMQ_DEFAULT_PASS=guest
RABBITMQ_DEFAULT_VHOST=rabbitmq
RABBITMQ_USERNAME=guest
RABBITMQ_PASSWORD=guest
RABBITMQ_HOST=rabbitmq

error

coder_workers_ex        | 20:03:25.676 [error] Cannot connect to RabbitMQ broker: :unknown_host
coder_workers_ex        | 20:03:41.300 [error] Cannot connect to RabbitMQ broker: :unknown_host
coder_workers_ex        | 20:04:10.856 [error] Cannot connect to RabbitMQ broker: :unknown_host
coder_workers_ex        | 20:04:39.142 [error] Cannot connect to RabbitMQ broker: :unknown_host

CodePudding user response:

I can not see how you connect from the coder_workers_ex to the rabbit_mq. So just in case:

You can connect inside the network by using the container name as the host, not the host name. That is only used inside the container, as you can read also here.

For instance: attaching a terminal session to coder_workers_ex container and executing: ping rabbitmq will not work, but ping coder_workers_rabbitmq will.

If this does not help, then maybe show the code that connects the containers so we can try to help you better.

EDIT: as pointed out in the comments by David Maze: Connecting can be done using either: comtainer_name, hostname, or service-block-name. So while this answer gives you a correct working solution, it is not the correct answer, because this was not your problem in the first place.

CodePudding user response:

Looks like your docker setup is correct, it won't work because you have to use runtime configuration (read about config/runtime.exs).

When you are using a attribute, in your case @connection, it will always get evaluated at compile-time.

To avoid this, there is a rule of thumb:

If your configuration is not a compile-time configuration, always use a function to fetch the configuration.

Example:

def connection() do
 [
    username: System.get_env("RABBITMQ_USERNAME"),
    password: System.get_env("RABBITMQ_PASSWORD"),
    host: System.get_env("RABBITMQ_HOST")
 ]
end

This should work as-is, however it is recommended to store all your configuration inside of config files. So all you have to do is create your runtime.exs file:

import Config
if config_env() == :prod do
  config :my_app, :rabbitmq_config,
    username: System.get_env("RABBITMQ_USERNAME"),
    password: System.get_env("RABBITMQ_PASSWORD"),
    host: System.get_env("RABBITMQ_HOST")
end

Then, you can get the configuration using Application.get_env/3 or Application.fetch_env/2, remember to fetch configurations using functions.

To make this easier, I would recommend using credo, it enforces you to use Applicaiton.compile_env/3 in situations where you are trying to call runtime configurations at compile-time.

  • Related