1

I am trying to create NestJS micro-service and accessing it with a client gateway using docker container. When I ran it locally it works fine but when I deploy it on docker it gives me below error. I have two different docker files one for gateway and one for microserice.

[Nest] 1 - 03/06/2021, 10:11:19 PM [ExceptionsHandler] connect ECONNREFUSED 127.0.0.1:4000 +19833ms
Error: connect ECONNREFUSED 127.0.0.1:4000
at TCPConnectWrap.afterConnect [as oncomplet]

Dockerfile.gateway

FROM node:12.18-alpine
RUN mkdir -p /custom-root
WORKDIR /custom-root
COPY ./package.json .
COPY ./nest-cli.json .
COPY ./tsconfig.json .
COPY ./tsconfig.build.json .
COPY ./apps/gateway-client/. ./apps/gateway-client/.
RUN npm install -g @nestjs/cli
RUN npm install
RUN npm run build gateway-client
EXPOSE 3001
CMD [ "node", "./dist/apps/gateway-client/main.js" ]

Service docker file

FROM node:12.18-alpine
RUN mkdir -p /custom-root
WORKDIR /custom-root
COPY ./package.json .
COPY ./nest-cli.json .
COPY ./tsconfig.json .
COPY ./tsconfig.build.json .
COPY ./apps/service-customer/. ./apps/service-customer/.
RUN npm install -g @nestjs/cli
RUN npm install
RUN npm run build service-customer
EXPOSE 4000
CMD [ "node", "./dist/apps/service-customer/main.js" ]

Here is the Service file TCP connection

async function bootstrap() {
  const { SERVICE_CUSTOMER_PORT, SERVICE_CUSTOMER_HOST } = process.env;
  const port = SERVICE_CUSTOMER_PORT || 4000;
  const host = SERVICE_CUSTOMER_HOST || '0.0.0.0';
  const app = await NestFactory.createMicroservice(CustomerModule, {
    transport: Transport.TCP,
    options: {
      host,
      port
    },
  });
  app.listen(() => logger.log(`Customer Microservice is listening at ${port} host -> ${host}`));
}
bootstrap();

Here is the Code for gateway

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const { GATEWAY_PORT } = process.env;
  const port = GATEWAY_PORT || 3001
  await app.listen(port);
}
bootstrap();

Please help

Alejandro
  • 5,834
  • 1
  • 19
  • 36
Abhishek Jain
  • 13
  • 1
  • 3

3 Answers3

1

Noticed, you are using NestJS to create your micro-services and api-gateway both. In order to containerise them separately, you need to create separate hybrid application to communicate through http. Please have a look at Expose normal http endpoint in NestJS Microservices.

Here is an article that can help in splitting the apps.
How to split Nest.js microservices into separate projects?.

Post that, you can containerise all those different hybrid apps(micro-services over http) and configure them at your api gateway or any channel where the communication can happen.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Gaurav Mall
  • 500
  • 4
  • 16
0

You are trying to connect to the other container via the localhost, this is why you get the ECONNREFUSED 127.0.0.1:4000. The containers by default are running in isolated namespaces, including the network. There is nothing on port 4000 listening inside the namespace of the client container.

So for this to work, you have two options:

  1. Assure both containers share same network and use the servicename of the container to connect.

    version: "3.9"
    services:
    
      client:
        image: client
        links:
          - "server:server"
      server:
        image: server
    

    after this, the client container will have a DNS name server so a connection to server:4000 instead of the localhost:4000 will work.

  2. Connect both containers to host network. This is not recommended approach

jordanvrtanoski
  • 5,104
  • 1
  • 20
  • 29
0

For those facing the same issue, I followed @jordanvrtanoski's advice.

My problem was relatively similar to @Abhishek Jain's. I was trying to connect an API gateway and a microservice, both created with Nestjs and then dockerized, using TCP. While the connections between these two seemed very easy when running locally without Docker, they didn't work at all after dockerization. Note that I was using @EventPattern to establish the communication.

I realized that the problem was due to a failing network configuration. You can check the networks with the following command: docker network ls. In my case, my containers were running under the bridge driver, but when I inspected it with: docker network inspect bridge, I couldn't see them under the 'Containers' property.

To resolve this, I created a docker-compose file that sets the networks as follows: [docker-compose.yaml][1] Then after rebuilding my containers with the command: docker compose up I was able to see my two containers when inspecting 'shared_networks' under the 'Containers' property. But I was still missing something, whatever I tried the connection was not established.

Then I followed @jordanvrtanoski's advice. So, I simply registered the microservice in the API gateway using the network name that appeared for the microservice when inspecting the "shared_network", along with the port used in the microservice settings. Additionally, I ensured to inquire about the same configuration when creating the microservice.

Images are better than words: api-controller app.module.ts [app.module.ts][2]

microservice-user main.ts [main.ts microservice user][3]

docker network inspect shared_network [terminal inspect screen][4]

Then running my POST query through the api gateway emitted an event that the microservice was able to get.

UPDATE: The shared network configuration was the key in local environment. Just setting this up and call your service name as declared in the docker compose when registering the microservice and creating it will be enough to work. [1]: https://i.stack.imgur.com/dYVkK.png [2]: https://i.stack.imgur.com/tPp5E.png [3]: https://i.stack.imgur.com/cjx8m.png [4]: https://i.stack.imgur.com/S4oEp.png

Loup Lyon
  • 1
  • 1