【GO】K8s 管理系统项目[API部分--Workflow]

news2024/11/5 23:58:20

K8s 管理系统项目[API部分–Workflow]

年终于算过完了,身体也康复了,继续学习

1. DB设置

1.1 连接配置

service/config.go

package config

import "time"

const (
	ListenAddr = "0.0.0.0:9091"
	KubeConfig = "D:\\golang\\k8s-plantform\\config\\cka"
	//KubeConfig = "D:\\golang\\k8s-plantform\\config\\config"
	// tail 的日志行数
	PodLogTailLine = 2000

	// DB Config
	DbType = "mysql"
	DbHost = "192.168.31.24"
	DbPort = 3306
	DbName = "k8s_dashboard"
	DbUser = "root"
	DbPass = "123456"
	// 打印mysql debug的sql日志
	LogMode = false
	// 连接池配置
	MaxIdleConns = 10               // 最大空闲连接
	MaxOpenConns = 100              // 最大连接数
	MaxLifeTime  = 30 * time.Second // 会话时间
)

1.2 初始化

db/init.go

package db

import (
	"fmt"
	"k8s-plantform/config"
	"time"

	"github.com/wonderivan/logger"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

var (
	isInit bool
	GORM   *gorm.DB
	err    error
)

// DB的初始化函数,与数据库建立连接
func Init() {
	// 判断是否已经初始化
	if isInit {
		return
	}
	// 组装连接配置
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local",
		config.DbUser,
		config.DbPass,
		config.DbHost,
		config.DbPort,
		config.DbName)
	GORM, err = gorm.Open(config.DbType, dsn)
	if err != nil {
		panic("数据库连接失败," + err.Error())
	}
	// 打印sql语句
	GORM.LogMode(config.LogMode)
	// 开启连接池
	GORM.DB().SetMaxIdleConns(config.MaxIdleConns)
	GORM.DB().SetMaxOpenConns(config.MaxOpenConns)
	GORM.DB().SetConnMaxLifetime(time.Duration(config.MaxLifeTime))
	isInit = true
	logger.Info("数据库初始化成功")
}

// 关闭数据库连接
func Close() error {
	return GORM.Close()
}

1.3 初始化

main.go

package main
import (
	"fmt"
	"k8s-plantform/config"
	"k8s-plantform/controller"
	"k8s-plantform/db"
	"k8s-plantform/service"
	"github.com/gin-gonic/gin"
)

func main() {
	// 初始化数据库
	db.Init()
	// 初始化k8s client
	service.K8s.Init()
	// 初始化gin
	r := gin.Default()
	controller.Router.InitApiRouter(r)
	// gin 程序启动
	//r.Run(config.ListenAdd)
	fmt.Println("http://192.168.31.1:9091/")
	r.Run(config.ListenAddr)
	// 关闭数据库
	db.Close()
}

1.4 创建数据库

创建数据库

请添加图片描述

重启服务确认数据库连接正常

请添加图片描述

1.5 表结构

model/workflow.go

package model

import "time"

//定义结构体,属性与mysql表字段对齐
type Workflow struct {
	//gorm:"primaryKey"用于声明主键
	ID        uint        `json:"id" gorm:"primaryKey"`
	CreatedAt *time.Time  `json:"created_at"`
	UpdatedAt *time.Time  `json:"updated_at"`
	DeletedAt *time.Time  `json:"deleted_at"`

	Name        string `json:"name"`
	Namespace   string `json:"namespace"`
	Replicas    int32  `json:"replicas"`
	Deployment  string `json:"deployment"`
	Service     string `json:"service"`
	Ingress     string `json:"ingress"`
	//gorm:"column:type"用于声明mysql中表的字段名
	Type        string `json:"type" gorm:"column:type"`
}
//定义TableName方法,返回mysql表名,以此来定义mysql中的表名
func(*Workflow) TableName() string {
	return "workflow"
}

1.6 创建workflow表

连接数据库,在命令行或管理工具中创建workflow表

