Search code examples
dockernetwork-programmingdocker-composecontainersmicroservices

How to allow microservices to communicate with each other?


So I'm running a nodejs backend microservice based application. And I'm trying to do something like this:

services:
      comments:
        build: ./comments
        ports:
          - "4201:4201"
      posts:
        build: ./posts
        ports: 
          - "4200:4200"
        links:
          - comments
        depends_on:
          - comments

I'm hosting this on my local host address, I have my containers kept together in the environment, so how to properly get the microservice API IP from another service in docker-compose environment?

This is where I call comments inside of postsmicroservice

let comments  = await axios.get("http://localhost:4201/comments");

This is the error when I do docker-compose run and try to get the route with testing tool called Postman: enter image description here

At the end of the error line: It says isAxiosError: true (this might be helpful)


Solution

  • Your problem is related to the usage of localhost inside of containers. Check this to understand why localhost does not work in docker environments.

    You need the ip of the server, in your case your laptop. If you start an app (any technology) at 5000, you can access it using localhost:5000 and if you know your ip: 192.168.1.10:5000

    Try to get your local ip and use it directly on your axios invocation to validate if that is your problem.

    If that was the mistake, the second level of improvement is to use environment variable in your nodejs to avoid hardcoded values. You could pass this value using your docker-compose

    services:
      comments:
        build: ./comments
        ports:
          - "4201:4201"
      posts:
        build: ./posts
        ports: 
          - "4200:4200"
        environment:
            - POSTS_API_BASE_DOMAIN=http://192.168.4.15:4201
        depends_on:
          - comments
    

    And in your nodejs:

    await axios.get(process.env.POSTS_API_BASE_DOMAIN+"/comments");
    

    This strategy will allow you to use a public domain for real scenarios instead ips on your development or staging environments:

    POSTS_API_BASE_DOMAIN=https://jan-tudan-post.com
    

    As you see, networks or links is not required if you use the ip and prepares you to real environment in which microservices are deployed in different servers with its own ip or public domain

    Deploy on another server

    What happen if you need to deploy in another server. You will have to update the ip in your docker-compose or use a kind of script to get the ip and use a variable. Sample on linux:

    export POSTS_API_BASE_DOMAIN="http://"$(hostname -I| awk '{printf $1}')
    

    and in your docker-compose

    environment:
        - POSTS_API_BASE_DOMAIN=http://192.168.4.15:4201
    

    Just for test or quickly deploy

    If you don't want to mess up with ips and you just need a quicly deploy for a demo, you could use host.docker.internal. Check that section here

    Recommend topics