Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关框架及工具。
名字来源于:《战神》游戏以希腊神话为背景,讲述由凡人成为战神的奎托斯(Kratos)成为战神并展开弑神屠杀的冒险历程。
工具集
kratos
kratos 命令行工具主要命令有
- new (通过 layout 模板创建项目)
- proto (proto 命令用于通过 proto 定义生成代码)
- upgrade (升级 kratos 和其他配套的命令行工具)
proto-gen-go-http
proto-gen-go-http 命令行工具是用于通过 proto 定义生成 http 代码
service BlogService {
rpc CreateArticle (CreateArticleRequest) returns (CreateArticleReply) {
option (google.api.http) = {
post: "/v1/article/"
body: "*"
};
}
rpc UpdateArticle (UpdateArticleRequest) returns (UpdateArticleReply) {
option (google.api.http) = {
put: "/v1/article/{id}"
body: "*"
};
}
rpc DeleteArticle (DeleteArticleRequest) returns (DeleteArticleReply) {
option (google.api.http) = {
delete: "/v1/article/{id}"
};
}
rpc GetArticle (GetArticleRequest) returns (GetArticleReply) {
option (google.api.http) = {
get: "/v1/article/{id}"
};
}
}
proto-gen-go-errors
proto-gen-go-errors 命令行工具用于通过 proto 定义生成 errors 代码
enum ErrorReason {
option (errors.default_code) = 500;
USER_NOT_FOUND = 0 [(errors.code) = 500];
CONTENT_MISSING = 1 [(errors.code) = 400];
}
proto-gen-validate
proto-gen-go-errors 命令行工具用于通过 proto 定义生成 validate 代码
message Request {
int64 id = 1 [(validate.rules).int64 = {gt: 0}];
int32 age = 2 [(validate.rules).int32 = {gt:0, lt: 120}];
uint32 code = 3 [(validate.rules).uint32 = {in: [1,2,3]}];
float score = 4 [(validate.rules).float = {not_in: [0, 99.99]}];
bool state = 5 [(validate.rules).bool.const = true];
string path = 6 [(validate.rules).string.const = "/hello"];
string phone = 7 [(validate.rules).string.len = 11];
string explain = 8 [(validate.rules).string.min_len = 3];
string name = 9 [(validate.rules).string = {min_len: 1, max_len: 10}];
string card = 10 [(validate.rules).string.pattern = "(?i)^[0-9a-f]+$"];
Info info = 11 [(validate.rules).message.required = true];
}
Makefile
Makefile 与 kratos 命令行工具,功能基本相同,更易于用户自行定制(本文中提到的 Makefile 相关命令均以下面的代码为准,与 layout 中不同,请注意辨别)
GOPATH:=$(shell go env GOPATH)
VERSION=$(shell git describe --tags --always)
INTERNAL_PROTO_FILES=$(shell find internal -name *.proto)
API_PROTO_FILES=$(shell find api -name *.proto)
KRATOS_VERSION=$(shell go mod graph |grep go-kratos/kratos/v2 |head -n 1 |awk -F '@' '{print $$2}')
KRATOS=$(GOPATH)/pkg/mod/github.com/go-kratos/kratos/v2@$(KRATOS_VERSION)
.PHONY: init
# init env
init:
go get -u github.com/go-kratos/kratos/cmd/kratos/v2
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
go get -u github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
go get -u github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
go get -u github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
go get -u github.com/google/wire/cmd/wire
go get -u github.com/envoyproxy/protoc-gen-validate
.PHONY: grpc
# generate grpc code
grpc:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
--go-grpc_out=paths=source_relative:. \
$(API_PROTO_FILES)
.PHONY: http
# generate http code
http:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
--go-http_out=paths=source_relative:. \
$(API_PROTO_FILES)
.PHONY: errors
# generate errors code
errors:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
--go-errors_out=paths=source_relative:. \
$(API_PROTO_FILES)
.PHONY: validate
# generate validate code
validate:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
--validate_out=paths=source_relative,lang=go:. \
$(API_PROTO_FILES)
.PHONY: proto
# generate internal proto
proto:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
$(INTERNAL_PROTO_FILES)
.PHONY: api
# generate api proto
api:
protoc --proto_path=. \
--proto_path=./third_party \
--go_out=paths=source_relative:. \
$(API_PROTO_FILES)
.PHONY: swagger
# generate swagger file
swagger:
protoc --proto_path=. \
--proto_path=./third_party \
--openapiv2_out . \
--openapiv2_opt logtostderr=true \
--openapiv2_opt json_names_for_fields=false \
$(API_PROTO_FILES)
.PHONY: generate
# generate client code
generate:
go generate ./...
.PHONY: build
# build
build:
mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./...
.PHONY: test
# test
test:
go test -v -cover ./...
.PHONY: all
# generate all
all:
make generate;
make grpc;
make http;
make errors;
make validate;
make proto;
make api;
make swagger;
make build;
make test;
# show help
help:
@echo ''
@echo 'Usage:'
@echo ' make [target]'
@echo ''
@echo 'Targets:'
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
helpMessage = match(lastLine, /^# (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")-1); \
helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help
安装步骤
安装 kratos 命令行工具
# 使用 go get
go get -u github.com/go-kratos/kratos/cmd/kratos/v2@latest
# 使用 go install, go 1.16版本后需要加上版本号 @latest 或者指定版本
go install github.com/go-kratos/kratos/cmd/kratos/v2
安装其他工具
通过 kratos 命令行工具的 upgrade 命令可以很方便的安装其他工具
kratos upgrade
也可以手动安装其他工具
go get -u github.com/go-kratos/kratos/cmd/kratos/v2
go get -u github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
go get -u github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
go get -u github.com/envoyproxy/protoc-gen-validate
# 或者通过 go install 安装,go 1.16版本后需要加上版本号 @latest 或者指定版本
go install github.com/go-kratos/kratos/cmd/kratos/v2
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
go install github.com/envoyproxy/protoc-gen-validate
实际使用
创建项目时指定自定义的模板仓库
kratos new hello -r https://github.com/xxx/xxx.git
创建项目时指定模板仓库的 tag 或 branch
kratos new hello -b test
构建 proto
构建 proto 时可以使用 kratos 命令行工具或者使用 Makefile
kratos 命令行工具
# kratos proto client xxxx 其中 xxx 可以为目录或指定文件,后面也可以透传参数
kratos client proto .
Makefile
make api
通过 proto 生成 http
定义 http 接口
// 想要使用 proto 生成 http 代码的话文件中需要 import "google/api/annotations.proto";
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
// 定义一个 GET 接口,并且把 name 映射到 HelloRequest
get: "/helloworld/{name}",
// 可以添加附加接口
additional_bindings {
// 定义一个 POST 接口,并且把 body 映射到 HelloRequest
post: "/v1/greeter/say_hello",
body: "*",
}
};
}
生成代码
kratos proto client xxx.proto --go-http_opt=omitempty=false
# 或者
make http
通过 proto 生成 errors 代码
定义错误码
enum ErrorReason {
// 设置缺省错误码
option (errors.default_code) = 500;
// 为某个枚举单独设置错误码
USER_NOT_FOUND = 0 [(errors.code) = 404];
CONTENT_MISSING = 1 [(errors.code) = 400];;
}
生成代码
errors 代码只会在 proto文件声明了错误码时才会生成
kratos proto client xxx.proto
# 或者
make errors
通过 proto 生成 validate 代码
定义 validate
message Request {
int64 id = 1 [(validate.rules).int64 = {gt: 0}];
int32 age = 2 [(validate.rules).int32 = {gt:0, lt: 120}];
uint32 code = 3 [(validate.rules).uint32 = {in: [1,2,3]}];
float score = 4 [(validate.rules).float = {not_in: [0, 99.99]}];
bool state = 5 [(validate.rules).bool.const = true];
string path = 6 [(validate.rules).string.const = "/hello"];
string phone = 7 [(validate.rules).string.len = 11];
string explain = 8 [(validate.rules).string.min_len = 3];
string name = 9 [(validate.rules).string = {min_len: 1, max_len: 10}];
string card = 10 [(validate.rules).string.pattern = "(?i)^[0-9a-f]+$"];
Info info = 11 [(validate.rules).message.required = true];
}
生成代码
validate 代码只会在 proto文件声明了参数校验规则时才会生成
kratos proto client xxx.proto
# 或者
make validate
通过 proto 生成 grpc 代码
定义 grpc 方法
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/helloworld/{name}",
};
}
}
生成代码
validate 代码只会在 proto文件声明了参数校验规则时才会生成
kratos proto client xxx.proto
# 或者
make validate
通过 proto 生成 service 代码
生成代码
kratos proto server xxx.proto -t internal/service