Kratos 项目目录结构由 Go 编译器规则和框架工具链共同约束,非风格选择:/cmd 仅存 main.go 以满足 Go 构建要求;/internal 利用 Go internal 包机制实现业务隔离;/pkg 显式导出供外部引用;biz/data/service 三层严格分层保障依赖流向与可测试性;api 目录仅放 .proto 文件作为唯一契约源;configs 和 third_party 是启动必读路径,缺失将导致 panic 或配置失效。

Kratos 项目目录不是“看着顺眼就放”,而是靠 Go 编译器规则 + 框架工具链共同约束出来的结构。不按约定组织,kratos run 会找不到入口,wire 生成依赖会失败,protoc 生成的 service 代码也容易包导入错——这不是风格问题,是编译期报错问题。
为什么必须有 /cmd、/internal、/pkg 这三个顶层目录
Go 编译器从 1.4 开始强制限制 internal 包的可见性:只有同级或上层路径能 import 它。Kratos 的 /internal 就是靠这个机制实现“业务代码天然不可被外部项目直接引用”的隔离效果。而 /cmd 是唯一允许放 main.go 的地方,因为 Go 工具链只认 package main 在根目录下(或其子目录)才能构建可执行文件;/pkg 则是显式声明“这里的东西欢迎别人 go get”,和 /internal/pkg 有本质区别——后者只是项目内复用,对外不可见。
-
/cmd/demo/main.go→ 构建出demo二进制,不能写 biz 逻辑 -
/internal/biz/user.go→ 可被/internal/serviceimport,但不能被/cmd或外部项目 import -
/pkg/redis→ 其他项目可import "your-repo/pkg/redis",且go list -m能识别为模块导出路径
/internal 下 biz/data/service 三层不能混着写
这三层不是“为了分而分”,而是对应清晰的数据流向和依赖方向:biz 处理领域规则(比如“用户余额不能为负”),data 封装数据源访问(DB/Redis/gRPC Client),service 做服务编排(组合多个 biz 和 data 实现一个 RPC 接口)。如果把 DB 查询逻辑直接写进 service,会导致:
- 单元测试时无法单独 mock
data层,因为没抽象出 interface -
wire无法自动生成依赖注入代码,因为service直接 new 了 DB client - 后续想把某个
biz抽成独立微服务时,没有干净的接口定义出口
正确做法是:每个 biz 类型暴露 interface,data 实现它,service 只依赖 interface。
api 目录只放 .proto,别塞 Go 代码
api 是契约层,不是实现层。所有 HTTP 路径、gRPC 方法、请求响应结构、错误码枚举,都该用 Protobuf 定义在 .proto 文件里。框架靠 protoc + 插件自动生成 *_http.pb.go 和 *_grpc.pb.go,这些文件会被 /internal/service import 并实现。如果手动在 api 下写 xxx.go 放 handler,会出现:
- HTTP 和 gRPC 接口行为不一致(比如校验逻辑写两遍)
-
kratos proto client生成的客户端代码无法对齐服务端定义 - 跨团队协作时,前端或 iOS 团队拿不到权威的 IDL,只能靠文档或反向猜
记住:api/xxx/xxx.proto 是唯一真相源,其他都是它的衍生物。
configs 和 third_party 不是可选项,是启动必读路径
configs 目录下放的是运行时配置文件(app.yaml、bootstrap.yaml),Kratos 启动时默认从这里加载;third_party 是放非 Go 生态的协议定义(比如 OpenAPI spec、Thrift IDL),供生成工具消费。这两个目录虽不参与编译,但一旦路径错位或文件名不匹配,kratos run 会 panic 报 config not found 或 no bootstrap config。尤其注意:
-
configs/bootstrap.yaml必须存在,它是服务发现、注册中心、日志等级等全局配置的入口 -
configs/app.yaml是服务自身配置(如监听地址、DB 连接串),会被paladin或apollo等配置中心组件读取 -
third_party/google/api/annotations.proto必须存在,否则google.api.http注解失效,HTTP 映射不生成
最常被忽略的是 bootstrap.yaml 里的 providers 配置——它决定了哪些配置源(file、etcd、nacos)会被启用,漏配会导致环境变量或远程配置根本拉不下来。


















