Compare commits

...

15 Commits

Author SHA1 Message Date
kingxt
89f3712347 remove no need empty line (#29)
* rebase upstream

* rebase

* trim no need line

* trim no need line

* trim no need line

* trim no need line

Co-authored-by: kingxt <dream4kingxt@163.com>
2020-09-01 11:08:19 +08:00
kevin
af7acdd843 fix doc errors 2020-09-01 10:26:16 +08:00
kevin
7ffa3349a9 update readme 2020-08-31 22:45:55 +08:00
kevin
f03862c378 update docs 2020-08-31 22:37:43 +08:00
kevin
fe3e70a60f update shorturl doc 2020-08-31 20:52:29 +08:00
kevin
36174ba5cc make svcCtx as a member for better code generation 2020-08-31 12:32:13 +08:00
kevin
7b17b3604a fix dockerfile generation 2020-08-31 12:27:38 +08:00
kevin
eb40c2731d remove files 2020-08-30 23:56:51 +08:00
kevin
618bec5075 remove makefile generation 2020-08-30 23:52:51 +08:00
kevin
5821b7324e update readme 2020-08-30 23:34:57 +08:00
kevin
befdaab542 update goctl makefile 2020-08-30 18:22:46 +08:00
kevin
431be8ed9d make goctl work on linux 2020-08-30 16:37:34 +08:00
kevin
3c688c319e update shorturl doc 2020-08-29 23:42:42 +08:00
kevin
59ffa75c00 fix typo in doc 2020-08-29 23:33:34 +08:00
kevin
09340e82a7 fix doc error 2020-08-29 22:51:48 +08:00
43 changed files with 254 additions and 1304 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -1,50 +1,77 @@
# 使用go-zero从0到1快速构建高并发的短链服务
# 快速构建高并发服务
## 0. 什么是短链服务
## 0. 什么说做好微服务很难
要想做好微服务,我们需要理解和掌握的知识点非常多,从几个维度上来说:
* 基本功能层面
1. 并发控制&限流,避免服务被突发流量击垮
2. 服务注册与服务发现,确保能够动态侦测增减的节点
3. 负载均衡,需要根据节点承受能力分发流量
4. 超时控制,避免对已超时请求做无用功
5. 熔断设计,快速失败,保障故障节点的恢复能力
* 高阶功能层面
1. 请求认证,确保每个用户只能访问自己的数据
2. 链路追踪,用于理解整个系统和快速定位特定请求的问题
3. 日志,用于数据收集和问题定位
4. 可观测性,没有度量就没有优化
对于其中每一点,我们都需要用很长的篇幅来讲述其原理和实现,那么对我们后端开发者来说,要想把这些知识点都掌握并落实到业务系统里,难度是非常大的,不过我们可以依赖已经被大流量验证过的框架体系。[go-zero微服务框架](https://github.com/tal-tech/go-zero)就是为此而生。
另外,我们始终秉承**工具大于约定和文档**的理念。我们希望尽可能减少开发人员的心智负担,把精力都投入到产生业务价值的代码上,减少重复代码的编写,所以我们开发了`goctl`工具。
下面我通过短链微服务来演示通过[go-zero](https://github.com/tal-tech/go-zero)快速的创建微服务的流程,走完一遍,你就会发现:原来编写微服务如此简单!
## 1. 什么是短链服务?
短链服务就是将长的URL网址通过程序计算等方式转换为简短的网址字符串。
写此短链服务是为了从整体上演示go-zero构建完整微服务的过程算法和实现细节尽可能简化了所以这不是一个高阶的短链服务。
## 1. 短链微服务架构图
## 2. 短链微服务架构图
<img src="images/shorturl-arch.png" alt="架构图" width="800" />
## 2. 准备工作
* 这里只用了`Transform RPC`一个微服务并不是说API Gateway只能调用一个微服务只是为了最简演示API Gateway如何调用RPC微服务而已
* 在真正项目里要尽可能每个微服务使用自己的数据库,数据边界要清晰
## 3. 准备工作
* 安装etcd, mysql, redis
* 准备goctl工具
* 直接从`https://github.com/tal-tech/go-zero/releases`下载最新版,后续会加上自动更新
* 也可以从源码编译在任意目录下进行目的是为了编译goctl工具
1. `git clone https://github.com/tal-tech/go-zero`
2.`tools/goctl`目录下编译goctl工具`go build goctl.go`
3. 将生成的goctl放到`$PATH`确保goctl命令可运行
* 安装goctl工具
```shell
export GO111MODULE=on export GOPROXY=https://goproxy.cn/,direct go get github.com/tal-tech/go-zero/tools/goctl
```
* 创建工作目录`shorturl`
* 在`shorturl`目录下执行`go mod init shorturl`初始化`go.mod`
## 3. 编写API Gateway代码
## 4. 编写API Gateway代码
* 通过goctl生成`shorturl.api`并编辑,为了简洁,去除了文件开头的`info`,代码如下:
* 通过goctl生成`api/shorturl.api`并编辑,为了简洁,去除了文件开头的`info`,代码如下:
```go
type (
expandReq struct {
shorten string `form:"shorten"`
}
expandResp struct {
url string `json:"url"`
}
)
type (
shortenReq struct {
url string `form:"url"`
}
shortenResp struct {
shortUrl string `json:"shortUrl"`
}
)
type (
expandReq struct {
key string `form:"key"`
}
expandResp struct {
url string `json:"url"`
shorten string `json:"shorten"`
}
)
@@ -71,7 +98,7 @@
* 使用goctl生成API Gateway代码
```shell
goctl api go -api shorturl.api -dir api
goctl api go -api shorturl.api -dir .
```
生成的文件结构如下:
@@ -95,16 +122,16 @@
│   │   │   └── servicecontext.go // 定义ServiceContext
│   │   └── types
│   │   └── types.go // 定义请求、返回结构体
│   ├── shorturl.api
│   └── shorturl.go // main入口定义
├── go.mod
── go.sum
└── shorturl.api
── go.sum
```
* 启动API Gateway服务默认侦听在8888端口
```shell
go run api/shorturl.go -f api/etc/shorturl-api.yaml
go run shorturl.go -f etc/shorturl-api.yaml
```
* 测试API Gateway服务
@@ -134,14 +161,14 @@
* 到这里你已经可以通过goctl生成客户端代码给客户端同学并行开发了支持多种语言详见文档
## 4. 编写shorten rpc服务
## 5. 编写transform rpc服务
* 在`rpc/shorten`目录下编写`shorten.proto`文件
* 在`rpc/transform`目录下编写`transform.proto`文件
可以通过命令生成proto文件模板
```shell
goctl rpc template -o shorten.proto
goctl rpc template -o transform.proto
```
修改后文件内容如下:
@@ -149,183 +176,120 @@
```protobuf
syntax = "proto3";
package shorten;
message shortenReq {
string url = 1;
}
message shortenResp {
string key = 1;
}
service shortener {
rpc shorten(shortenReq) returns(shortenResp);
}
```
* 用`goctl`生成rpc代码在`rpc/shorten`目录下执行命令
```shell
goctl rpc proto -src shorten.proto
```
文件结构如下:
```
rpc/shorten
├── etc
│   └── shorten.yaml // 配置文件
├── internal
│   ├── config
│   │   └── config.go // 配置定义
│   ├── logic
│   │   └── shortenlogic.go // rpc业务逻辑在这里实现
│   ├── server
│   │   └── shortenerserver.go // 调用入口, 不需要修改
│   └── svc
│   └── servicecontext.go // 定义ServiceContext传递依赖
├── pb
│   └── shorten.pb.go
├── shorten.go // rpc服务main函数
├── shorten.proto
└── shortener
├── shortener.go // 提供了外部调用方法,无需修改
├── shortener_mock.go // mock方法测试用
└── types.go // request/response结构体定义
```
直接可以运行,如下:
```shell
$ go run shorten.go -f etc/shorten.yaml
Starting rpc server at 127.0.0.1:8080...
```
`etc/shorten.yaml`文件里可以修改侦听端口等配置
## 5. 编写expand rpc服务
* 在`rpc/expand`目录下编写`expand.proto`文件
可以通过命令生成proto文件模板
```shell
goctl rpc template -o expand.proto
```
修改后文件内容如下:
```protobuf
syntax = "proto3";
package expand;
package transform;
message expandReq {
string key = 1;
string shorten = 1;
}
message expandResp {
string url = 1;
}
service expander {
message shortenReq {
string url = 1;
}
message shortenResp {
string shorten = 1;
}
service transformer {
rpc expand(expandReq) returns(expandResp);
rpc shorten(shortenReq) returns(shortenResp);
}
```
* 用`goctl`生成rpc代码在`rpc/expand`目录下执行命令
* 用`goctl`生成rpc代码在`rpc/transform`目录下执行命令
```shell
goctl rpc proto -src expand.proto
goctl rpc proto -src transform.proto
```
文件结构如下:
```
rpc/expand
rpc/transform
├── etc
│   └── expand.yaml // 配置文件
├── expand.go // rpc服务main函数
├── expand.proto
├── expander
│   ├── expander.go // 提供了外部调用方法,无需修改
│   ├── expander_mock.go // mock方法测试用
│   └── types.go // request/response结构体定义
│   └── transform.yaml // 配置文件
├── internal
│   ├── config
│   │   └── config.go // 配置定义
│   │   └── config.go // 配置定义
│   ├── logic
│   │   ── expandlogic.go // rpc业务逻辑在这里实现
│   │   ── expandlogic.go // expand业务逻辑在这里实现
│   │   └── shortenlogic.go // shorten业务逻辑在这里实现
│   ├── server
│   │   └── expanderserver.go // 调用入口, 不需要修改
│   │   └── transformerserver.go // 调用入口, 不需要修改
│   └── svc
│   └── servicecontext.go // 定义ServiceContext传递依赖
── pb
└── expand.pb.go
│   └── servicecontext.go // 定义ServiceContext传递依赖
── pb
│   └── transform.pb.go
├── transform.go // rpc服务main函数
├── transform.proto
└── transformer
├── transformer.go // 提供了外部调用方法,无需修改
├── transformer_mock.go // mock方法测试用
└── types.go // request/response结构体定义
```
修改`etc/expand.yaml`里面的`ListenOn`的端口为`8081`,因为`8080`已经被`shorten`服务占用了
修改后运行,如下:
直接可以运行,如下:
```shell
$ go run expand.go -f etc/expand.yaml
Starting rpc server at 127.0.0.1:8081...
$ go run transform.go -f etc/transform.yaml
Starting rpc server at 127.0.0.1:8080...
```
`etc/expand.yaml`文件里可以修改侦听端口等配置
## 6. 修改API Gateway代码调用shorten/expand rpc服务
`etc/transform.yaml`文件里可以修改侦听端口等配置
* 修改配置文件`shorter-api.yaml`,增加如下内容
## 6. 修改API Gateway代码调用transform rpc服务
* 修改配置文件`shorturl-api.yaml`,增加如下内容
```yaml
Shortener:
Transform:
Etcd:
Hosts:
- localhost:2379
Key: shorten.rpc
Expander:
Etcd:
Hosts:
- localhost:2379
Key: expand.rpc
Key: transform.rpc
```
通过etcd自动去发现可用的shorten/expand服务
通过etcd自动去发现可用的transform服务
* 修改`internal/config/config.go`如下,增加shorten/expand服务依赖
* 修改`internal/config/config.go`如下,增加transform服务依赖
```go
type Config struct {
rest.RestConf
Shortener rpcx.RpcClientConf // 手动代码
Expander rpcx.RpcClientConf // 手动代码
Transform rpcx.RpcClientConf // 手动代码
}
```
* 修改`internal/logic/expandlogic.go`,如下:
* 修改`internal/svc/servicecontext.go`,如下:
```go
type ExpandLogic struct {
ctx context.Context
logx.Logger
expander rpcx.Client // 手动代码
type ServiceContext struct {
Config config.Config
Transformer rpcx.Client // 手动代码
}
func NewExpandLogic(ctx context.Context, svcCtx *svc.ServiceContext) ExpandLogic {
return ExpandLogic{
ctx: ctx,
Logger: logx.WithContext(ctx),
expander: svcCtx.Expander, // 手动代码
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
Transformer: rpcx.MustNewClient(c.Transform), // 手动代码
}
}
```
通过ServiceContext在不同业务逻辑之间传递依赖
* 修改`internal/logic/expandlogic.go`里的`Expand`方法,如下:
```go
func (l *ExpandLogic) Expand(req types.ExpandReq) (*types.ExpandResp, error) {
// 手动代码开始
resp, err := expander.NewExpander(l.expander).Expand(l.ctx, &expander.ExpandReq{
Key: req.Key,
trans := transformer.NewTransformer(l.svcCtx.Transformer)
resp, err := trans.Expand(l.ctx, &transformer.ExpandReq{
Shorten: req.Shorten,
})
if err != nil {
return nil, err
@@ -338,28 +302,15 @@
}
```
增加了对`expander`服务的依赖,并通过调用`expander`的`Expand`方法实现短链恢复到url
通过调用`transformer`的`Expand`方法实现短链恢复到url
* 修改`internal/logic/shortenlogic.go`,如下:
```go
type ShortenLogic struct {
ctx context.Context
logx.Logger
shortener rpcx.Client // 手动代码
}
func NewShortenLogic(ctx context.Context, svcCtx *svc.ServiceContext) ShortenLogic {
return ShortenLogic{
ctx: ctx,
Logger: logx.WithContext(ctx),
shortener: svcCtx.Shortener, // 手动代码
}
}
func (l *ShortenLogic) Shorten(req types.ShortenReq) (*types.ShortenResp, error) {
// 手动代码开始
resp, err := shortener.NewShortener(l.shortener).Shorten(l.ctx, &shortener.ShortenReq{
trans := transformer.NewTransformer(l.svcCtx.Transformer)
resp, err := trans.Shorten(l.ctx, &transformer.ShortenReq{
Url: req.Url,
})
if err != nil {
@@ -367,49 +318,28 @@
}
return &types.ShortenResp{
ShortUrl: resp.Key,
Shorten: resp.Shorten,
}, nil
// 手动代码结束
}
```
增加了对`shortener`服务的依赖,并通过调用`shortener`的`Shorten`方法实现url到短链的变换
* 修改`internal/svc/servicecontext.go`,如下:
```go
type ServiceContext struct {
Config config.Config
Shortener rpcx.Client // 手动代码
Expander rpcx.Client // 手动代码
}
func NewServiceContext(config config.Config) *ServiceContext {
return &ServiceContext{
Config: config,
Shortener: rpcx.MustNewClient(config.Shortener), // 手动代码
Expander: rpcx.MustNewClient(config.Expander), // 手动代码
}
}
```
通过ServiceContext在不同业务逻辑之间传递依赖
通过调用`transformer`的`Shorten`方法实现url到短链的变换
至此API Gateway修改完成虽然贴的代码多但是期中修改的是很少的一部分为了方便理解上下文我贴了完整代码接下来处理CRUD+cache
## 7. 定义数据库表结构并生成CRUD+cache代码
* shorturl下创建rpc/model目录`mkdir -p rpc/model`
* 在roc/model目录下编写创建shorturl表的sql文件`shorturl.sql`,如下:
* shorturl下创建`rpc/transform/model`目录:`mkdir -p rpc/transform/model`
* 在rpc/transform/model目录下编写创建shorturl表的sql文件`shorturl.sql`,如下:
```sql
CREATE TABLE `shorturl`
(
`id` bigint(10) NOT NULL AUTO_INCREMENT,
`key` varchar(255) NOT NULL DEFAULT '' COMMENT 'shorten key',
`url` varchar(255) DEFAULT '' COMMENT 'original url',
PRIMARY KEY(`id`),
UNIQUE KEY `key_index`(`key`)
`shorten` varchar(255) NOT NULL COMMENT 'shorten key',
`url` varchar(255) NOT NULL COMMENT 'original url',
PRIMARY KEY(`shorten`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
@@ -423,18 +353,18 @@
source shorturl.sql;
```
* 在`rpc/model`目录下执行如下命令生成CRUD+cache代码`-c`表示使用`redis cache`
* 在`rpc/transform/model`目录下执行如下命令生成CRUD+cache代码`-c`表示使用`redis cache`
```shell
goctl model mysql ddl -c -src shorturl.sql -dir .
```
也可以用`datasource`命令代替`ddl`来指定数据库链接直接从schema生成
生成后的文件结构如下:
```
rpc/model
rpc/transform/model
├── shorturl.sql
├── shorturlmodel.go // CRUD+cache代码
└── vars.go // 定义常量和变量
@@ -442,7 +372,7 @@
## 8. 修改shorten/expand rpc代码调用crud+cache代码
* 修改`rpc/expand/etc/expand.yaml`,增加如下内容:
* 修改`rpc/transform/etc/transform.yaml`,增加如下内容:
```yaml
DataSource: root:@tcp(localhost:3306)/gozero
@@ -453,7 +383,7 @@
可以使用多个redis作为cache支持redis单点或者redis集群
* 修改`rpc/expand/internal/config.go`,如下:
* 修改`rpc/transform/internal/config.go`,如下:
```go
type Config struct {
@@ -466,116 +396,46 @@
增加了mysql和redis cache配置
* 修改`rpc/expand/internal/svc/servicecontext.go`,如下:
* 修改`rpc/transform/internal/svc/servicecontext.go`,如下:
```go
type ServiceContext struct {
c config.Config
Model *model.ShorturlModel // 手动代码
Model *model.ShorturlModel // 手动代码
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
c: c,
c: c,
Model: model.NewShorturlModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), // 手动代码
}
}
```
* 修改`rpc/expand/internal/logic/expandlogic.go`,如下:
* 修改`rpc/transform/internal/logic/expandlogic.go`,如下:
```go
type ExpandLogic struct {
ctx context.Context
logx.Logger
model *model.ShorturlModel // 手动代码
}
func NewExpandLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ExpandLogic {
return &ExpandLogic{
ctx: ctx,
Logger: logx.WithContext(ctx),
model: svcCtx.Model, // 手动代码
}
}
func (l *ExpandLogic) Expand(in *expand.ExpandReq) (*expand.ExpandResp, error) {
// 手动代码开始
res, err := l.model.FindOne(in.Key)
// 手动代码开始
res, err := l.svcCtx.Model.FindOne(in.Shorten)
if err != nil {
return nil, err
}
return &expand.ExpandResp{
return &transform.ExpandResp{
Url: res.Url,
}, nil
// 手动代码结束
}
```
* 修改`rpc/shorten/etc/shorten.yaml`,增加如下内容:
```yaml
DataSource: root:@tcp(localhost:3306)/gozero
Table: shorturl
Cache:
- Host: localhost:6379
```
可以使用多个redis作为cache支持redis单点或者redis集群
* 修改`rpc/shorten/internal/config.go`,如下:
```go
type Config struct {
rpcx.RpcServerConf
DataSource string // 手动代码
Table string // 手动代码
Cache cache.CacheConf // 手动代码
}
```
增加了mysql和redis cache配置
* 修改`rpc/shorten/internal/svc/servicecontext.go`,如下:
```go
type ServiceContext struct {
c config.Config
Model *model.ShorturlModel // 手动代码
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
c: c,
Model: model.NewShorturlModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), // 手动代码
}
// 手动代码结束
}
```
* 修改`rpc/shorten/internal/logic/shortenlogic.go`,如下:
```go
const keyLen = 6
type ShortenLogic struct {
ctx context.Context
logx.Logger
model *model.ShorturlModel // 手动代码
}
func NewShortenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ShortenLogic {
return &ShortenLogic{
ctx: ctx,
Logger: logx.WithContext(ctx),
model: svcCtx.Model, // 手动代码
}
}
func (l *ShortenLogic) Shorten(in *shorten.ShortenReq) (*shorten.ShortenResp, error) {
// 手动代码开始,生成短链接
key := hash.Md5Hex([]byte(in.Url))[:keyLen]
_, err := l.model.Insert(model.Shorturl{
key := hash.Md5Hex([]byte(in.Url))[:6]
_, err := l.svcCtx.Model.Insert(model.Shorturl{
Shorten: key,
Url: in.Url,
})
@@ -583,8 +443,8 @@
return nil, err
}
return &shorten.ShortenResp{
Key: key,
return &transform.ShortenResp{
Shorten: key,
}, nil
// 手动代码结束
}
@@ -597,7 +457,7 @@
* shorten api调用
```shell
~ curl -i "http://localhost:8888/shorten?url=http://www.xiaoheiban.cn"
curl -i "http://localhost:8888/shorten?url=http://www.xiaoheiban.cn"
```
返回如下:
@@ -608,13 +468,13 @@
Date: Sat, 29 Aug 2020 10:49:49 GMT
Content-Length: 21
{"shortUrl":"f35b2a"}
{"shorten":"f35b2a"}
```
* expand api调用
```shell
curl -i "http://localhost:8888/expand?key=f35b2a"
curl -i "http://localhost:8888/expand?shorten=f35b2a"
```
返回如下:

View File

@@ -1,13 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
#docker pull alpine
#docker pull golang:alpine
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/etcdmon:$(version) . -f example/etcd/demo/Dockerfile
#docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/etcdmon:$(version)
deploy: push
kubectl -n xx-xiaoheiban set image deployment/etcdmon-deployment etcdmon=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcdmon:$(version)

View File

@@ -1,15 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: etcdmon
namespace: discov
spec:
containers:
- name: etcdmon
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcdmon:v200620093045
imagePullPolicy: Always
env:
- name: ETCD_CLUSTER
value: etcd.discov:2379
imagePullSecrets:
- name: aliyun

View File

@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: discovery

View File

@@ -1,378 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: discov
namespace: discovery
spec:
ports:
- name: discov-port
port: 2379
protocol: TCP
targetPort: 2379
selector:
app: discov
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: discov
discov_node: discov0
name: discov0
namespace: discovery
spec:
containers:
- command:
- /usr/local/bin/etcd
- --name
- discov0
- --initial-advertise-peer-urls
- http://discov0:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://discov0:2379
- --initial-cluster
- discov0=http://discov0:2380,discov1=http://discov1:2380,discov2=http://discov2:2380,discov3=http://discov3:2380,discov4=http://discov4:2380
- --initial-cluster-state
- new
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcd:latest
name: discov0
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
imagePullSecrets:
- name: aliyun
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- discov
topologyKey: "kubernetes.io/hostname"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
discov_node: discov0
name: discov0
namespace: discovery
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: server
port: 2380
protocol: TCP
targetPort: 2380
selector:
discov_node: discov0
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: discov
discov_node: discov1
name: discov1
namespace: discovery
spec:
containers:
- command:
- /usr/local/bin/etcd
- --name
- discov1
- --initial-advertise-peer-urls
- http://discov1:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://discov1:2379
- --initial-cluster
- discov0=http://discov0:2380,discov1=http://discov1:2380,discov2=http://discov2:2380,discov3=http://discov3:2380,discov4=http://discov4:2380
- --initial-cluster-state
- new
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcd:latest
name: discov1
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
imagePullSecrets:
- name: aliyun
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- discov
topologyKey: "kubernetes.io/hostname"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
discov_node: discov1
name: discov1
namespace: discovery
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: server
port: 2380
protocol: TCP
targetPort: 2380
selector:
discov_node: discov1
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: discov
discov_node: discov2
name: discov2
namespace: discovery
spec:
containers:
- command:
- /usr/local/bin/etcd
- --name
- discov2
- --initial-advertise-peer-urls
- http://discov2:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://discov2:2379
- --initial-cluster
- discov0=http://discov0:2380,discov1=http://discov1:2380,discov2=http://discov2:2380,discov3=http://discov3:2380,discov4=http://discov4:2380
- --initial-cluster-state
- new
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcd:latest
name: discov2
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
imagePullSecrets:
- name: aliyun
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- discov
topologyKey: "kubernetes.io/hostname"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
discov_node: discov2
name: discov2
namespace: discovery
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: server
port: 2380
protocol: TCP
targetPort: 2380
selector:
discov_node: discov2
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: discov
discov_node: discov3
name: discov3
namespace: discovery
spec:
containers:
- command:
- /usr/local/bin/etcd
- --name
- discov3
- --initial-advertise-peer-urls
- http://discov3:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://discov3:2379
- --initial-cluster
- discov0=http://discov0:2380,discov1=http://discov1:2380,discov2=http://discov2:2380,discov3=http://discov3:2380,discov4=http://discov4:2380
- --initial-cluster-state
- new
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcd:latest
name: discov3
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
imagePullSecrets:
- name: aliyun
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- discov
topologyKey: "kubernetes.io/hostname"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
discov_node: discov3
name: discov3
namespace: discovery
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: server
port: 2380
protocol: TCP
targetPort: 2380
selector:
discov_node: discov3
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: discov
discov_node: discov4
name: discov4
namespace: discovery
spec:
containers:
- command:
- /usr/local/bin/etcd
- --name
- discov4
- --initial-advertise-peer-urls
- http://discov4:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://discov4:2379
- --initial-cluster
- discov0=http://discov0:2380,discov1=http://discov1:2380,discov2=http://discov2:2380,discov3=http://discov3:2380,discov4=http://discov4:2380
- --initial-cluster-state
- new
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/etcd:latest
name: discov4
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: server
protocol: TCP
imagePullSecrets:
- name: aliyun
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- discov
topologyKey: "kubernetes.io/hostname"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
discov_node: discov4
name: discov4
namespace: discovery
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: server
port: 2380
protocol: TCP
targetPort: 2380
selector:
discov_node: discov4

View File

@@ -1,11 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/pub:$(version) . -f example/etcd/pub/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/pub:$(version)
deploy: push
kubectl -n adhoc set image deployment/pub-deployment pub=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/pub:$(version)

View File

@@ -1,26 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: pub-deployment
namespace: adhoc
labels:
app: pub
spec:
replicas: 1
selector:
matchLabels:
app: pub
template:
metadata:
labels:
app: pub
spec:
containers:
- name: pub
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/pub:v200213172101
command:
- /app/pub
- -v
- ccc
imagePullSecrets:
- name: aliyun

View File

@@ -1,11 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/sub:$(version) . -f example/etcd/sub/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/sub:$(version)
deploy: push
kubectl -n adhoc set image deployment/sub-deployment sub=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/sub:$(version)

View File

@@ -1,16 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
labels:
app: sub
name: sub
namespace: adhoc
spec:
containers:
- command:
- /app/sub
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/sub:v200213220509
name: sub
imagePullSecrets:
- name: aliyun
restartPolicy: Always

View File

@@ -1,11 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
docker pull alpine
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version) . -f example/graceful/dns/api/Dockerfile
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version)
deploy: push
kubectl -n kevin set image deployment/graceful-deployment graceful=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version)

View File

@@ -1,42 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: graceful
namespace: kevin
spec:
selector:
app: graceful
type: ClusterIP
ports:
- name: graceful-port
port: 3333
targetPort: 8888
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: graceful-deployment
namespace: kevin
labels:
app: graceful
spec:
replicas: 3
selector:
matchLabels:
app: graceful
template:
metadata:
labels:
app: graceful
spec:
containers:
- name: graceful
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/graceful:v191022133857
imagePullPolicy: Always
ports:
- containerPort: 8888
imagePullSecrets:
- name: aliyun

View File

@@ -1,11 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
docker pull alpine
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version) . -f example/graceful/dns/rpc/Dockerfile
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version)
deploy: push
kubectl -n kevin set image deployment/gracefulrpc-deployment gracefulrpc=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version)

View File

@@ -1,46 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: gracefulrpc
namespace: kevin
spec:
selector:
app: gracefulrpc
type: ClusterIP
clusterIP: None
ports:
- name: gracefulrpc-port
port: 3456
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gracefulrpc-deployment
namespace: kevin
labels:
app: gracefulrpc
spec:
replicas: 3
selector:
matchLabels:
app: gracefulrpc
template:
metadata:
labels:
app: gracefulrpc
spec:
containers:
- name: gracefulrpc
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:v191022143425
imagePullPolicy: Always
ports:
- containerPort: 3456
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
imagePullSecrets:
- name: aliyun

View File

@@ -1,13 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
docker pull alpine
docker pull golang:alpine
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version) . -f example/graceful/etcd/api/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version)
deploy: push
kubectl -n kevin set image deployment/graceful-deployment graceful=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/graceful:$(version)

View File

@@ -1,42 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: graceful
namespace: kevin
spec:
selector:
app: graceful
type: ClusterIP
ports:
- name: graceful-port
port: 3333
targetPort: 8888
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: graceful-deployment
namespace: kevin
labels:
app: graceful
spec:
replicas: 3
selector:
matchLabels:
app: graceful
template:
metadata:
labels:
app: graceful
spec:
containers:
- name: graceful
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/graceful:v191031145905
imagePullPolicy: Always
ports:
- containerPort: 8888
imagePullSecrets:
- name: aliyun

View File

@@ -1,13 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
docker pull alpine
docker pull golang:alpine
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version) . -f example/graceful/etcd/rpc/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version)
deploy: push
kubectl -n kevin set image deployment/gracefulrpc-deployment gracefulrpc=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:$(version)

View File

@@ -1,30 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gracefulrpc-deployment
namespace: kevin
labels:
app: gracefulrpc
spec:
replicas: 9
selector:
matchLabels:
app: gracefulrpc
template:
metadata:
labels:
app: gracefulrpc
spec:
containers:
- name: gracefulrpc
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:v191031144304
imagePullPolicy: Always
ports:
- containerPort: 3456
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
imagePullSecrets:
- name: aliyun

View File

@@ -1,41 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: gracefulrpc
namespace: kevin
spec:
selector:
app: gracefulrpc
type: ClusterIP
clusterIP: None
ports:
- name: gracefulrpc-port
port: 3456
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gracefulrpc-deployment
namespace: kevin
labels:
app: gracefulrpc
spec:
replicas: 9
selector:
matchLabels:
app: gracefulrpc
template:
metadata:
labels:
app: gracefulrpc
spec:
containers:
- name: gracefulrpc
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:v191031144304
imagePullPolicy: Always
ports:
- containerPort: 3456
imagePullSecrets:
- name: aliyun

View File

@@ -1,25 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gracefulrpc-deployment
namespace: kevin
labels:
app: gracefulrpc
spec:
replicas: 9
selector:
matchLabels:
app: gracefulrpc
template:
metadata:
labels:
app: gracefulrpc
spec:
containers:
- name: gracefulrpc
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/gracefulrpc:v191031144304
imagePullPolicy: Always
ports:
- containerPort: 3456
imagePullSecrets:
- name: aliyun

View File

@@ -1,13 +0,0 @@
version := v1
build:
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/shedding:$(version) . -f example/load/simulate/cpu/Dockerfile
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/shedding:$(version)
deploy: push
kubectl apply -f shedding.yaml
clean:
kubectl delete -f shedding.yaml

View File

@@ -1,17 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: shedding
namespace: adhoc
spec:
containers:
- name: shedding
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/shedding:v1
imagePullPolicy: Always
resources:
requests:
cpu: 1000m
limits:
cpu: 1000m
imagePullSecrets:
- name: aliyun

View File

@@ -1,10 +0,0 @@
version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/unarydirect:$(version) . -f example/rpc/client/direct/Dockerfile
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/unarydirect:$(version)
deploy: push
kubectl -n adhoc set image deployment/unarydirect-deployment unarydirect=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/unarydirect:$(version)

View File

@@ -1,23 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: unarydirect-deployment
namespace: adhoc
labels:
app: unarydirect
spec:
replicas: 1
selector:
matchLabels:
app: unarydirect
template:
metadata:
labels:
app: unarydirect
spec:
containers:
- name: unarydirect
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/unarydirect:v1
imagePullPolicy: Always
imagePullSecrets:
- name: aliyun

View File

@@ -1,46 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: unaryproxy
namespace: kevin
spec:
selector:
app: unaryproxy
ports:
- name: unaryproxy-port
port: 3456
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: unaryproxy-deployment
namespace: kevin
labels:
app: unaryproxy
spec:
replicas: 3
selector:
matchLabels:
app: unaryproxy
template:
metadata:
labels:
app: unaryproxy
spec:
containers:
- name: unaryproxy
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/unaryproxy:v1
imagePullPolicy: Always
ports:
- containerPort: 3456
volumeMounts:
- name: timezone
mountPath: /etc/localtime
imagePullSecrets:
- name: aliyun
volumes:
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai

View File

@@ -1,11 +0,0 @@
version := v1
build:
cd $(GOPATH)/src/zero && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/unaryserver:$(version) . -f example/rpc/server/unary/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/unaryserver:$(version)
deploy: push
kubectl -n adhoc set image deployment/unaryserver-deployment unaryserver=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/unaryserver:$(version)

View File

@@ -1,25 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: unaryserver-deployment
namespace: adhoc
labels:
app: unaryserver
spec:
replicas: 3
selector:
matchLabels:
app: unaryserver
template:
metadata:
labels:
app: unaryserver
spec:
containers:
- name: unaryserver
image: registry-vpc.cn-hangzhou.aliyuncs.com/xapp/unaryserver:v1
imagePullPolicy: Always
ports:
- containerPort: 3456
imagePullSecrets:
- name: aliyun

View File

@@ -89,15 +89,17 @@ go get -u github.com/tal-tech/go-zero
## 6. Quick Start
0. 完整示例请查看[从0到1快速构建一个高并发的微服务系统](doc/shorturl.md)
0. 完整示例请查看
1. 编译goctl工具
[快速构建高并发微服务](doc/shorturl.md)
1. 安装goctl工具
```shell
go build tools/goctl/goctl.go
export GO111MODULE=on export GOPROXY=https://goproxy.cn/,direct go get github.com/tal-tech/go-zero/tools/goctl
```
把goctl放到$PATH的目录下确保goctl可执行
确保goctl可执行
2. 定义API文件比如greet.api可以在vs code里安装`goctl`插件支持api语法
@@ -135,7 +137,7 @@ go get -u github.com/tal-tech/go-zero
```
├── greet
│   ├── etc
│   │   └── greet-api.json // 配置文件
│   │   └── greet-api.yaml // 配置文件
│   ├── greet.go // main文件
│   └── internal
│   ├── config
@@ -152,18 +154,24 @@ go get -u github.com/tal-tech/go-zero
└── greet.api // api描述文件
```
生成的代码可以直接运行:
```shell
cd greet
go run greet.go -f etc/greet-api.json
go run greet.go -f etc/greet-api.yaml
```
默认侦听在8888端口可以在配置文件里修改可以通过curl请求
```shell
➜ go-zero git:(master) curl -w "\ncode: %{http_code}\n" http://localhost:8888/greet/from/kevin
{"code":0}
code: 200
curl -i http://localhost:8888/greet/from/you
```
返回如下:
```http
HTTP/1.1 200 OK
Date: Sun, 30 Aug 2020 15:32:35 GMT
Content-Length: 0
```
编写业务代码:
@@ -187,7 +195,7 @@ go get -u github.com/tal-tech/go-zero
## 8. 文档 (逐步完善中)
* [从0到1快速构建一个高并发微服务系统](doc/shorturl.md)
* [快速构建高并发微服务](doc/shorturl.md)
* [goctl使用帮助](doc/goctl.md)
* [关键字替换和敏感词过滤工具](doc/keywords.md)

View File

@@ -2,3 +2,9 @@ version := $(shell /bin/date "+%Y-%m-%d %H:%M")
build:
go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" goctl.go && upx goctl
mac:
GOOS=darwin go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-darwin goctl.go && upx goctl-darwin
win:
GOOS=windows go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl.exe goctl.go && upx goctl.exe
linux:
GOOS=linux go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-linux goctl.go && upx goctl-linux

View File

@@ -98,6 +98,7 @@ func ApiFormat(path string, printToConsole bool) error {
_, err := fmt.Print(result)
return err
}
result = strings.TrimSpace(result)
return ioutil.WriteFile(path, []byte(result), os.ModePerm)
}

View File

@@ -141,23 +141,26 @@ func createGoModFileIfNeed(dir string) {
}
_, hasGoMod := util.FindGoModPath(dir)
if !hasGoMod {
gopath := os.Getenv("GOPATH")
parent := path.Join(gopath, "src")
pos := strings.Index(absDir, parent)
if pos < 0 {
moduleName := absDir[len(filepath.Dir(absDir))+1:]
cmd := exec.Command("go", "mod", "init", moduleName)
cmd.Dir = dir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
fmt.Println(err.Error())
}
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
fmt.Printf(outStr + "\n" + errStr)
}
if hasGoMod {
return
}
gopath := os.Getenv("GOPATH")
parent := path.Join(gopath, "src")
pos := strings.Index(absDir, parent)
if pos >= 0 {
return
}
moduleName := absDir[len(filepath.Dir(absDir))+1:]
cmd := exec.Command("go", "mod", "init", moduleName)
cmd.Dir = dir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err = cmd.Run(); err != nil {
fmt.Println(err.Error())
}
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
fmt.Printf(outStr + "\n" + errStr)
}

View File

@@ -20,18 +20,22 @@ import (
)
type {{.logic}} struct {
ctx context.Context
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) {{.logic}} {
return {{.logic}}{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
// todo: add your logic here and delete this line
{{.returnString}}
}
`

View File

@@ -22,7 +22,7 @@ func getParentPackage(dir string) (string, error) {
}
absDir = strings.ReplaceAll(absDir, `\`, `/`)
var rootPath, hasGoMod = goctlutil.FindGoModPath(dir)
rootPath, hasGoMod := goctlutil.FindGoModPath(dir)
if hasGoMod {
return rootPath, nil
}
@@ -32,7 +32,7 @@ func getParentPackage(dir string) (string, error) {
pos := strings.Index(absDir, parent)
if pos < 0 {
fmt.Printf("%s not in go.mod project path, or not in GOPATH of %s directory\n", absDir, gopath)
var tempPath = filepath.Dir(absDir)
tempPath := filepath.Dir(absDir)
rootPath = absDir[len(tempPath)+1:]
} else {
rootPath = absDir[len(parent)+1:]
@@ -61,7 +61,7 @@ func writeProperty(writer io.Writer, name, tp, tag, comment string, indent int)
}
func getAuths(api *spec.ApiSpec) []string {
var authNames = collection.NewSet()
authNames := collection.NewSet()
for _, g := range api.Service.Groups {
if value, ok := util.GetAnnotationValue(g.Annotations, "server", "jwt"); ok {
authNames.Add(value)
@@ -78,5 +78,6 @@ func formatCode(code string) string {
if err != nil {
return code
}
return string(ret)
}

View File

@@ -9,14 +9,9 @@ import (
func DockerCommand(c *cli.Context) error {
goFile := c.String("go")
namespace := c.String("namespace")
if len(goFile) == 0 || len(namespace) == 0 {
return errors.New("-go and -namespace can't be empty")
if len(goFile) == 0 {
return errors.New("-go can't be empty")
}
if err := gen.GenerateDockerfile(goFile, "-f", "etc/config.json"); err != nil {
return err
}
return gen.GenerateMakefile(goFile, namespace)
return gen.GenerateDockerfile(goFile, "-f", "etc/config.yaml")
}

View File

@@ -1,6 +1,7 @@
package gen
import (
"path/filepath"
"strings"
"text/template"
@@ -9,11 +10,16 @@ import (
)
func GenerateDockerfile(goFile string, args ...string) error {
relPath, err := util.PathFromGoSrc()
projPath, err := getFilePath(filepath.Dir(goFile))
if err != nil {
return err
}
pos := strings.IndexByte(projPath, '/')
if pos >= 0 {
projPath = projPath[pos+1:]
}
out, err := util.CreateIfNotExist("Dockerfile")
if err != nil {
return err
@@ -28,7 +34,7 @@ func GenerateDockerfile(goFile string, args ...string) error {
t := template.Must(template.New("dockerfile").Parse(dockerTemplate))
return t.Execute(out, map[string]string{
"projectName": vars.ProjectName,
"goRelPath": relPath,
"goRelPath": projPath,
"goFile": goFile,
"exeFile": util.FileNameWithoutExt(goFile),
"argument": builder.String(),

View File

@@ -0,0 +1,26 @@
package gen
import (
"errors"
"os"
"path/filepath"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
func getFilePath(file string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
projPath, ok := util.FindGoModPath(filepath.Join(wd, file))
if !ok {
projPath, err = util.PathFromGoSrc()
if err != nil {
return "", errors.New("no go.mod found, or not in GOPATH")
}
}
return projPath, nil
}

View File

@@ -1,52 +0,0 @@
package gen
import (
"strings"
"text/template"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
func GenerateMakefile(goFile, namespace string) error {
relPath, err := util.PathFromGoSrc()
if err != nil {
return err
}
movePath, err := getMovePath()
if err != nil {
return err
}
out, err := util.CreateIfNotExist("Makefile")
if err != nil {
return err
}
defer out.Close()
t := template.Must(template.New("makefile").Parse(makefileTemplate))
return t.Execute(out, map[string]string{
"rootRelPath": movePath,
"relPath": relPath,
"exeFile": util.FileNameWithoutExt(goFile),
"namespace": namespace,
})
}
func getMovePath() (string, error) {
relPath, err := util.PathFromGoSrc()
if err != nil {
return "", err
}
var builder strings.Builder
for range strings.Split(relPath, "/") {
builder.WriteString("../")
}
if move := builder.String(); len(move) == 0 {
return ".", nil
} else {
return move, nil
}
}

View File

@@ -1,7 +1,6 @@
package gen
const (
dockerTemplate = `FROM golang:alpine AS builder
const dockerTemplate = `FROM golang:alpine AS builder
LABEL stage=gobuilder
@@ -26,19 +25,3 @@ COPY --from=builder /app/{{.exeFile}} /app/{{.exeFile}}
CMD ["./{{.exeFile}}"{{.argument}}]
`
makefileTemplate = `version := v$(shell /bin/date "+%y%m%d%H%M%S")
build:
docker pull alpine
docker pull golang:alpine
cd $(GOPATH)/src/xiao && docker build -t registry.cn-hangzhou.aliyuncs.com/xapp/{{.exeFile}}:$(version) . -f {{.relPath}}/Dockerfile
docker image prune --filter label=stage=gobuilder -f
push: build
docker push registry.cn-hangzhou.aliyuncs.com/xapp/{{.exeFile}}:$(version)
deploy: push
kubectl -n {{.namespace}} set image deployment/{{.exeFile}}-deployment {{.exeFile}}=registry-vpc.cn-hangzhou.aliyuncs.com/xapp/{{.exeFile}}:$(version)
`
)

View File

@@ -76,7 +76,7 @@ func MustCreateRpcContext(protoSrc, targetDir, serviceName string, idea bool) *R
func MustCreateRpcContextFromCli(ctx *cli.Context) *RpcContext {
os := runtime.GOOS
switch os {
case "darwin", "windows":
case "darwin", "linux", "windows":
default:
logx.Must(fmt.Errorf("unexpected os: %s", os))
}

View File

@@ -12,13 +12,14 @@ func Run(arg string) (string, error) {
goos := runtime.GOOS
var cmd *exec.Cmd
switch goos {
case "darwin":
case "darwin", "linux":
cmd = exec.Command("sh", "-c", arg)
case "windows":
cmd = exec.Command("cmd.exe", "/c", arg)
default:
return "", fmt.Errorf("unexpected os: %v", goos)
}
dtsout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd.Stdout = dtsout
@@ -30,5 +31,6 @@ func Run(arg string) (string, error) {
}
return "", err
}
return dtsout.String(), nil
}

View File

@@ -45,7 +45,7 @@ func (g *defaultRpcGenerator) mustGetPackage(dir string) string {
switch os {
case "windows":
relativePath = filepath.ToSlash(relativePath)
case "darwin":
case "darwin", "linux":
default:
g.Ctx.Fatalln("unexpected os: %s", os)
}

View File

@@ -8,8 +8,6 @@ import (
)
const etcTemplate = `Name: {{.serviceName}}.rpc
Log:
Mode: console
ListenOn: 127.0.0.1:8080
Etcd:
Hosts:

View File

@@ -22,13 +22,15 @@ import (
)
type {{.logicName}} struct {
ctx context.Context
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logicName}} {
return &{{.logicName}}{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}