Docker容器无法相互连接 - 连接拒绝
我有一个由Docker组成的简单应用程序。它由一个简单的前端(使用NextJS构建),GraphQl API(使用Nestjs构建)和微服务(使用Nestjs构建)组成。
架构如下:
- 前端直接与GraphQl服务说话。
- GraphQL服务通过用作消息代理的NATS服务器通信到微服务。
- 微服务通过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:4222
,nats://127.0.0.1:42222
,nats://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:
- The frontend speaks directly to the GraphQL service.
- The GraphQL service communicates to the microservice via a NATS server that acts as a message broker.
- 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我遇到了几乎相同的配置的确切问题。对我而言,它解决的问题是查看Nest js https://docs.nestjs.com/微服务/NAT 。如果您查看所有示例,他们使用
服务器
键来配置NAT而不是url
。因此,尝试在usermodule
中使用以下内容: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 ofurl
. So try using the following inside yourUsersModule
: