Search code examples
dockerdnsnestjsgrpc

How to fix "14 UNAVAILABLE: Name resolution failed for target dns:http://sample-service:40000" GRPC + Docker error


I have a deployed nest.js gRPC server and a client in docker containers with the following docker commands,

Client (api-gateway) :

docker run -dit -p 3000:3000 --hostname ${{ env.IMAGE_NAME }} --name ${{ env.IMAGE_NAME }} --network web_server ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{env.TAG}}

env for client

IMAGE_NAME=api-gateway

Server (question-service) :

docker run -dit -p 40000:40000 --hostname ${{ env.IMAGE_NAME }} --name ${{ env.IMAGE_NAME }} --network web_server ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{env.TAG}}

env for server

IMAGE_NAME=question-service

Main.ts of the server (question-service) is like this,

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();

and the client integration is like this, grpc.option.ts:

import { ClientOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';

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

question.service.ts:

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

@Injectable()
export class QuestionService implements OnModuleInit {
  private logger = new Logger('QuestionService');
  @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;
  }
}

But when I call the graphql enpoint of api-gateway to get all question it returns following error,

{
  "errors": [
    {
      "message": "14 UNAVAILABLE: Name resolution failed for target dns:http://question-service:40000",
      "locations": [
        {
          "line": 16,
          "column": 3
        }
      ],
      "path": [
        "question"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "code": 14,
          "details": "Name resolution failed for target dns:http://question-service:40000",
          "metadata": {},
          "stacktrace": [
            "Error: 14 UNAVAILABLE: Name resolution failed for target dns:http://question-service:40000",
            "    at Object.callErrorFromStatus (/node_modules/@grpc/grpc-js/build/src/call.js:31:19)",
            "    at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client.js:190:52)",
            "    at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141)",
            "    at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181)",
            "    at /node_modules/@grpc/grpc-js/build/src/call-stream.js:188:78",
            "    at processTicksAndRejections (internal/process/task_queues.js:79:11)",
            "for call at",
            "    at ServiceClientImpl.makeUnaryRequest (/node_modules/@grpc/grpc-js/build/src/client.js:160:30)",
            "    at ServiceClientImpl.getQuestions (/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)",
            "    at Observable._subscribe (/node_modules/@nestjs/microservices/client/client-grpc.js:177:39)",
            "    at Observable._trySubscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:41:25)",
            "    at /node_modules/rxjs/dist/cjs/internal/Observable.js:35:31",
            "    at Object.errorContext (/node_modules/rxjs/dist/cjs/internal/util/errorContext.js:22:9)",
            "    at Observable.subscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:26:24)",
            "    at /node_modules/rxjs/dist/cjs/internal/firstValueFrom.js:24:16",
            "    at new Promise (<anonymous>)",
            "    at firstValueFrom (/node_modules/rxjs/dist/cjs/internal/firstValueFrom.js:8:12)"
          ]
        }
      }
    }
  ],
  "data": null
}

below command return,

sudo docker inspect web_server 

[
    {
        "Name": "web_server",
        "Id": "23b4a40928a88861f7a063db4dac5c491db5384181d28ee5563db52f96c22e55",
        "Created": "2022-09-06T17:55:54.611611429Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "181868f91a188056e5f21de4bb6ca16b92f36befcd832386206256701b7be16a": {
                "Name": "question-service",
                "EndpointID": "01a4c375b95be1eb9be58993abcb8bf15fe2a8d91ac2635c4a3746036fc51747",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "828c06298e42184665507f3c6bd73a54feb36e3da3214360a015ba67104f1fdd": {
                "Name": "api-gateway",
                "EndpointID": "2ca0ba9b3f6664095e8146b5d6243362fc0a5188a73c80b7afd47207a5c62e1e",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

Solution

  • I was able to fix this issue by changing the URLs in both client and server configurations as below.

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

    refer this anwer for more information. Also you can refer this blog post