首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

微服务从代码到k8s部署应有尽有系列(一)

从本篇文章开始,我们用一个系列来讲解从需求到上线、从代码到 k8s 部署、从日志到监控等各个方面的微服务完整实践。

实战项目地址:https://github.com/Mikaelemmmm/go-zero-looklook

一、项目简介

整个项目使用了 go-zero 开发的微服务,基本包含了 go-zero 以及相关 go-zero 作者开发的一些中间件,所用到的技术栈基本是 go-zero 项目组的自研组件,基本是 go-zero 全家桶了。

项目目录结构如下:

  • app:所有业务代码包含 api、rpc 以及 mq(消息队列、延迟队列、定时任务)
  • common:通用组件 error、middleware、interceptor、tool、ctxdata 等
  • data:该项目包含该目录依赖所有中间件(mysql、es、redis、grafana 等)产生的数据,此目录下的所有内容应该在 git 忽略文件中,不需要提交。
  • deploy:filebeat: docker 部署 filebeat 配置 go-stash:go-stash 配置 nginx: nginx 网关配置 prometheus : prometheus 配置 script:gencode:生成 api、rpc,以及创建 kafka 语句,复制粘贴使用 mysql:生成 model 的 sh 工具 goctl: 该项目 goctl 的 template,goctl 生成自定义代码模版,tempalte 用法可参考 go-zero 文档,复制到家目录下.goctl 即可,该项目用到 goctl 版本是 v1.3.0
  • doc : 该项目系列文档

二、用到技术栈

  • go-zero
  • nginx 网关
  • filebeat
  • kafka
  • go-stash
  • elasticsearch
  • kibana
  • prometheus
  • grafana
  • jaeger
  • go-queue
  • asynq
  • asynqmon
  • dtm
  • docker
  • docker-compose
  • mysql
  • redis

三、项目架构图

四、业务架构图

五、项目环境搭建

本项目采用 air 热加载功即时修改代码及时生效,并且不需要每次都要重启,改了代码自动就在容器中重新加载了,本地不需要启动服务,本地安装的 sdk 就是写代码自动提示使用的,实际运行是以来容器中 cosmtrek/air 的 golang 环境。所以使用 goland、vscode 都一样

1、clone 代码 &更新依赖

代码语言:javascript
复制
$ git clone git@github.com:Mikaelemmmm/go-zero-looklook.git$ go mod tidy

2、启动项目所依赖的环境

代码语言:javascript
复制
$ docker-compose -f docker-compose-env.yml up -d

jaeger: http://127.0.0.1:16686/search

asynq (延时、定时消息队列): http://127.0.0.1:8980/

kibana: http://127.0.0.1:5601/

Elastic search: http://127.0.0.1:9200/

Prometheus: http://127.0.0.1:9090/

Grafana: http://127.0.0.1:3001/

Mysql: 自行客户端工具(Navicat、Sequel Pro)查看

  • host : 127.0.0.1
  • port : 33069
  • username : root
  • pwd : PXDN93VRKUm8TeE7

Redis: 自行工具(redisManager)查看

  • host : 127.0.0.1
  • port : 63799
  • pwd : G62m50oigInC30sf

Kafka: 自行客户端工具查看

  • host : 127.0.0.1
  • port : 9092

3、拉取项目依赖镜像

因为本项目是用 air 热加载的,所以是在 air+golang 镜像中运行,直接 docker-compose 也可以,但是考虑依赖可能会比较大,会影响启动项目,所以最好先把这个镜像拉取下来再去启动项目,拉取 air+golang 项目依赖的镜像命令如下

代码语言:javascript
复制
$ docker pull cosmtrek/air:latest

4、导入 mysql 数据

创建数据库 looklook_order && 导入 deploy/sql/looklook_order.sql 数据

创建数据库 looklook_payment && 导入 deploy/sql/looklook_payment.sql 数据

创建数据库 looklook_travel && 导入 deploy/sql/looklook_travel.sql 数据

创建数据库 looklook_usercenter && 导入 looklook_usercenter.sql 数据

