Kratos服务需通过Istio注入或自建xDS服务器将注册中心数据转换为EDS/CDS配置供Envoy消费,而非直接暴露registry;关键在于确保Pod启用istio-injection、Service标签正确、gRPC健康检查使用http2_health_check并匹配service_name,且DestinationRule host必须为Service DNS名而非IP。

Kratos服务如何让Envoy识别并正确路由?
Kratos本身不直接暴露服务发现细节给Envoy,必须通过显式注册机制打通。Envoy默认只认xDS(如EDS、CDS)下发的集群和服务信息,而Kratos的registry模块(比如registry/etcd或registry/kubernetes)只是把实例注册到后端注册中心,并不会自动同步到Envoy的配置中。
关键点在于:Envoy不消费Kratos的注册中心数据,它只认Istio控制面或自建xDS服务器下发的配置。所以常见错误是以为“Kratos注册了,Envoy就能发现”,结果请求404或503。
实操建议:
- 若用Istio,确保Kratos服务Pod打了
istio-injection=enabled标签,且Service资源有正确的app和versionlabel,否则Istio无法生成对应的EndpointSlice - 若不用Istio,需自己实现xDS server(如基于
envoy-control-plane),将Kratos注册中心的数据(如etcd中的/registry/kratos-user-service)转换为EDS响应 - Kratos启动时要启用gRPC反射(
grpc.EnableReflection),否则Envoy的健康检查可能因无法探测gRPC服务而标记为unhealthy
为什么Kratos gRPC接口在Envoy里返回UNAVAILABLE?
这不是Kratos没起来,而是Envoy对gRPC状态码和HTTP/2语义理解错位导致的典型误判。gRPC over HTTP/2的GRPC_STATUS放在Trailers里,但Envoy默认健康检查只看HTTP状态码(如200),不解析Trailers;若后端gRPC服务返回StatusCode.Unavailable,而Envoy健康检查用HTTP GET /healthz探活,就会判定实例下线。
更隐蔽的问题是:Kratos的gRPC服务监听地址若写成0.0.0.0:9000,而Envoy的cluster配置中lb_endpoints指向的是Pod IP,但Kubernetes里Pod IP可能被CNI插件隔离,Envoy容器无法直连——此时必须走ClusterIP Service,且DestinationRule中host字段必须匹配Service DNS名(如user-service.default.svc.cluster.local),不能填IP。
实操建议:
- 健康检查路径改用gRPC原生探活:
http2_health_check+service_name(对应Kratos的gRPC service full name,如kratos.api.v1.UserService) - 确保
VirtualService中grpc协议声明明确:port.protocol: GRPC,否则Envoy按HTTP处理,gRPC metadata丢失 - 检查Kratos的
transport/grpc/server.go是否启用了KeepaliveParams,否则长连接空闲超时会被Envoy断开,触发重连风暴
Envoy日志里反复出现“upstream connect error or disconnect/reset before headers”怎么定位?
这个错误本质是Envoy发出了请求,但没收到任何响应头(headers),常见于gRPC流式响应未及时flush、TLS握手失败、或Kratos中间件panic导致连接静默关闭。
最容易被忽略的是:Kratos的middleware/recovery默认捕获panic但不记录堆栈,而Envoy看到连接突然中断,就记下这条模糊日志。此时实际问题在Kratos侧,但排查方向全被引向网络或TLS。
实操建议:
- 在Kratos启动时加
log.SetLevel(log.LevelDebug),并开启transport/grpc.ServerOption(grpc.StatsHandler(...))打印gRPC调用耗时与状态 - 用
tcpdump -i any port 9000 -w envoy-grpc.pcap在Envoy容器内抓包,过滤tcp.stream eq 0 and http2,看是否真有HEADERS帧发出 - 检查Envoy的
access_log格式是否包含%UPSTREAM_TRANSPORT_FAILURE_REASON%,该字段会明确写出是read_timeout、connection_termination还是ssl_error - 若用mTLS,确认Kratos证书的
Subject Alternative Name包含Pod DNS名,否则Envoy校验失败后直接reset连接,不发任何error detail
对接Kratos和Envoy不是配通就完事,真正卡点往往藏在gRPC协议细节、健康检查语义、以及错误传播链路的断层上——这些地方日志不报具体原因,只甩一句“connect reset”,得靠抓包+状态码+证书三者交叉验证才能闭环。


