CREATE TABLE `workflow` ( 
	`id` int NOT NULL AUTO_INCREMENT,
	`name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL,
	`namespace` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
	`replicas` int DEFAULT NULL,
	`deployment` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
	`service` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
	`ingress` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
	`type` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
	`created_at` datetime DEFAULT NULL,
	`updated_at` datetime DEFAULT NULL,
	`deleted_at` datetime DEFAULT NULL,
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE KEY `name` (`name`)
	) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2. Workflow dao

dao/workflow.go

package dao

import (
	"errors"
	"k8s-plantform/db"
	"k8s-plantform/model"

	"github.com/wonderivan/logger"
)

var Workflow workflow

type workflow struct{}

type WorkflowResp struct {
	Items []*model.Workflow `json:"items"`
	Total int               `json:"total"`
}

// 获取workflow列表
func (w *workflow) GetWorkflows(filterName, namespace string, limit, page int) (data *WorkflowResp, err error) {
	//定义分页的起始位置
	startSet := (page - 1) * limit
	//定义数据库查询返回的内容
	var (
		workflowList []*model.Workflow
		total        int
	)
	//数据库查询,Limit方法用于限制条数,Offset方法用于设置起始位置
	tx := db.GORM.
		Model(&model.Workflow{}).
		Where("name like ?", "%"+filterName+"%").
		Count(&total).
		Limit(limit).
		Offset(startSet).
		Order("id desc").
		Find(&workflowList)
	if tx.Error != nil && tx.Error.Error() != "record not found" {
		logger.Error("获取Workflow列表失败, " + tx.Error.Error())
		return nil, errors.New("获取Workflow列表失败, " + tx.Error.Error())
	}
	return &WorkflowResp{
		Items: workflowList,
		Total: total,
	}, nil
}

// 获取详情
func (w *workflow) GetById(id int) (workflow *model.Workflow, err error) {
	workflow = &model.Workflow{}
	tx := db.GORM.Where("id = ?", id).First(&workflow)
	if tx.Error != nil && tx.Error.Error() != "record not found" {
		logger.Error("获取Workflow详情失败, " + tx.Error.Error())
		return nil, errors.New("获取Workflow详情失败, " + tx.Error.Error())
	}
	return workflow, nil
}

// 创建
func (w *workflow) Add(workflow *model.Workflow) (err error) {
	tx := db.GORM.Create(&workflow)
	if tx.Error != nil && tx.Error.Error() != "record not found" {
		logger.Error("创建Workflow失败, " + tx.Error.Error())
		return errors.New("创建Workflow失败, " + tx.Error.Error())
	}
	return nil
}

// 删除
func (w *workflow) DelById(id int) (err error) {
	tx := db.GORM.Where("id = ?", id).Delete(&model.Workflow{})
	if tx.Error != nil && tx.Error.Error() != "record not found" {
		logger.Error("获取Workflow详情失败, " + tx.Error.Error())
		return errors.New("获取Workflow详情失败, " + tx.Error.Error())
	}
	return nil
}

3. Workflow Service

service/workflow.go

package service

import (
	"k8s-plantform/dao"
	"k8s-plantform/model"
)

var Workflow workflow

type workflow struct {}

//定义workflowCreate类型
type WorkflowCreate struct {
	Name           string  `json:"name"`
	Namespace      string  `json:"namespace"`
	Replicas       int32   `json:"replicas"`
	Image          string  `json:"image"`
	Label          map[string]string  `json:"label"`
	Cpu            string  `json:"cpu"`
	Memory         string  `json:"memory"`
	ContainerPort  int32   `json:"container_port"`
	HealthCheck    bool    `json:"health_check"`
	HealthPath     string  `json:"health_path"`
	Type           string  `json:"type"`
	Port           int32   `json:"port"`
	NodePort       int32   `json:"node_port"`
	Hosts          map[string][]*HttpPath `json:"hosts"`
}

//获取列表分页查询
func(w *workflow) GetList(name, namespace string, page, limit int) (data *dao.WorkflowResp, err error) {
	data, err = dao.Workflow.GetWorkflows(name, namespace, page, limit)
	if err != nil {
		return nil, err
	}
	return data, nil
}

//查询workflow单条数据
func(w *workflow) GetById(id int) (data *model.Workflow, err error) {
	data, err = dao.Workflow.GetById(id)
	if err != nil {
		return nil, err
	}
	return data, nil
}



//创建workflow
func(w *workflow) CreateWorkFlow(data *WorkflowCreate) (err error) {
	//定义ingress名字
	var ingressName string
	if data.Type == "Ingress" {
		ingressName = getIngressName(data.Name)
	} else {
		ingressName = ""
	}

	//workflow数据落库
	workflow := &model.Workflow{
		Name:       data.Name,
		Namespace:  data.Namespace,
		Replicas:   data.Replicas,
		Deployment: data.Name,
		Service:    getServiceName(data.Name),
		Ingress:    ingressName,
		Type:       data.Type,
	}
	err = dao.Workflow.Add(workflow)
	if err != nil {
		return err
	}
	//创建k8s资源
	err = createWorkflowRes(data)
	if err != nil {
		return err
	}

	return err
}

//删除workflow
func(w *workflow) DelById(id int) (err error) {
	//获取数据库数据
	workflow, err := dao.Workflow.GetById(id)
	if err != nil {
		return err
	}
	//删除k8s资源
	err = delWorkflowRes(workflow)
	if err != nil {
		return err
	}
	//删除数据库数据
	err = dao.Workflow.DelById(id)
	if err != nil {
		return err
	}

	return
}

//删除k8s资源 deployment service ingress
func delWorkflowRes(workflow *model.Workflow) (err error) {
	err = Deployment.DeleteDeployment(workflow.Name, workflow.Namespace)
	if err != nil {
		return err
	}
	err = Servicev1.DeleteService(getServiceName(workflow.Name), workflow.Namespace)
	if err != nil {
		return err
	}

	if workflow.Type == "Ingress" {
		err = Ingress.DeleteIngress(getIngressName(workflow.Name), workflow.Namespace)
		if err != nil {
			return err
		}
	}

	return nil
}

//创建k8s资源 deployment service ingress
func createWorkflowRes(data *WorkflowCreate) (err error) {

	//创建deployment
	dc := &DeployCreate{
		Name:          data.Name,
		Namespace:     data.Namespace,
		Replicas:      data.Replicas,
		Image:         data.Image,
		Label:         data.Label,
		Cpu:           data.Cpu,
		Memory:        data.Memory,
		ContainerPort: data.ContainerPort,
		HealthCheck:   data.HealthCheck,
		HealthPath:    data.HealthPath,
	}
	err = Deployment.CreateDeployment(dc)
	if err != nil {
		return err
	}
	var serviceType string
	if data.Type != "Ingress" {
		serviceType = data.Type
	} else {
		serviceType = "ClusterIP"
	}
	//创建service
	sc := &ServiceCreate{
		Name:          getServiceName(data.Name),
		Namespace:     data.Namespace,
		Type:          serviceType,
		ContainerPort: data.ContainerPort,
		Port:          data.Port,
		NodePort:      data.NodePort,
		Label:         data.Label,
	}
	if err := Servicev1.CreateService(sc); err != nil {
		return err
	}
	//创建ingress
	var ic *IngressCreate
	if data.Type == "Ingress" {
		ic = &IngressCreate{
			Name:      getIngressName(data.Name),
			Namespace: data.Namespace,
			Label:     data.Label,
			Hosts:     data.Hosts,
		}
		err = Ingress.CreateIngress(ic)
		if err != nil {
			return err
		}
	}

	return nil
}


//workflow名字转换成service名字,添加-svc后缀
func getServiceName(workflowName string) (serviceName string) {
	return workflowName + "-svc"
}
//workflow名字转换成ingress名字,添加-ing后缀
func getIngressName(workflowName string) (ingressName string) {
	return workflowName + "-ing"
}

4. Workflow controller

controller/workflow.go

package controller

import (
	"k8s-plantform/service"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/wonderivan/logger"
)

var Workflow workflow

type workflow struct{}

// 获取列表分页查询
func (w *workflow) GetList(ctx *gin.Context) {
	params := new(struct {
		Name      string `form:"name"`
		Namespace string `form:"namespace"`
		Page      int    `form:"page"`
		Limit     int    `form:"limit"`
	})
	if err := ctx.Bind(params); err != nil {
		logger.Error("Bind请求参数失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	data, err := service.Workflow.GetList(params.Name, params.Namespace, params.Limit, params.Page)
	if err != nil {
		logger.Error("获取Workflow列表失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "获取Workflow列表成功",
		"data": data,
	})
}

// 查询workflow单条数据
func (w *workflow) GetById(ctx *gin.Context) {
	params := new(struct {
		ID int `form:"id"`
	})
	if err := ctx.Bind(params); err != nil {
		logger.Error("Bind请求参数失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	data, err := service.Workflow.GetById(params.ID)
	if err != nil {
		logger.Error("查询Workflow单条数据失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "查询Workflow单条数据成功",
		"data": data,
	})
}

// 创建workflow
func (w *workflow) Create(ctx *gin.Context) {
	var (
		wc  = &service.WorkflowCreate{}
		err error
	)

	if err = ctx.ShouldBindJSON(wc); err != nil {
		logger.Error("Bind请求参数dc失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	if err = service.Workflow.CreateWorkFlow(wc); err != nil {
		logger.Error("创建Workflow失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "创建Workflow成功",
		"data": nil,
	})

}

// 删除workflow
func (w *workflow) DelById(ctx *gin.Context) {
	params := new(struct {
		ID int `json:"id"`
	})
	if err := ctx.ShouldBindJSON(params); err != nil {
		logger.Error("Bind请求参数失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	if err := service.Workflow.DelById(params.ID); err != nil {
		logger.Error("删除Workflow失败, " + err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "删除Workflow成功",
		"data": nil,
	})
}

5. Workflow路由

controller/router.go

		// workflows
		GET("/api/k8s/workflows", Workflow.GetList).
		GET("/api/k8s/workflow/detail", Workflow.GetById).
		POST("/api/k8s/workflow/create", Workflow.Create).
		DELETE("/api/k8s/workflow/del", Workflow.DelById)

6. 测试Workflow方法

5.1 获取Workflow

http://192.168.31.1:9091/api/k8s/workflows

请添加图片描述

5.2 获取Workflow详情

http://192.168.31.1:9091/api/k8s/workflow/detail?id=1

请添加图片描述

5.3 创建Workflow

http://192.168.31.1:9091/api/k8s/workflow/create
{
      "name": "test-7",
      "namespace": "default",
      "replicas": 1,
      "image": "nginx",
      "resource": "0.5/1",
      "health_check": false,
      "health_path": "",
      "label": {
            "app": "test-7"
      },
      "container_port": 80,
      "type": "Ingress",
      "port": 80,
      "node_port": null,
      "host": "www.bbb.com",
      "path": "/",
      "path_type": "Prefix",
      "cpu": "0.5",
      "memory": "1Gi",
      "hosts": {
            "www.ccc.com": [
			{
                  "path": "/",
                  "path_type":"Prefix",
                  "service_name": "test-7",
                  "service_port": 80
            }
			]
      }
}

请添加图片描述

此时,对应资源也一并被创建
请添加图片描述

请添加图片描述

5.4 删除Workflow

/api/k8s/ingress/del

就删除刚才创建的test-7.根据id再获取一次

请添加图片描述

k8s下也能获取到相关资源

请添加图片描述

删除一下
请添加图片描述

资源被删除

请添加图片描述

数据库是软删除,所以可以看到deleted时间

请添加图片描述

至此workflow完成

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

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

相关文章

有序表(中):Size Balanced Tree(SBT/SB树)

1、SB树简介 本质上是一棵二叉搜索树,SB树全称 Size Balanced Tree,顾名思义,这是一棵通过大小(Size)域来维持平衡的二叉搜索树。 它不仅支持简单的二叉搜索树操作,也支持 Select 和 Rank。 定义一下Siz…

每天一道大厂SQL题【Day10】电商分组TopK实战

每天一道大厂SQL题【Day10】电商分组TopK实战 大家好,我是Maynor。相信大家和我一样,都有一个大厂梦,作为一名资深大数据选手,深知SQL重要性,接下来我准备用100天时间,基于大数据岗面试中的经典SQL题&…

Linux入门篇(二)

Linux前言链接文件符号链接(软链接)硬链接shellshell 的类型shell的父子关系理解外部命令和内建命令外部命令内建命令Linux环境变量PATH环境变量前言 在这一章,我对Linux中有关shell较为深入的理解和环境变量方面知识的一个记录。同时&#x…

PBR工作流实现与对比

工作流实现工作流中的核心内容便是贴图,不论是UE4还是Unity都支持将PBR的参数以贴图的形式传入引擎,我们可以根据一个物体同一mesh或不同mesh的不同区域的属性差异来控制贴图上的属性产生不同,而没有贴图的话,一个物体只能使用一种…

Java Lambda表达式 匿名内部类 函数式接口(FunctionalInterface)

Java Lambda表达式定义背景示例匿名类实现Lambda表达式实现对比匿名类和Lambda实现Lambda表达式(调用)说明Lambda表达式的语法Java 1.8 新特性:函数式接口jdk 1.8 自带的函数式接口 (举例)定义 参考Oracle官网&#x…

目标检测6--R-FCN中的Position-Sensitive RoI Pooling

文章目录1.介绍2.Position-Sensitive Score Map 和 Position-Sensitive RoI Pooling3.源码参考资料欢迎访问个人网络日志🌹🌹知行空间🌹🌹 1.介绍 论文: Region-based Fully Convolutional Networks 代码: R-FCN 本论文作者同9.De…

电子组装流水线MES系统实行条码质量追溯

在电子制造行业,保证生产过程的稳定性与对制造关键能力的改善与提升,是大多数制造企业的管理重心,而缺乏有效的方法与手段。MES系统即制造执行系统,是企业信息集成的纽带,企业实施敏捷制造战略,实现车间生产…

C++学习记录——십 STL初级认识、标准库string类

文章目录1、什么是STL2、STL简介3、什么是string类4、string类的常用接口说明1、常见构造函数2、容量操作3、迭代器4、其他的标准库的string类关于string类的内容,可以在cplusplus.com查看到。 1、什么是STL STL是C标准库的重要组成部分,不仅是一个可复…

指 针

1.指针指针的作用: 可以通过指针间接访问内存(可以通过指针的保存一个地址(指针--地址))内存编号是从0开始记录的,一般用十六进制数字表示。可以利用指针变量保存地址指针变量的定义和使用指针变是定义语法: 数据类型 …

【MFC】模拟采集系统——图形按钮(18)

左边可以简单地使用一个组框,贴上背景图。当然,也可以使用新的对话框。 图形按钮类 1、类向导-》添加类-》选择MFC-》填入新类名称-》选择父类为 CButton 2、添加消息响应函数和虚函数: 消息响应mouse leave (离开) mouse move …

CSS3 animation-fill-mode详解

CSS3 animation-fill-mode详解 定义 animation-fill-mode 属性规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。 默认情况下,CSS 动画在第一个关键帧播放完之前不会影响元素&…

各CCFA类核心期刊的信息汇总与评价总结(科技领域)

CCF中文期刊投稿选择之篇章二:各CCFA类核心期刊的信息汇总与评价总结上一篇章总结一部分期刊的介绍自动化学报相关信息的介绍有关录用比、审稿速度及费用的相关数据收集相关学术论坛上网友的评价与讨论期刊年度出版概况与学术热点动态(知网)计算机学报相…

2023年可供学习的 10 大 SaaS 知识库工具!

客户迫切希望快速找到所需的信息。在软件行业尤其如此,因为软件行业节奏很快,公司经常销售学习曲线陡峭的产品。为了减缓流失率并提高盈利能力,SaaS 公司正在转向知识库,以帮助他们让客户了解情况。什么是知识库?您可以…

设计模式之代理模式详解和应用

目录1 代理模式定义2 代理模式的应用场景3 代理模式的通用写法4 从静态代理到动态代理5 静态模式在业务中的应用6 动态代理在业务中的应用7 手写JDK动态代理实现原理7.1 JDK动态代理的实现原理7.2 CGLib动态代理容易踩的坑8 CGLib代理调用API及原理分析9 CGLib和JDK动态代理对比…

JVM - 高效并发

目录 Java内存模型和内存间的交互操作 Java内存模型 内存间的交互操作 内存间交互操作的规则 volatile特性 多线程中的可见性 volatile 指令重排原理和规则 指令重排 指令重排的基本规则 多线程中的有序性 线程安全处理 锁优化 锁优化之自旋锁与自适应自旋 锁优…

jvisualvm工具使用

jdk自带的工具jvisualvm,可以分析java内存使用情况,jvm相关的信息。 1、设置jvm启动参数 设置jvm参数**-Xms20m -Xmx20m -XX:PrintGCDetails** 最小和最大堆内存,打印gc详情 2、测试代码 TestScheduleClassGc package com.core.schedule;…

LeetCode 82. 删除排序链表中的重复元素 II

原题链接 难度:middle\color{orange}{middle}middle 题目描述 给定一个已排序的链表的头 headheadhead , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。 示例 1: 输入:head [1,2,3,…

ASML逆袭史:人、资金、技术,缺一不可

前言 近年来,由于众所周知的原因,荷兰ASML(阿斯麦)公司的先进半导体制造设备——光刻机,进入普通大众视野,成为人们茶余饭后谈论的焦点话题之一。 1月底,“美日荷三方谈判达成协议,可…

Selenium自动化测试Python二:WebDriver基础

欢迎阅读WebDriver基础讲义。本篇讲义将会重点介绍Selenium WebDriver的环境搭建和基本使用方法。 WebDriver环境搭建 Selenium WebDriver 又称为 Selenium2。 Selenium 1 WebDriver Selenium 2 WebDriver是主流Web应用自动化测试框架,具有清晰面向对象 API&…

SAP ABAP 输出结果带有空格

方法一: 字段内容前增加空格,需使用全角空格,使用半角空格时,ALV显示无效,空格无法显示, 全角与半角的切换方法:shift空格切换, 如下的标记部分,要想通过ALV显示空格&…