5、启动项目

代码语言:javascript
复制
$ docker-compose up -d 

【注】依赖的是项目根目录下的 docker-compose.yml 配置

6、查看项目运行情况

访问 http://127.0.0.1:9090/ , 点击上面菜单“Status”,在点击 Targets ,蓝色的就是启动成了,红色就是没启动成功

【注】如果是第一次拉取项目,每个项目容器第一次构建拉取依赖,这个看网络情况,可能会比较慢有的服务,所以会导致项目启动失败或者被依赖的服务启动失败自己也启动失败了,这个很正常,如果碰到项目启动不起来的情况,比如 order-api ,这时候我们去看下日志就可以

代码语言:javascript
复制
$ docker logs -f order-api 

很明显是因为 order-rpc 启动时间太久了,而 order-api 一直等他启动,order-rpc 一定时间内没有启动成功,order-api 没耐心了(超时了),就算后面 order-rpc 启动起来,它也不管了,这时候再去重启一次 order-api 就可以了,这个只是第一次创建容器会这样,之后只要不销毁容器就不会,我们去到项目根目录下重启一下

代码语言:javascript
复制
$ docker-compose restart order-api

【注意】一定要去到项目根目录下重启 ,因为 docker-compose.yml 在项目根目录

然后我们在看一下,这里我们使用 docker logs 看了

代码语言:javascript
复制
  __    _   ___   / /\  | | | |_) /_/--\ |_| |_| \_ , built with Go 1.17.6
mkdir /go/src/github.com/looklook/app/order/cmd/api/tmpwatching .watching descwatching desc/orderwatching etcwatching internalwatching internal/configwatching internal/handlerwatching internal/handler/homestayOrderwatching internal/logicwatching internal/logic/homestayOrderwatching internal/svcwatching internal/types!exclude tmpbuilding...running...

可以看到 order-api 已经成功了 ,再去 prometheus 看一下

可以看到 prometheus 也显示成功了,同理把其他的也排查一次,启动成功就可以了

7、访问项目

由于我们使用 nginx 做的网关,nginx 网关配置在 docker-compose 中,也是配置在 docker-compose 中,nignx 对外暴露端口是 8888,所以我们通过 8888 端口访问

