美文网首页
crow-han(基于go-micro框架的微服务脚手架)-02

crow-han(基于go-micro框架的微服务脚手架)-02

作者: 玄德公笔记 | 来源:发表于2023-05-21 21:20 被阅读0次

    1. 目录结构

    image.png
    • bin
      编译好的二进制文件

    • cmd
      各微服务的main函数和相关初始化函数

    • docker
      容器相关,包括docker-compose.yml和dockerFile

    • internal:内部代码(不需要对外)

      • app:各微服务私有的代码
      • cache:redis相关的代码
      • conf:配置和变量相关的
      • models:数据库相关
      • pkg:各微服务公用的方法等代码
    • pkg:公共代码,外部可能用到的

    • sql:sql文件

    • MakeFile

    • README.md

    2. 添加自己的微服务

    已获取k8s的node节点列表为例,写一个k8s的微服务接入crow-han中

    2.1 配置文件和必要的函数

    2.1.1 配置文件

    • cmd目录下创建k8s目录

    以后放置微服务k8s的main函数、初始化相关代码、配置文件等

    • 该目录下创建etc目录放置配置文件
    • etc目录下创建kube.conf 文件,将k8s服务器master上 ~/.kube/config文件内容拷贝进去。

    2.1.2 连接k8s

    internal/conf 目录下创建 connect_k8s.go文件

    以下这段是链接k8s的代码。这段代码可以作为微服务k8s的私有代码放在internal/app/k8s中,也可以最为脚手架公用配置放在internal/conf中。考虑到我之后将按照crow-han的风格,在微服务k8s的main函数中初始化k8s链接,为避免以后出现循环调用的可能,这里选择了后者。

    ackage conf
    
    import (
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/tools/clientcmd"
    )
    
    var K8sClientSet *kubernetes.Clientset
    
    func ConnectK8s() (clientSet *kubernetes.Clientset, err error) {
        configPath := "etc/kube.conf"
        config, err := clientcmd.BuildConfigFromFlags("", configPath)
        if err != nil {
            return nil, err
        }
        clientSet, err = kubernetes.NewForConfig(config)
        if err != nil {
            return nil, err
        }
        return clientSet, nil
    }
    

    2.2 k8s服务相关代码

    internal/app下添加k8s目录(放置该微服务处理逻辑的一些代码),在下边创建 nodes.go文件(放置node操作相关的代码,我们这里写一个获取nodeList作为示例)。

    package service
    
    import (
        "context"
        "crow-han/internal/conf"
        coreV1 "k8s.io/api/core/v1"
        metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    )
    
    func GetNodeList() (nodeList *coreV1.NodeList, err error) {
        nodeList, err = conf.K8sClientSet.CoreV1().Nodes().List(context.TODO(), metaV1.ListOptions{})
        if err != nil {
            return nodeList, err
        }
        return nodeList, nil
    }
    

    2.3 proto

    2.3.1 创建proto文件

    • proto目录下创建k8s目录,下边创建k8s.proto文件
    syntax = "proto3";
    
    package k8s;
    
    option go_package = "./proto/k8s;k8s";
    
    service K8s {
      rpc GetNodeList(GetNodeListRequest) returns (GetNodeListResponse) {}
    }
    
    message GetNodeListRequest {
    }
    
    message GetNodeListResponse {
       string NodeList = 1;
    }
    

    GetNodeListResponse这个是微服务返回给gateway的返回值,GetNodeList() 返回是*coreV1.NodeList,通常我们可以转换成proto的格式。但是因为这个node返回值比较复杂,所以这里我返回一个字串(json)然后在gateway再解析回来。

    2.3.2 编译proto

    • 编译proto
     protoc --proto_path=. --micro_out=. --go_out=:. proto/k8s/k8s.proto
    
    • 生成文件
      此时 proto/k8s目录下生成k8s.pb.go k8s.pb.micro.go两个文件

    2.4 handler

    internal/app/k8s目录下创建 /handler目录,下边创建 nodes.go 文件

    package handler
    
    import (
        "context"
        "crow-han/internal/app/k8s/service"
        pb "crow-han/proto/k8s"
        "encoding/json"
        "github.com/toolkits/pkg/logger"
    )
    
    type Nodes struct{}
    
    func (e *Nodes) GetNodeList(ctx context.Context, req *pb.GetNodeListRequest, rsp *pb.GetNodeListResponse) error {
        logger.Infof("Received K8s.GetNodeList request: %v", req)
    
        nodeList, err := service.GetNodeList()
        if err != nil {
            logger.Error(err)
            return err
        }
    
        output, err := json.Marshal(&nodeList)
        if err != nil {
            logger.Error(err)
        }
        rsp.NodeList = string(output)
    
        return nil
    }
    

    2.5 k8s的main函数

    在cmd目录下创建k8s目录,目录下创建main.go文件,内容如下

    package k8s
    
    import (
        "crow-han/internal/app/k8s/handler"
        "crow-han/internal/cache"
        "crow-han/internal/conf"
        pb "crow-han/proto/k8s"
        "fmt"
        "github.com/go-micro/plugins/v4/registry/consul"
        "github.com/kelseyhightower/envconfig"
        "go-micro.dev/v4/registry"
    
        "go-micro.dev/v4"
        "go-micro.dev/v4/logger"
    )
    
    func init() {
        //初始化变量
        err := envconfig.Process("crow", &conf.MyEnvs)
        if err != nil {
            fmt.Println(err)
        }
        fmt.Printf("%+v\n", &conf.MyEnvs)
    
        //初始化日志
        conf.LoggerInit()
        logger.Info("logger init")
        //mysql初始化
        var tx conf.MyConnect
        tx.ConnectMysql()
    
        //初始化redis
        //redis初始化
        conf.RedisConnect()
        cache.CheckRides()
    
        //初始化k8s
        conf.K8sClientSet, err = conf.ConnectK8s()
        if err != nil {
            fmt.Println(err)
        }
    }
    
    var (
        service = "k8s"
        version = "latest"
    )
    
    func main() {
        // Create service
        srv := micro.NewService()
    
        consulRegis := consul.NewRegistry(func(options *registry.Options) {
            options.Addrs = []string{
                conf.MyEnvs.ConsulAddr,
            }
        })
    
        srv.Init(
            micro.Name(service),
            micro.Version(version),
            micro.Registry(consulRegis),
        )
    
        // Register handler
        if err := pb.RegisterK8SHandler(srv.Server(), new(handler.Nodes)); err != nil {
            logger.Fatal(err)
        }
    
        if err := srv.Run(); err != nil {
            logger.Fatal(err)
        }
    }
    

    3. gateway调用

    3.1 调用微服务

    internal/app/gate-way/service目录下创建k8s_nodes.go文件,内容如下:

    package service
    
    import (
        "context"
        k8sProto "crow-han/proto/k8s"
        "encoding/json"
        "github.com/gin-gonic/gin"
        "github.com/toolkits/pkg/logger"
        coreV1 "k8s.io/api/core/v1"
    )
    
    func GetNodeList(c *gin.Context) {
    
        //调用k8s
        userSrv := k8sProto.NewK8SService("k8s", srv.Client())
        respSr, err := userSrv.GetNodeList(context.Background(), &k8sProto.GetNodeListRequest{})
        logger.Infof("%+v", respSr)
        if err != nil {
            logger.Error(err)
            SetErr(c, 500, err, err.Error())
            return
        }
        //将结果转换为原结构体
        var resp *coreV1.NodeList
        json.Unmarshal([]byte(respSr.NodeList), &resp)
        
        SetOK(c, resp)
    }
    

    3.2 router

    internal/app/gate-way/service/router.go文件中添加一条路由规则

    func ServerRouter() {
        ……
        groupV1 := r.Group("/api/v1")
        {
          ……
          groupV1.GET("/k8s/node/list", user(), GetNodeList) //添加这条路由
        }
    

    说明:需要user验证的加上验证方法 user(),不想验证可以不加。

    4. 添加文档 swagger

    • internal/app/gate-way/service/k8s_nodes.go文件的GetNodeList()函数前添加如下注释
    // GetNodeList 查看node列表
    // @Summary 查看node列表
    // @Description 查看node列表
    // @Tags Node
    // @Success 200 {object} response.Response{data=v1.NodeList} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
    // @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
    // @Router /api/v1/k8s/node/list [get]
    // @Security Bearer
    func GetNodeList(c *gin.Context) {
      ……
    }
    

    详细方法见另一篇博文《GO语言gin框架实战-03-swagger和接口文档》

    • 编译swagger
    cd internal/app/gate-way/service
    swag init --parseDependency --parseInternal --parseDepth 2 -g .\router.go
    

    5. 调试

    5.1 启动服务

    • consul上查看
      我们新写的微服务注册上来了


      image.png

    5.2 swagger接口测试

    • 获取token
      默认用户名密码:admin/liubei@161


      image.png

    输出结果


    image.png
    • Bearer验证
      点开锁标记,输入 Bearer xxxxxxxxxxx(xxxx 是刚才获取的token值)

      image.png
    • 验证我们之前写的接口

    image.png

    输出如下:


    image.png

    相关文章

      网友评论

          本文标题:crow-han(基于go-micro框架的微服务脚手架)-02

          本文链接:https://www.haomeiwen.com/subject/fclzsdtx.html