Docker容器无法相互连接 - 连接拒绝

发布于 2025-01-27 20:46:25 字数 3820 浏览 2 评论 0原文

我有一个由Docker组成的简单应用程序。它由一个简单的前端(使用NextJS构建),GraphQl API(使用Nestjs构建)和微服务(使用Nestjs构建)组成。

架构如下:

  1. 前端直接与GraphQl服务说话。
  2. GraphQL服务通过用作消息代理的NATS服务器通信到微服务。
  3. 微服务通过Nodejs驱动程序库直接与MongoDB实例进行通信。

当我在本地运行所有内容时,所有这些都可以完美连接,并且应用程序可以正常运行。但是,当我在Docker容器中运行所有内容(使用Docker Compose)时,我发现GraphQl API无法连接到NATS服务器,并且微服务无法与MongoDB实例连接。

这是我的docker-compose.yml文件:

version: '3'

services:
  nats:
    container_name: nats
    image: nats
    ports:
      - 4222:4222
      - 6222:6222
      - 8222:8222
    networks:
      - services

  mongo:
    container_name: mongo
    image: mongo
    restart: always
    ports:
      - 27017:27017
    networks:
      - services

  frontend:
    container_name: frontend
    build:
      context: ./apps/frontend/.
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    ports:
      - 3000:3000
  
  gateway:
    container_name: gateway
    build:
      context: ./apps/gateway/
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    environment:
      - NATS_URL="nats://nats:4222"
    ports:
      - 3001:3001
    networks:
      - services
    depends_on:
      - nats
      - mongo

  user-service:
    container_name: user-service
    build:
      context: ./apps/user-service
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    environment:
      - NATS_URL="nats://nats:4222"
      - MONGO_URL="mongodb://localhost:27017"
    ports:
      - 3002:3002
    networks:
      - services
    depends_on:
      - nats
      - mongo

networks:
  services:
    driver: bridge

这是试图向Nats服务器发送消息的代码:

import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { map, Observable, tap, toArray } from 'rxjs';
import { User } from './models/user.model';

@Injectable()
export class UsersService {
  constructor(@Inject('NATS_CLIENT') private nats: ClientProxy) {}

  findAll(): Observable<User[]> {
    return this.nats.send('users.get-users', {}).pipe(
      tap((result) => console.log('result', result)),
      map((user) => ({ name: user.name, email: user.email })),
      toArray(),
    );
  }
}

这是启动NATS客户端的模块:

import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { UsersResolver } from './users.resolver';
import { UsersService } from './users.service';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'NATS_CLIENT',
        transport: Transport.NATS,
        options: {
          url: process.env.NATS_URL,
        },
      },
    ]),
  ],
  providers: [UsersService, UsersResolver],
})
export class UsersModule {}

您可以看到连接字符串通过以前在docker-compose.yml文件中设置的环境变量。

当我发送GraphQl请求以触发发送消息时,我会收到以下错误:

Error: connect EADDRNOTAVAIL ::1:4222 - Local (:::0)
     at internalConnect (node:net:953:16)
     at defaultTriggerAsyncIdScope (node:internal/async_hooks:465:18)
     at node:net:1044:9
     at processTicksAndRejections (node:internal/process/task_queues:78:11) {
   errno: -99,
   code: 'EADDRNOTAVAIL',
   syscall: 'connect',
   address: '::1',
   port: 4222
}

潜在解决方案尝试:

  • 我尝试了连接字符串的不同URL,包括nats:// nats:42222 < /code>,nats:// localhost:4222nats://127.0.0.1:42222nats://0.0.0.0.0.0.0:42222 ,nats://host.docker.internal:4222等。它们的最终结果是上述错误或连接拒绝错误。
  • 我试图确保容器可以通过运行docker exec [container1] ping [container2] -c2进行通信,其中[container1]/[container2]是相应的容器名称。这样做,我总是得到回应。

自从我使用Docker容器以来已经很长时间了,所以如果有人有任何想法,我会很感兴趣,因为这让我发疯了!

I have a simple application orchestrated by Docker Compose. It consists of a simple frontend (built using NextJS), a GraphQL API (built with NestJS), and a microservice (built with NestJS).

The architecture is as follows:

  1. The frontend speaks directly to the GraphQL service.
  2. The GraphQL service communicates to the microservice via a NATS server that acts as a message broker.
  3. The microservice communicates directly with a MongoDB instance via the NodeJS driver library.

