acroynon
acroynon

Reputation: 60

Docker Compose Linked Microservices Not Discoverable

When using docker compose I cannot get two services to communicate with one another. The idea is getting a Node.JS service to talk to a Java/Spring service.

I have tried using 'links', putting them into the same 'network' and then sending requests to http://service_name:port and it returns ERR_NAME_NOT_RESOLVED.

Within the Node.JS service I have tried using Axios and the http module, neither work (ERR_NAME_NOT_RESOLVED). I have also tried 'localhost', which doesn't work either (ERR_CONNECTION_REFUSED). The Spring service is literally just an exposed REST endpoint (that I know works, as I can access it directly).

I have also tried passing a reference to the service via environment variables e.g (inside docker-compose.yml).

environment:
  - SERVICE_HOST=serviceB

The env variable inside the Node.JS project is undefined when calling below

process.env.SERVICE_HOST

I am using Windows with Docker toolbox, but have also tried the same project in a Ubuntu VM.

  serviceA:
    build: ./serviceA/
    ports: 
      - "8080:8080"
    networks:
      - my_network
  serviceB:
    build: ./serviceB/
    ports:
      - "9003:9003"
    networks:
      - my_network

networks:
  my_network:
    driver: bridge
axios.get("http://serviceB:9003/test")
  .then(function(res){
    console.log(res);
  })

I expected the console.log statement within the Node.JS service to respond with the results from ServiceB's rest call, instead of the error messages.

I am new to using docker-compose, so am expecting I am just missing something obvious here, but I haven't been able to find anything that solves my problem online, nor in similar questions on SO.

EDIT Added entire yaml file and errors for better understanding.

version: '3'
services:

  # Consul
  consul:
    container_name: consul
    image: consul:latest
    ports:
      - "8500:8500"
      - "8300:8300"
    hostname: consul
    networks:
      - front_end
      - back_end

  # Actor Service   
  actor_service:
    build: ./actor_service/
    ports: 
      - "9001:8080"
    depends_on:
      - actor_service_db
      - consul
    networks:
      - back_end

  actor_service_db:
    image: postgres:9.4.5
    depends_on:
      - consul
    networks:
      - back_end
    environment:
      - POSTGRES_DB=actor
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - CONSUL_HTTP_ADDR=https://consul:8500

  # Movie Service   
  movie_service:
    build: ./movie_service/
    ports: 
      - "9002:8080"
    depends_on:
      - movie_service_db
      - consul
    networks:
      - back_end

  movie_service_db:
    image: postgres:9.4.5
    depends_on:
      - consul
    networks:
      - front_end
    environment:
      - POSTGRES_DB=movie
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - CONSUL_HTTP_ADDR=https://consul:8500

  # Movie Aggregate Service
  movie_aggregate_service:
    container_name: movie_aggregate_service
    build: 
      context: ./movie_aggregate_service/
    ports: 
      - "9003:8080"
    depends_on:
      - consul
      - movie_service
      - actor_service
    networks:
      - front_end
      - back_end
    hostname: movie_aggregate_service

  # Frontend
  front_end:
    build: ./front_end/
    ports: 
      - "8080:8080"
    networks:
      - front_end
    environment:
      - "CONSUL_HOST=consul"
    links:
      - consul
      - movie_aggregate_service

networks:
  front_end:
    driver: bridge
  back_end:
    driver: bridge

Browser Console errors and output

Upvotes: 1

Views: 290

Answers (2)

Allan Chua
Allan Chua

Reputation: 10195

You might want to specify a hostname on each service to ease accessing of endpoints living on them and link them explicitly. Below is a sample Docker-compose file.

version: "3"

services:
  ocelot.products:
    image: pogs/ocelot-products
    container_name: ocelot-products
    hostname: ocelot.products
    build:
      context: ./products
    ports:
      - "52790:3000"
    environment:
      "PUBLIC_PORT": "52790"
  ocelot.users:
    image: pogs/ocelot-users
    container_name: ocelot-users
    hostname: ocelot.users
    build:
      context: ./users
    ports:
      - "52791:3000"
    environment:
      "PUBLIC_PORT": "52791"
  ocelot.transactions:
    image: pogs/ocelot-transactions
    container_name: ocelot-transactions
    hostname: ocelot.transactions
    build:
      context: ./transactions
    ports:
      - "52792:3000"
    environment:
      "PUBLIC_PORT": "52792"
  ocelot.gateway:
    image: pogs/ocelot-gateway
    container_name: ocelot-gateway
    build:
      context: ./gateway/EShop
    ports:
      - "52793:80"
    links:
      - ocelot.products
      - ocelot.users
      - ocelot.transactions
    depends_on:
      - ocelot.products
      - ocelot.users
      - ocelot.transactions

Whole repo available here

Upvotes: 1

Funky Penguin
Funky Penguin

Reputation: 189

Your compose looks good - service discovery relies on DNS within the containers, I’d try execing(exec) into serviceA, and checking that nothing funky happened to /etc/resolv.conf.. you should be able to ping serviceB from the exec shell.

Upvotes: 0

Related Questions