微服務從程式碼到k8s部署應有盡有系列(一)
從本篇文章開始,我們用一個系列來講解從需求到上線、從程式碼到k8s部署、從日誌到監控等各個方面的微服務完整實踐。
實戰項目地址://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程式碼&更新依賴
$ git clone [email protected]:Mikaelemmmm/go-zero-looklook.git
$ go mod tidy
2、啟動項目所依賴的環境
$ docker-compose -f docker-compose-env.yml up -d
jaeger: //127.0.0.1:16686/search
asynq (延時、定時消息隊列): //127.0.0.1:8980/
kibana: //127.0.0.1:5601/
Elastic search: //127.0.0.1:9200/
Prometheus: //127.0.0.1:9090/
Grafana: //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項目依賴的鏡像命令如下
$ 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、啟動項目
$ docker-compose up -d
【注】依賴的是項目根目錄下的docker-compose.yml配置
6、查看項目運行情況
訪問 //127.0.0.1:9090/ , 點擊上面菜單「Status」,在點擊Targets ,藍色的就是啟動成了,紅色就是沒啟動成功
【注】如果是第一次拉取項目,每個項目容器第一次構建拉取依賴,這個看網路情況,可能會比較慢有的服務,所以會導致項目啟動失敗或者被依賴的服務啟動失敗自己也啟動失敗了,這個很正常,如果碰到項目啟動不起來的情況,比如order-api ,這時候我們去看下日誌就可以
$ docker logs -f order-api
很明顯是因為order-rpc啟動時間太久了,而order-api一直等他啟動,order-rpc一定時間內沒有啟動成功,order-api沒耐心了(超時了),就算後面order-rpc啟動起來,它也不管了,這時候再去重啟一次order-api就可以了,這個只是第一次創建容器會這樣,之後只要不銷毀容器就不會,我們去到項目根目錄下重啟一下
$ docker-compose restart order-api
【注意】一定要去到項目根目錄下重啟 ,因為docker-compose.yml在項目根目錄
然後我們在看一下,這裡我們使用docker logs 看了
__ _ ___
/ /\ | | | |_)
/_/--\ |_| |_| \_ , built with Go 1.17.6
mkdir /go/src/github.com/looklook/app/order/cmd/api/tmp
watching .
watching desc
watching desc/order
watching etc
watching internal
watching internal/config
watching internal/handler
watching internal/handler/homestayOrder
watching internal/logic
watching internal/logic/homestayOrder
watching internal/svc
watching internal/types
!exclude tmp
building...
running...
可以看到order-api已經成功了 ,再去prometheus看一下
可以看到prometheus也顯示成功了,同理把其他的也排查一次,啟動成功就可以了
7、訪問項目
由於我們使用nginx做的網關,nginx網關配置在docker-compose中,也是配置在docker-compose中,nignx對外暴露埠是8888,所以我們通過8888埠訪問
$ curl -X POST "//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即可,項目根目錄下重啟
$ docker-compose restart nginx
六、日誌收集
將項目日誌收集到es(filebeat收集日誌->kafka -> go-stash消費kafka日誌->輸出到es中, kibana查看es數據)
所以我們要提前在kafka中創建日誌的topic
進入kafka容器
$ docker exec -it kafka /bin/sh
創建log的topic
$ cd /opt/kafka/bin
$ ./kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 -partitions 1 --topic looklook-log
訪問kibana //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/api/desc目錄下,直接複製deploy/script/gencode/gen.sh中的生成api命令運行即可
$ goctl api go -api *.api -dir ../ -style=goZero
生成rpc也一樣,在寫完proto文件後,直接粘複製deploy/script/gencode/gen.sh中的生成rpc命令運行即可
goctl >= 1.3 進入”服務/cmd/rpc/pb”目錄下,執行下面命令
$ goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../ --zrpc_out=../
$ sed -i "" 's/,omitempty//g' *.pb.go
goctl < 1.3 進入”服務/cmd”目錄下,執行下面命令
$ 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下
九、後續
由於項目中由於涉及到的技術棧稍微有點多,將分章節一步一步講解,敬請關注。
項目地址
//github.com/zeromicro/go-zero
歡迎使用 go-zero
並 star 支援我們!
微信交流群
關注『微服務實踐』公眾號並點擊 交流群 獲取社區群二維碼。