Docker容器内NestJS gRPC客户端无法解析gRPC服务DNS问题
gRPC服务与Docker容器内客户端连接失败问题
我有一个gRPC服务和作为gRPC客户端的简易HTTP服务器,本地运行正常,但放入独立Docker容器后无法建立连接。gRPC服务运行并暴露5001端口。
NestJS gRPC客户端注册代码
ClientsModule.register([ { name: "TOKEN_NAME", transport: Transport.GRPC, options: { ...GRPC_OPTIONS, url: process.env.GRPC_SERVICE_URL }, }, ]),
尝试过的Docker配置
方案1:使用容器名称作为URL
version: '3.9' services: grpc-service: restart: always build: ./grpc-service container_name: grpc-service grpc-client: restart: always build: ./backend container_name: grpc-client # links: # - "grpc-service:service" depends_on: - grpc-service ports: - "3000:3000" environment: - GRPC_SERVICE_URL=http://grpc-service:5001 # - GRPC_SERVICE_URL=http://service:5001
方案2:自定义网络并分配固定IP
version: '3.9' networks: mynetwork: driver: bridge ipam: config: - subnet: 179.20.0.0/24 services: grpc-service: restart: always build: ./grpc-service container_name: grpc-service networks: mynetwork: ipv4_address: 179.20.0.5 grpc-client: restart: always build: ./backend container_name: grpc-client networks: mynetwork: ipv4_address: 179.20.0.6 depends_on: - grpc-service ports: - "3000:3000" environment: - GRPC_SERVICE_URL=179.20.0.5:5001
错误信息
使用http://grpc-service:5001时
grpc-client | [Nest] 1 - 09/20/2022, 12:20:14 PM ERROR [ExceptionsHandler] 14 UNAVAILABLE: Name resolution failed for target dns:http://grpc-service:5001 grpc-client | Error: 14 UNAVAILABLE: Name resolution failed for target dns:http://grpc-service:5001 grpc-client | at Object.callErrorFromStatus (/node_modules/@grpc/grpc-js/build/src/call.js:31:19) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client.js:190:52) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181) grpc-client | at /node_modules/@grpc/grpc-js/build/src/call-stream.js:188:78 grpc-client | at processTicksAndRejections (node:internal/process/task_queues:78:11) grpc-client | for call at grpc-client | at ServiceClientImpl.makeUnaryRequest (/node_modules/@grpc/grpc-js/build/src/client.js:160:30) grpc-client | at ServiceClientImpl.<anonymous> (/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19) grpc-client | at Observable._subscribe (/node_modules/nestjs/microservices/client/client-grpc.js:177:35) grpc-client | at Observable._trySubscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:41:25) grpc-client | at /node_modules/rxjs/dist/cjs/internal/Observable.js:35:31 grpc-client | at Object.errorContext (/node_modules/rxjs/dist/cjs/internal/util/errorContext.js:22:9) grpc-client | at Observable.subscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:26:24) grpc-client | at /node_modules/rxjs/dist/cjs/internal/lastValueFrom.js:10:16 grpc-client | at new Promise (<anonymous>) grpc-client | at lastValueFrom (/node_modules/rxjs/dist/cjs/internal/lastValueFrom.js:7:12)
使用179.20.0.5:5001时
grpc-client | [Nest] 1 - 09/20/2022, 12:22:14 PM ERROR [ExceptionsHandler] 14 UNAVAILABLE: No connection established grpc-client | Error: 14 UNAVAILABLE: No connection established grpc-client | at Object.callErrorFromStatus (/node_modules/@grpc/grpc-js/build/src/call.js:31:19) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client.js:190:52) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141) grpc-client | at Object.onReceiveStatus (/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181) grpc-client | at /node_modules/@grpc/grpc-js/build/src/call-stream.js:188:78 grpc-client | at processTicksAndRejections (node:internal/process/task_queues:78:11) grpc-client | for call at grpc-client | at ServiceClientImpl.makeUnaryRequest (/node_modules/@grpc/grpc-js/build/src/client.js:160:30) grpc-client | at ServiceClientImpl.<anonymous> (/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19) grpc-client | at Observable._subscribe (/node_modules/nestjs/microservices/client/client-grpc.js:177:35) grpc-client | at Observable._trySubscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:41:25) grpc-client | at /node_modules/rxjs/dist/cjs/internal/Observable.js:35:31 grpc-client | at Object.errorContext (/node_modules/rxjs/dist/cjs/internal/util/errorContext.js:22:9) grpc-client | at Observable.subscribe (/node_modules/rxjs/dist/cjs/internal/Observable.js:26:24) grpc-client | at /node_modules/rxjs/dist/cjs/internal/lastValueFrom.js:10:16 grpc-client | at new Promise (<anonymous>) grpc-client | at lastValueFrom (/node_modules/rxjs/dist/cjs/internal/lastValueFrom.js:7:12)
补充测试
将gRPC服务在Docker中运行并映射端口5001:5001,本地HTTP客户端尝试连接localhost:5001的gRPC服务,出现如下错误:
[Nest] 93680 - 09/24/2022, 2:52:50 PM ERROR [ExceptionsHandler] 14 UNAVAILABLE: Connection dropped Error: 14 UNAVAILABLE: Connection dropped at Object.callErrorFromStatus (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/call.ts:81:17) at Object.onReceiveStatus (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/client.ts:352:36) at Object.onReceiveStatus (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/client-interceptors.ts:462:34) at Object.onReceiveStatus (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/client-interceptors.ts:424:48) at /Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/call-stream.ts:330:24 at processTicksAndRejections (node:internal/process/task_queues:78:11) for call at at ServiceClientImpl.makeUnaryRequest (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/client.ts:324:26) at ServiceClientImpl.<anonymous> (/Users/grpc-docker/backend/node_modules/@grpc/grpc-js/src/make-client.ts:189:15) at Observable._subscribe (/Users/grpc-docker/backend/node_modules/nestjs/microservices/client/client-grpc.js:177:35) at Observable._trySubscribe (/Users/grpc-docker/backend/node_modules/rxjs/src/internal/Observable.ts:245:19) at /Users/grpc-docker/backend/node_modules/rxjs/src/internal/Observable.ts:235:18 at Object.errorContext (/Users/grpc-docker/backend/node_modules/rxjs/src/internal/util/errorContext.ts:29:5) at Observable.subscribe (/Users/grpc-docker/backend/node_modules/rxjs/src/internal/Observable.ts:221:5) at /Users/grpc-docker/backend/node_modules/rxjs/src/internal/lastValueFrom.ts:59:12 at new Promise (<anonymous>) at lastValueFrom (/Users/grpc-docker/backend/node_modules/rxjs/src/internal/lastValueFrom.ts:56:10)
解决方案
1. 修正gRPC客户端URL格式
gRPC的url配置不需要http://前缀,直接使用容器名:端口或IP:端口即可。修改环境变量:
# 方案1中修改为 GRPC_SERVICE_URL=grpc-service:5001 # 方案2中保持IP格式但确认无协议前缀 GRPC_SERVICE_URL=179.20.0.5:5001
2. 确保gRPC服务绑定正确地址
gRPC服务启动时,不要绑定localhost,而是绑定0.0.0.0,这样容器内的服务才能接受来自其他容器或外部的连接。例如在NestJS的gRPC服务配置中:
// gRPC服务启动代码 app.connectMicroservice({ transport: Transport.GRPC, options: { url: '0.0.0.0:5001', // 关键:绑定0.0.0.0而非localhost ...其他配置 }, });
3. 显式声明gRPC服务容器端口
在docker-compose中为gRPC服务添加expose配置,明确暴露容器内的5001端口(容器间通信无需端口映射,但显式声明更清晰):
grpc-service: restart: always build: ./grpc-service container_name: grpc-service expose: - "5001"
4. 处理容器启动顺序与服务就绪问题
depends_on仅保证容器启动顺序,不保证服务已就绪。添加健康检查,确保gRPC服务启动后客户端再尝试连接:
grpc-service: restart: always build: ./grpc-service container_name: grpc-service expose: - "5001" healthcheck: test: ["CMD", "grpc-health-probe", "-addr=:5001"] interval: 5s timeout: 5s retries: 5 grpc-client: restart: always build: ./backend container_name: grpc-client depends_on: grpc-service: condition: service_healthy # 等待服务健康 ports: - "3000:3000" environment: - GRPC_SERVICE_URL=grpc-service:5001
注意:需要在gRPC服务容器中安装
grpc-health-probe工具,可在Dockerfile中添加:RUN GRPC_HEALTH_PROBE_VERSION=v0.4.19 && \ wget -qO/bin/grpc-health-probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc-health-probe-linux-amd64 && \ chmod +x /bin/grpc-health-probe
5. 验证容器间网络连通性
进入客户端容器,尝试ping gRPC服务容器名或IP,确认网络可达:
docker exec -it grpc-client ping grpc-service # 或测试端口连通性 docker exec -it grpc-client nc -zv grpc-service 5001
如果无法连通,检查自定义网络配置是否正确,或使用Docker默认网络(同一docker-compose下的服务默认加入同一网络,容器名可直接解析)。
内容的提问来源于stack exchange,提问作者user13553252
相关产品推荐
相关产品推荐

