多分支部署必须用Registry+Namespace隔离,Kratos不内置分支概念,需通过服务注册中心的namespace或tag实现逻辑隔离,避免配置爆炸与路由混乱。

多分支部署必须用 Registry + Namespace 隔离
Kratos 本身不内置“分支”概念,所谓多分支部署,本质是靠服务注册中心的命名空间(namespace)或标签(tag)做逻辑隔离。硬靠改服务名或端口来区分 dev/staging/prod,会导致配置爆炸、路由混乱、客户端耦合加重。
常见错误现象:本地跑 kratos run 启动两个同名服务(比如都叫 user-service),但没配 registry 的 namespace 或 tags,结果 consul/etcd 里只看到一个实例,或者两个实例互相覆盖。
- Consul 用户必须在
Bootstrap.registry.consul中显式设置namespace字段(如"dev"),且服务启动时传入对应 tag:--registry=consul://127.0.0.1:8500?namespace=dev - Etcd 用户需在
registry初始化时指定prefix,例如/services/dev/user-service,避免和/services/prod/user-service冲突 - 所有客户端调用必须使用带 namespace 的
client.NewClient,否则默认走全局 registry,跨分支调用就成常态了
测试环境路由控制靠 Selector + Tag Matching
测试环境需要让 A 服务只调用 B 服务的 dev 分支实例,不能靠改 URL 硬编码(比如把 http://b-service 改成 http://b-service-dev),这违背 Kratos 的服务发现原则,也破坏了 Protobuf 定义的契约。
正确做法是用 selector 插件做标签路由。Kratos 默认用 selector.DefaultSelector,它支持按 metadata 匹配节点。
- 启动 B 服务 dev 实例时,在
server配置中注入标签:metadata: {"env": "dev", "branch": "feature/login"} - A 服务发起调用前,构造带匹配规则的
selector.Option:selector.WithMetadata(map[string]string{"env": "dev"}) - 若需更细粒度(比如只调 feature/login 分支),则用
selector.WithMetadata(map[string]string{"branch": "feature/login"}),但要注意该标签必须存在于目标实例的 registry 注册信息中 - 别漏掉
client.WithSelector—— 这个 option 必须显式传给client.NewClient,否则 selector 不生效
Protobuf 接口定义要预留 metadata 透传能力
很多团队在 proto 文件里只定义业务字段,没预留 metadata 透传机制,导致测试环境无法动态注入路由标签。Kratos 的 gRPC 请求天然支持 context 透传,但 HTTP 层需手动处理。
- HTTP 接口在
.proto的google.api.http扩展中,加additional_bindings并声明body: "*",允许前端传额外字段 - 服务端解析请求时,从
ctx.Value或http.Request.Header提取X-Env/X-Branch头,并写入metadata供 selector 使用 - gRPC 接口无需额外字段,直接用
grpc.SendHeader和metadata.MD透传即可,但注意 client 端要ctx = metadata.AppendToOutgoingContext(ctx, "env", "dev") - 切勿在 proto message 里硬加
string env = 999;—— 这会让业务逻辑感知部署细节,污染领域模型
本地开发联调时绕过 registry 的坑
开发阶段常有人用 --skip-registry 或直接注释掉 registry 配置来“快速启动”,结果测试环境路由完全失效:selector 找不到任何节点,client 直接 panic “no endpoints available”。
- 本地开发必须启动轻量 registry(如 consul agent -dev 或 etcd --listen-client-urls=http://127.0.0.1:2379),哪怕只跑一个节点
- 不要禁用 registry,而是用
registry.NoopRegistry替代 —— 它不注册也不发现,但保留 selector 接口,方便单元测试 mock -
kratos run启动时加-conf ./configs/dev.yaml,确保 config 中registry配置指向本地 consul/etcd,而不是空或 prod 地址 - CI 流水线里,如果用 docker compose 启多个服务,记得每个 service 的
environment里设好REGISTRY_NAMESPACE=staging,并挂载对应 config
真正难的不是写几行 selector 代码,而是让整个团队对 “服务实例 = name + namespace + tags + metadata” 形成统一认知。一旦有人绕过 registry 直连 IP,或者在 proto 里塞环境字段,整套路由控制就形同虚设。



















