crow-han(基于go-micro框架的微服务脚手架)-02-添加一个微服务实战(已k8s为例)

news2024/11/24 2:46:00

文章目录

  • 1. 目录结构
  • 2. 添加自己的微服务
    • 2.1 配置文件和必要的函数
      • 2.1.1 配置文件
      • 2.1.2 连接k8s
    • 2.2 k8s服务相关代码
    • 2.3 proto
      • 2.3.1 创建proto文件
      • 2.3.2 编译proto
    • 2.4 handler
    • 2.5 k8s的main函数
  • 3. gateway调用
    • 3.1 调用微服务
    • 3.2 router
  • 4. 添加文档 swagger
  • 5. 调试
    • 5.1 启动服务
    • 5.2 swagger接口测试

1. 目录结构

在这里插入图片描述

  • 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 启动服务

  • 按上一章 《crow-han(基于go-micro框架的微服务脚手架)-01-快速启动》方法配置数据库并启动gate-way、auth、user。

  • goland配置k8s服务并启动
    在这里插入图片描述

  • consul上查看
    我们新写的微服务注册上来了
    在这里插入图片描述

5.2 swagger接口测试

  • 获取token
    默认用户名密码:admin/liubei@161
    在这里插入图片描述
    输出结果
    在这里插入图片描述
  • Bearer验证
    点开锁标记,输入 Bearer xxxxxxxxxxx(xxxx 是刚才获取的token值)
    在这里插入图片描述
  • 验证我们之前写的接口

在这里插入图片描述

输出如下:
在这里插入图片描述


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540471.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自学黑客(网络安全)有哪些技巧——初学者篇

很多人说,要想学好黑客技术,首先你得真正热爱它。 热爱,听着多么让人激情澎湃,甚至热泪盈眶。 但很可惜,“热爱”这个词对还没入门的小白完全不管用。 如果一个人还没了解过你就说爱你,不是骗财就是骗色…

第三十四章 使用react-redux进一步管理状态

react-redux和redux是两个不同的概念。 redux是一个重要的数据管理库。redux的作用是帮助处理应用程序中复杂的数据管理和状态管理,它可以让你的应用程序更加可维护和可扩展。 react-redux是一个react库,它可以帮助react开发者在react应用程序中集成re…

Java经典笔试题—day11

Java经典笔试题—day11 🔎选择题🔎编程题🥝最近公共祖先🥝最大连续bit数 🔎结尾 🔎选择题 (1)下面哪个标识符是合法的? A.9HelloWorld B._Hello World C.Hello*World D.Hello$World D Java中标…

操作符讲解1---C语言

目录 前言: 1.什么是操作符 2.算术操作符 3.移位操作符 4.位操作符 5.逻辑操作符 5.1逻辑与 5.2逻辑或 5.3练习 5.4逻辑非 前言: 博主这几天都在积累知识,俗话说:”只有多输入才能有输出”。在写博客之前,也…

一文1000字从0到1实现Jenkins+Allure+Pytest的持续集成

一、配置 allure 环境变量 1、下载 allure是一个命令行工具,可以去 github 下载最新版:https://github.com/allure-framework/allure2/releases 2、解压到本地 3、配置环境变量 复制路径如:F:\allure-2.13.7\bin 环境变量、Path、添加 F:\…

【硬核】C语言指针是什么?深入浅出带你掌握C语言指针!

指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问,本文章内容如下 1、C语言指针的作用 2、计算机的存储机制 3、如何定义指针 4、如何操作指针 5、数组与指针的关系 6、指针使用中的一些注意事项 1、C语言指针有什么作用…

企业级架构设计原则(含架构管理原则、业务架构设计原则、应用架构设计原则、数据架构设计原则、技术架构设计原则)

Togaf中的架构原则是一组用于指导企业架构设计和决策的基本准则。这些原则旨在支持组织的目标、价值观和战略,并提供一致性、可持续性和可扩展性的架构方案。 Togaf中提供了一些常见的架构原则,比如:保持一致性:确保架构与组织的目…

MySQL 性能调优及生产实战篇(二)

前言数据结构HASHBinary Search Trees、AVL TreesRed/Black TreesB TreesB Trees 数据存储InnoDBMyISAM 索引优化索引匹配方式哈希索引组合索引聚簇、非聚簇索引覆盖索引 优化细节(important)数据库勿做计算尽量主键查询前缀索引索引扫描排序子查询范围列…

