golang微服务实践、集群管理和自动化配置
暑期课设是写个项目,前端反正react native没得选了,Android原生大家都没接触过学习成本太高,跨平台也是个问题不如就入JS神教算了= =。
至于后端的话个人原因不喜欢java,又要凸显技术优势(zhuang bi)要搞dockerize的微服务,JS全栈也不太行,那就剩下go咯,反正我负责这块我说了算嘻嘻。
然而golang和spring cloud那一套完整的东西比还是有所欠缺,这里指的不是功能而是相关的教程方面,spring全家桶东西全,用的人多,教程也多;go语言主要依靠社区了,虽然国内大厂用的也多但是人家不开源啊,行吧自己动手丰衣足食,我就把我这几天折腾的经验分享一下吧。
参考项目
https://github.com/sjtu-jiaojiao/SJTU-JiaoJiao
目标
搭建一套基于微服务架构的,Dockerized的,自动化功能齐全的API后端并部署在服务器集群上。
技术栈
微服务框架:go-micro、micro
web路由:gin
服务管理:consul
单元测试:goconvey
doc文档:apidoc
热加载:realize
CI/CD:travis
日志集成:loggly
集群管理:docker swarm
集群监控:swarmprom
代码质量:goreportcard、codacy
Github插件:mergify、coveralls
待补充,相关的选型和细节会在下面说。
注意看文档非常重要,而且这些的中文文档少的可怜……所以多学英语8
组件-微服务框架
主流的大概就两个,go-kit和go-micro,前者看文档据说支持更多功能(不太清楚有什么特别的……)但是我觉得它的设计有点过于复杂了,可以看看它官网给的例子感受一下,这边也有reddit的讨论。而go-micro就很简练,比较符合我追求极简的风格(java好好学学),所以最后还是选择了go-micro。
大概需要1-2个小时
官方仓库:https://github.com/micro/go-micro
运行库:https://github.com/micro/micro
文档(有中文不过不建议看):https://micro.mu/docs/
例子:https://github.com/micro/examples
自然人只要看看example中greeter
的例子就基本上会玩了,代码很少哦。
组件-web路由
其实原本打算用beego全家桶的,不过因为要微服务很遗憾它太臃肿了,好消息是它的设计是可插拔的我们可以用其中方便的东西(比如日志记录的包),那么我们就选快速且文档全的gin吧,go-micro的greeter
例子中就有它的样例可以看看。
大概需要半个小时
官方仓库:https://github.com/gin-gonic/gin
文档:https://gin-gonic.com/docs/
其实不用看太多,看看hello world就行了,用到了在找。
组件-服务管理
etcd没有UI还要另外找……而且我配的时候似乎有问题还是算了吧,consul的支持比较完善就用这个吧。
而且consul自带的KV数据库就实现了配置中心的功能也就不需要其他的了还不错。
大概需要10分钟
只要装上就行了,arch系直接用aur包完事。
服务整合
现在我们可以搭建基本的微服务了!其实micro库里面已经很完善了我们只需要一键运行一下。
下面这些都是本地开发的命令,部署上线需要稍作调整(IP地址端口啥的)
首先是consul
consul agent -ui -bind=127.0.0.1 -dev
这样在本地8500端口就开了一个web服务,可以在里面看到正在运行哪些服务。
然后是APIGateway(基于gin的)
micro --registry=consul api --handler=http
刷新一下consul的界面是不是有了?
最后是micro的web界面(可以省略)
micro --registry=consul web
默认在8082端口
现在我们的一套基础设施就搞好了,可以继续我们的旅程。
【可选】KV数据库配置中心
可以先在consul的web界面配置,Key/Value选项卡中新建一个Key,然后内容是一段JSON,比如Key="test"
,值是
{
"test": "Do_not_modify_this"
}
获取的例子:https://github.com/micro/go-micro/tree/master/config/source/consul
那么在程序里就可以用conf.Get("test", "test").String("123")
来获得值了,获取不到就返回默认值123。
注意这个值会在consul被关闭时清除,如果不想每次都设置可以导出数据:
consul kv export > consul.json
然后下次用的时候先启动服务,然后输入
consul kv import @consul.json
就可以了,很奇怪我没在文档里找到启动时就加载这个的选项有知道的可以留言。
【可选】一键脚本&管理程序
每次运行这些很麻烦我们写个脚本8
consul agent -ui -bind=127.0.0.1 -dev > /dev/null 2>&1 &
sleep 5
micro --registry=consul api --handler=http > /dev/null 2>&1 &
sleep 5
micro --registry=consul web > /dev/null 2>&1 &
go run servedoc.go --registry=consul > /dev/null 2>&1 &
consul kv import @consul.json > /dev/null 2>&1 &
goconvey -port 8400 > /dev/null 2>&1 &
realize start > /dev/null 2>&1 &
其中sleep是必须的给程序时间启动要不然报错,有些命令没有出现这是后面的内容我先放这里。
然后在开发过程中经常要重启程序不是很方便(手动kill),因此用go写了个管理工具效果差不多方便一点。
【可选】MakeFile文件
东西多了敲命令也很麻烦,例如我们需要生成doc、生成proto等,可以考虑使用MakeFile,这样直接用make xxx
就可以运行各种命令。
组件-单元测试
单元测试是必须的,go有自带的test不过很简陋,可以换成更加酷炫的goconvey,还能实现自动检测修改等很多高级功能。
大概需要一个小时
官方仓库:https://github.com/smartystreets/goconvey
coverage不显示
Linux系统如果看不见coverage可能是权限问题,进入$GOPATH
目录找到smartystreets/goconvey
这个目录(可以通过搜索找),进入smartystreets/goconvey/web
,然后把client
目录设置成755以上权限就行。
组件-doc文档
原本打算用swagger的,然而搞了半天发现go版本的似乎太过智能,自动检测main,只支持一个,这样每个微服务都要有个单独的swagger服务不现实。不过好在还有一个apidoc可以用,自动检测目录下所有的没有main函数限制,UI也还可以。
大概需要一个小时
官方网站:http://apidocjs.com/
设置好json文件写好注释直接根目录运行apidoc
就好了,简单省事。
【可选】分配路由
默认生成在doc
目录下,纯静态文件直接打开就可以了,不过为了统一起见(懒得再点了)可以把它作为一个微服务分配路由,我们写一个servedoc.go
文件,用
router.Static("/doc", "./doc")
的方法,然后把它注册成一个微服务,运行:
go run servedoc.go --registry=consul
然后就能在localhost:8080/doc/
看到文档啦,我把这个也放到了上面的一键脚本里了。
组件-热加载
现在我们写一个个微服务已经没啥问题了,不过有个麻烦的地方就是每次修改完都要ctrl+c然后go run
,这不是很麻烦,所以我们需要一个时刻监控的东西热加载,社区提供了realize这个非常棒的工具。
大概需要一个小时
官方仓库:https://github.com/oxequa/realize
注意他这个似乎不支持多项目自动检测,我们每个微服务都得给它设置一个schema,类似于
1 | - name: xxx |
注意这里我们加了一个scripts,这样子修改完了连apidoc
这条命令都不用敲了,文档就能自动更新,很不错。
组件-CI/CD
Jenkins不是用的很惯所以我选的是Travis。文档还是比较好读的但是自定义的话就要多实验配置了,跑一次还挺久的所以需要点时间。
大概需要2-3个小时
官方文档:https://docs.travis-ci.com/
注意我们一些服务器配置信息不要放在里面可以用环境变量的方式以免泄漏。
组件-集群管理
因为我们是Dockerize的集群,自然要一套管理软件,Kubernate太复杂了搭起来太费时间我就用了docker自带的docker swarm,还是很简单的。
大概需要一个小时
可以参考这篇文章写的很好:https://www.cnblogs.com/drawnkid/p/8487337.html
有一点需要注意的是我一开始以为--update-delay
参数是可以自动从docker源上更新的,这样我们只要push到docker上就万事大吉了,然而实际上这是我们手动运行update命令的时候两个服务更新的延时,我们可以写个更新脚本扔服务器上,然后在CI里ssh运行它就行了。
组件-集群监控
节点多了的时候要想在压力测试的时候监控CPU等等就得一个一个登上去看很麻烦,因此我们还需要一个监控系统。这里采用了swarmprom,集成了Prometheus等一系列东西的一键包很nice。
大概需要10分钟
官方仓库:https://github.com/stefanprodan/swarmprom
按照readme写的跑起来就行了。
【可选】修改端口
因为3000端口我这边访问不了,如果要用得ssh连上映射过来也是麻烦,所以我们需要改一下映射的端口。在swarmprom目录下找到docker-compose.yml
文件,翻到最下面的caddy的port,格式就是docker的映射格式,改一下前面的端口号就行。
组件-代码质量
实现代码质量监控我们采用了两种工具,一个是针对go的goreportcard,还有一个是针对项目的codacy,都不复杂读读文档就行。
大概需要30分钟
goreportcard:https://goreportcard.com
codacy:https://app.codacy.com
其中codacy还可以设置PR comment这样就能看到每次PR的问题了。
Github插件-mergify
Github每次PR都要手动去点那个绿色的按钮还是觉得懒……我们可以用mergify实现满足一定要求后自动合并。
大概需要20分钟
官方网站:https://mergify.io
按照document写个.mergify.yml
文件放在master分支里就行了
Github插件-coveralls
为了提升逼格,我们可以把测试覆盖率的东西集成到github,我用的是coveralls因为官方给出了集成说明比较方便。
大概需要30分钟
官方文档:https://docs.coveralls.io/
Travis集成:https://docs.travis-ci.com/user/coveralls/
另外由于我们是微服务有多个coverage文件,可以用参考这个配置多package的提交:https://gist.github.com/rjeczalik/6f01430e8554bf59b88e
未完待续……
成果
现在我们的微服务已经基本成型了,可以专注于业务代码了,自动化程度还是相当高的,我们来看看:
首先运行一键脚本或者管理程序启动各种服务组件。
然后我们修改了文件,它会自动检测修改,自动生成API文档、自动跑单元测试、自动重新加载服务。
最后我们push,Travis自动跑测试,master分支还能自动部署到服务器集群。
未完待续……