docker-compose环境下跳过Envoy直接访问内部gRPC服务问题排查
问题根源排查
- Docker DNS解析失败
你在docker-compose.yml中将gRPC服务命名为grpcserver,Docker内部DNS仅能解析配置中定义的服务名,你使用basket-api作为主机名发起请求,自然找不到对应服务,这也是错误栈中Resource temporarily unavailable的核心原因。 - PathBase配置未适配
服务端配置了app.UsePathBase("/basket-api"),相当于给所有服务端点加了一层路径前缀,原本gRPC的默认调用路径/{服务名}/{方法名}会变成/basket-api/{服务名}/{方法名},如果客户端基地址不带此前缀,会直接返回404错误。 - 非加密HTTP2协议兼容问题
.NET gRPC客户端默认要求HTTPS才能使用HTTP2协议,你使用HTTP方案发起请求时需要显式开启非加密HTTP2支持,否则会出现协议协商失败的问题。
原项目81端口的作用说明
原项目中80端口配置为同时支持HTTP1和HTTP2,用于对外提供REST接口,81端口是专门配置的纯HTTP2端口,专门用于内部gRPC调用,不需要额外的协议协商开销,性能更高且稳定性更好。你看到的Envoy配置是用于对外暴露的REST接口转发,内部gRPC调用直接走81端口不经过Envoy,所以不需要走80端口。
修复方案
- 修正Docker服务名
将docker-compose.yml中的gRPC服务名改为basket-api,和调用时的主机名保持一致:
version: '3.4' services: basket-api: # 替换原有的grpcserver image: ${DOCKER_REGISTRY-}grpcserver build: context: . dockerfile: GrpcServer/Dockerfile grpcclient: image: ${DOCKER_REGISTRY-}grpcclient build: context: . dockerfile: GrpcClient/Dockerfile
- 修正客户端gRPC配置
这里推荐直接用专门的gRPC端口81,避免协议协商问题,同时适配PathBase配置,开启非加密HTTP2支持:
services.AddGrpcClient<Greeter.GreeterClient>((services, options) => { // 开启非加密HTTP2支持 AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); // 适配PathBase前缀,使用纯HTTP2的81端口 options.Address = new Uri("http://basket-api:81/basket-api"); });
如果不想保留PathBase配置,直接删除服务端app.UsePathBase("/basket-api")的代码,客户端地址改为http://basket-api:81即可。
内容的提问来源于stack exchange,提问作者Johhny Bravo
相关产品推荐
相关产品推荐