干货满满---90条简单实用的Python编程技巧

对于Python,想必大家都不陌生,自从它问世以来得到了广大编程爱好者的追捧和喜爱,但是再好的东西都需要讲究技巧和策略方法,才能达到事半功倍的效果,下面是我近几年的学习心得和总结,希望能对大家带来一定帮…

不懂就要问,现在的物联卡还有人用吗?

很多朋友私信小编,现在的物联卡还能买吗? 当然,对于企业设备来讲,物联卡是一直可以使用的,而且非常稳定。 如果是用在个人手机上面,可以说也是可以用的,只不过是使用时间长短的问题。 ​ 下面…

ChatGPT为企业应用赋能

chatgpt-on-wechat和bot-on-anything两个项目都支持企业微信部署,其中前者功能比较丰富,推荐! 如需帮助,可以搜索wx:Youngerer 找到我! 功能展示: ![在这里插入图片描述](https://img-blog.csd…

【Linux升级之路】3_Linux进程概念

🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux升级之路】 ✒️✒️本篇内容:认识冯诺依曼系统,操作系统概念与定位,深入理解进程概念(了解PCB&…

C语言函数大全-- m 开头的函数(2)

C语言函数大全 本篇介绍C语言函数大全-- m 开头的函数 1. mkdirat 1.1 函数说明 函数声明函数功能int mkdirat(int dirfd, const char *pathname, mode_t mode);它是一个 Linux 系统下的系统调用函数,用于在指定目录下创建新的子目录 参数: dirfd &a…

推荐一个一键AI抠图网站

一键去除图片背景 在这个数字化的世界里,我们经常需要处理各种图片,无论是用于个人的社交媒体,还是用于商业的广告设计。 然而,图片处理往往需要专业的技能和复杂的软件,这对许多人来说可能是个挑战。但现在&#xf…

3. Python字符串

文章目录 一、修改字符串大小写1.1 将字符串中每个单词的首字母改为大写1.2 将字符串中所有的字母改为大写1.3 将字符串中所有的字母改为小写 二、拼接字符串三、添加空白3.1 使用制表符添加空白3.2 使用换行符添加空白3.3 制表符和换行符同时使用 四、删除空白4.1 仅去掉字符串…

redis单机安装

1. 安装gcc 2.下载并编译redis wget http://download.redis.io/releases/redis-7.0.4.tar.gz 直接下载到虚拟机中解压 编译 安装redis 执行命令: make install PREFIX/usr/local/redis/ ,会将redis安装到指定目录下,在这个目录下会生产bin目录 在安…

《花雕学AI》人类推理能力对AI来说是什么?用ChatGPT来检验一下

”这里有一本书、九个鸡蛋、一台笔记本电脑、一个瓶子和一个钉子,请告诉我如何把它们稳定地堆叠在一起?“ 这是去年提出的一道测试推理能力的题目,当微软的计算机科学家开始试验一种新的AI系统时,他们要求AI解决这个难题&#xf…

【Java 并发编程】CAS 原理解析

CAS 原理解析 1. 什么是 CAS?1.1 悲观锁与乐观锁1.2 CAS 是什么? 2. CAS 核心源码3. CAS 实现原子操作的三大问题3.1 ABA 问题3.2 循环性能开销3.3 只能保证一个变量的原子操作 4. synchronized、volatile、CAS 比较 1. 什么是 CAS? 1.1 悲观…

物业企业多种类型合同,用泛微今承达实现统一数字化管理

随着物业业务的不断发展,物业服务越来越精细化、专业化,旨在为居民社区提供更便利的服务。 物业企业提供多种形态、全方位、立体式的综合服务,包括基础物业服务、业主增值服务(空间运营收入、房屋经纪、电商服务、社区金融、家政服务及养老服…

手撕-扫雷

一、前言-认识扫雷 二、打印菜单 三、创建棋盘并初始化 四、打印棋盘 五、布置雷 六、排查雷(统计坐标周围雷的个数) 七、扫雷代码全析(game.h game.c test.c) 铁汁们,今天给大家分享一篇扫雷游戏的实现&#…