代码语言:javascript
复制
$ curl  -X POST "http://127.0.0.1:8888/usercenter/v1/user/register" -H "Content-Type: application/json" -d "{\"mobile\":\"18888888888\",\"password\":\"123456\"}" 
返回:{"code":200,"msg":"OK","data":{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NzM5NjY0MjUsImlhdCI6MTY0MjQzMDQyNSwiand0VXNlcklkIjo1fQ.E5-yMF0OvNpBcfr0WyDxuTq1SRWGC3yZb9_Xpxtzlyw","accessExpire":1673966425,"refreshAfter":1658198425}}

【注】 如果是访问 nginx 失败,访问成功可以忽略,可能是 nginx 依赖后端服务,之前因为后端服务没启动起来,nginx 这里没启动起来,重启一次 nginx 即可,项目根目录下重启

代码语言:javascript
复制
$ docker-compose restart nginx

六、日志收集

将项目日志收集到 es(filebeat 收集日志->kafka -> go-stash 消费 kafka 日志->输出到 es 中, kibana 查看 es 数据)

所以我们要提前在 kafka 中创建日志的 topic

进入 kafka 容器

代码语言:javascript
复制
$ docker exec -it kafka /bin/sh

创建 log 的 topic

代码语言:javascript
复制
$ cd /opt/kafka/bin
$ ./kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 -partitions 1 --topic looklook-log

访问 kibana http://127.0.0.1:5601/ , 创建日志索引

点击左上角菜单(三个横线那个东东),找到 Analytics - > 点击 discover

然后在当前页面,Create index pattern->输入 looklook-* -> Next Step ->选择 @timestamp->Create index pattern

然后点击左上角菜单,找到 Analytics->点击 discover ,日志都显示了 (如果不显示,就去排查 filebeat、go-stash,使用 docker logs -f filebeat 查看)

七、本项目镜像介绍

所有服务启动成功,应该是如下这些,自行对比

  • nginx : 网关 (nginx->api->rpc)
  • cosmtrek/air : 我们业务代码开发依赖的环境镜像,之所以用这个是因为 air 热加载,写代码实时编译太方便了,这个镜像是 air+golang,实际上我们启我们自己的业务服务后,我们的业务服务是运行在此镜像中的
  • wurstmeister/kafka : 业务使用的 kafka
  • wurstmeister/zookeeper : kafka 依赖的 zookeeper
  • redis:业务使用的 redis
  • mysql: 业务使用的数据库
  • prom/prometheus:监控业务
  • grafana/grafana :prometheus 的 ui 很难看,用来显示 prometheus 收集来的数据
  • elastic/filebeat : 收集日志到 kafka
  • go-stash : 消费 kafka 中日志,脱敏、过滤然后输出到 es
  • docker.elastic.co/elasticsearch/elasticsearch : 存储收集的日志
  • docker.elastic.co/kibana/kibana : 显示 elasticsearch
  • jaegertracing/jaeger-query 、jaegertracing/jaeger-collector、jaegertracing/jaeger-agent:链路追踪
  • go-stash : filebeat 收集日志到 kafka 后,go-stash 去消费 kafka 进行数据脱敏、过滤日志中内容,最后输出到 es 中

八、项目开发建议

  • app 下放所有业务服务代码
  • common 放所有服务的公共基础库
  • data 项目依赖中间件产生的数据,实际开发中应该在 git 中忽略此目录以及此目录下产生的数据
  • 生成 api、rpc 代码:

一般我们在生成 api,rpc 代码时候手动去敲 goctl 的命令比较长,也记不住,所以我们直接去 deploy/script/gencode/gen.sh 中复制代码即可。比如我在 usercenter 服务中新增加了一个业务,修改密码,写完 api 文件之后,进入到 usercenter/cmd 目录下,直接复制 deploy/script/gencode/gen.sh 中的生成 api 命令运行即可

代码语言:javascript
复制
$ goctl api go -api ./api/desc/*.api -dir ./api -style=goZero

生成 rpc 也一样,在写完 proto 文件后,直接粘复制 deploy/script/gencode/gen.sh 中的生成 rpc 命令运行即可

代码语言:javascript
复制
$ goctl rpc proto -src rpc/pb/*.proto -dir ./rpc -style=goZero
$ sed -i 's/,omitempty//g'  ./rpc/pb/*.pb.go

【注】建议在生成 rpc 文件时候,在多执行一次下面那个命令,把 protobuf 生成的 omitempty 给删除掉,不然字段为 nil 就不返回了

  • 生成 kafka 代码: 因为本项目使用了 go-queue 的 kq 做消息队列,kq 又依赖的 kafka,实际就是使用了 kafka 做消息队列,但是 kq 默认是需要我们提前把 topic 建好的,不许默认自动生成,所以命令也准备好了,直接复制 deploy/script/gencode/gen.sh 中的创建 kafka 的 topic 代码即可  kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 -partitions 1 --topic {topic}
  • 生成 model 代码,直接运行 deploy/script/mysql/genModel.sh 参数
  • api 项目中的.api 文件我们做了拆分,统一放到每个 api 的 desc 文件夹下,因为如果所有内容都写在 api 中可能不便于查看,所以做了拆分,把所有方法写到一个 api 中,其他的实体以及 req、rep 统一放到一个文件夹单独定义比较清晰
  • 生成 model、错误处理时候使用了 template 重新定义,该项目用到的自定义的 goctl 的模版在项目 data/goctl 下

九、后续

由于项目中由于涉及到的技术栈稍微有点多,将分章节一步一步讲解,敬请关注。

项目地址

https://github.com/zeromicro/go-zero

欢迎使用 go-zerostar 支持我们!

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/c0d0d01d7d127aeab8fc77591
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券