Docker network for communication between gRPC client and server

Docker network for communication between gRPC client and server

Fix "14 UNAVAILABLE: Name resolution failed"

Sathya Molagoda's photo
Sathya Molagoda
·Sep 27, 2022·

3 min read

Play this article

Table of contents

  • Intro
  • Project Configuration
  • Conclusion

Intro

In a recent project that I have been working on, I faced an issue that was pretty hard to find a solution and helpful guide to implement correctly. "14 UNAVAILABLE: Name resolution failed for target DNS:http://0.0.0.0:40000" was the error that I was getting, and it took a reasonable time for me to fix it. So in this article, I am going to discuss why it happened and how I was able to fix it.

It is a GRPC microservices project which had several microservices developed in NestJs. API Gateway provides GraphQl APIs. The question service manages all the questions.

Project Configuration

These are configurations in the project which caused the error mentioned above.

Question Service

Main.ts file content.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '@nestjs/microservices';
import { join } from 'path';

const microserviceOptions = {
  transport: Transport.GRPC,
  options: {
    package: 'questionPackage',
    protoPath: join(__dirname, '../src/question/question.proto'),
    url: '0.0.0.0:40000',
  },
};

async function bootstrap() {
  const app = await NestFactory.createMicroservice(
    AppModule,
    microserviceOptions,
  );
  app.listen();
}
bootstrap();

API Gateway

import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { Client, ClientGrpc, ClientOptions, Transport } from '@nestjs/microservices';
import { CreateQuestionInput } from './dto/create-question.input';
import { QuestionGrpcService } from './grpc.interface';
import { Question } from './entities/question.entity';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class QuestionService implements OnModuleInit {
  private logger = new Logger('QuestionService');
  const microserviceOptions: ClientOptions = {
  transport: Transport.GRPC,
  options: {
    package: 'questionPackage',
    protoPath: join(__dirname, '../question/question.proto'),
    url: '0.0.0.0:40000',
  },
};
  @Client(microserviceOptions)
  private client: ClientGrpc;

  private questionGrpcService: QuestionGrpcService;

  onModuleInit() {
    this.questionGrpcService =
      this.client.getService<QuestionGrpcService>('QuestionService');
  }

  createQuestion(createQuestionInput: CreateQuestionInput) {
    return this.questionGrpcService.createQuestion(createQuestionInput);
  }

  async getQuestions(): Promise<Question[]> {
    let questions = [];
    const res = await firstValueFrom(this.questionGrpcService.getQuestions({}));
    questions = res.questionsResposes;
    return questions;
  }
}

Two applications deployed using the following docker commands.

docker run -dit -p 3000:3000  ${{ env.REGISTRY }}/api-gateway:latest
docker run -dit -p 40000:40000  ${{ env.REGISTRY }}/question-service:latest

After running the two docker images, when I tried to run the GraphQl query from the apollo server client, I received the "14 UNAVAILABLE: Name resolution failed for target DNS:http://0.0.0.0:40000" error.

Once we run docker containers, we cannot communicate between those docker containers through the local network. To overcome this problem, we use the docker network for communication between two containers.

docker network create web_server --driver bridge

Then we should mention the service name and the network in the docker command.

docker run -dit -p 3000:3000 --name question-service --network web_server ${{ env.REGISTRY }}/api-gateway:latest
docker run -dit -p 40000:40000 --name question-service --network web_server  ${{ env.REGISTRY }}/question-service:latest

After making these changes, we can update the gRPC URL of both services as below.

const microserviceOptions: ClientOptions = {
  transport: Transport.GRPC,
  options: {
    package: 'questionPackage',
    protoPath: join(__dirname, '../question/question.proto'),
    url: 'dns:///question-service:40000',
  }

Conclusion

Docker uses the docker network to communicate between containers. To establish the communication between docker containers, we register them to the docker network by specifying the service name and network in the docker run command.

 
Share this