When I run everything locally, it all connects perfectly and the application works. However when I run everything in Docker containers (using Docker Compose) I find that the GraphQL API cannot connect to the NATS server and the microservice cannot connect with the MongoDB instance.

Here is my docker-compose.yml file:

version: '3'

services:
  nats:
    container_name: nats
    image: nats
    ports:
      - 4222:4222
      - 6222:6222
      - 8222:8222
    networks:
      - services

  mongo:
    container_name: mongo
    image: mongo
    restart: always
    ports:
      - 27017:27017
    networks:
      - services

  frontend:
    container_name: frontend
    build:
      context: ./apps/frontend/.
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    ports:
      - 3000:3000
  
  gateway:
    container_name: gateway
    build:
      context: ./apps/gateway/
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    environment:
      - NATS_URL="nats://nats:4222"
    ports:
      - 3001:3001
    networks:
      - services
    depends_on:
      - nats
      - mongo

  user-service:
    container_name: user-service
    build:
      context: ./apps/user-service
      dockerfile: Dockerfile
      args:
        - NODE_ENV=development
    environment:
      - NATS_URL="nats://nats:4222"
      - MONGO_URL="mongodb://localhost:27017"
    ports:
      - 3002:3002
    networks:
      - services
    depends_on:
      - nats
      - mongo

networks:
  services:
    driver: bridge

Here is the code that attempts to send a message to the NATS server:

import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { map, Observable, tap, toArray } from 'rxjs';
import { User } from './models/user.model';

@Injectable()
export class UsersService {
  constructor(@Inject('NATS_CLIENT') private nats: ClientProxy) {}

  findAll(): Observable<User[]> {
    return this.nats.send('users.get-users', {}).pipe(
      tap((result) => console.log('result', result)),
      map((user) => ({ name: user.name, email: user.email })),
      toArray(),
    );
  }
}

And here is the module that initialises the NATS client:

import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { UsersResolver } from './users.resolver';
import { UsersService } from './users.service';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'NATS_CLIENT',
        transport: Transport.NATS,
        options: {
          url: process.env.NATS_URL,
        },
      },
    ]),
  ],
  providers: [UsersService, UsersResolver],
})
export class UsersModule {}

As you can see the connection string comes through as an environmental variable that was previously set in the docker-compose.yml file.

When I send a GraphQL request to trigger the send message I get the following error:

Error: connect EADDRNOTAVAIL ::1:4222 - Local (:::0)
     at internalConnect (node:net:953:16)
     at defaultTriggerAsyncIdScope (node:internal/async_hooks:465:18)
     at node:net:1044:9
     at processTicksAndRejections (node:internal/process/task_queues:78:11) {
   errno: -99,
   code: 'EADDRNOTAVAIL',
   syscall: 'connect',
   address: '::1',
   port: 4222
}

Potential solutions tried:

  • I've tried different urls for the connection string including nats://nats:4222, nats://localhost:4222, nats://127.0.0.1:4222, nats://0.0.0.0:4222, nats://host.docker.internal:4222, etc. The end result of each of them is either the above error or a connection refused error.
  • I've tried to ensure that the containers can communicate by running docker exec [container1] ping [container2] -c2 where [container1]/[container2] are the respective container names. Doing this I always get a response.

It's been a long time since I've used Docker containers so I'd be interested if anybody has any ideas as this is driving me crazy!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

各自安好 2025-02-03 20:46:25

我遇到了几乎相同的配置的确切问题。对我而言,它解决的问题是查看Nest js https://docs.nestjs.com/微服务/NAT 。如果您查看所有示例,他们使用服务器键来配置NAT而不是url。因此,尝试在usermodule中使用以下内容:

ClientsModule.register([
      {
        name: 'NATS_CLIENT',
        transport: Transport.NATS,
        options: {
          servers: [process.env.NATS_URL],
        },
      },
    ]),

I was having the same exact issue you were with almost the same configuration. What fixed it for me was looking at the NATS documentation for Nest JS https://docs.nestjs.com/microservices/nats. If you look at all the examples, they use the servers key to configure NATS instead of url. So try using the following inside your UsersModule:

ClientsModule.register([
      {
        name: 'NATS_CLIENT',
        transport: Transport.NATS,
        options: {
          servers: [process.env.NATS_URL],
        },
      },
    ]),
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文