【云原生开发】k8s后台管理系统开发接口优化方案

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑

🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。

🏆《博客》:Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏: 云原生开发
景天的主页: 景天科技苑

文章目录

  • 接口优化
    • [1. 首先先安装下kubeutils](#1. 首先先安装下kubeutils)
    • [2. 使用接口改造controllers.go](#2. 使用接口改造controllers.go)
    • [3. 创建pod功能实现](#3. 创建pod功能实现)
    • [4. 查询pod列表功能实现](#4. 查询pod列表功能实现)
    • [5. 获取pod详情功能实现](#5. 获取pod详情功能实现)
    • [6. 更新pod功能](#6. 更新pod功能)
    • [7. 删除单个pod和批量删除pod功能](#7. 删除单个pod和批量删除pod功能)

接口优化

观察前面我们开发的代码,我们发现,每种资源都有类似的增删改查逻辑,如果我们把这些类似的逻辑,做成统一的接口,就不用每种资源都需要写重复的代码了。

该怎么设计呢?

我们基于命名空间的struct,写增删改查方法,然后让各类资源去调用

我们使用一个接口工具来优化代码

接口工具地址:https://github.com/littlefun91/kubeutils

功能使用方法

1. 首先先安装下kubeutils

bash 复制代码
go get -u github.com/littlefun91/kubeutils

2. 使用接口改造controllers.go

创建各种资源,都可以使用这里面通用的增删改查方法

go 复制代码
// Package controllers 控制器层,实现路由的逻辑处理
package controllers

import (
    "errors"
    "github.com/gin-gonic/gin"
    "github.com/littlefun91/kubeutils/kubeutils"
    "jingtian/krm-backend/config"
    "jingtian/krm-backend/utils/logs"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "net/http"
)

// BasicInfo 定义全局的数据结构
type BasicInfo struct {
    //使用form标签指定参数名,以便正确地绑定参数 get请求使用功能form标签
    ClusterId  string      `json:"clusterId" form:"clusterId"`
    Namespace  string      `json:"namespace" form:"namespace"`
    Name       string      `json:"name" form:"name"`
    Item       interface{} `json:"item"`       //用来接收前端传来的更新资源的json串
    DeleteList []string    `json:"deleteList"` //用来接收前端传来的删除资源的json串,可以删一个,也可以删多个
}

type Info struct {
    BasicInfo
    ReturnData    config.ReturnData
    LabelSelector string `json:"labelSelector" form:"labelSelector"`
    FieldSelector string `json:"fieldSelector" form:"fieldSelector"`
    // 判断是否是强制删除
    Force bool `json:"force" form:"force"`
}

// NewInfo 定义一个函数,用来返回kubeconfig
func NewInfo(c *gin.Context, info *Info, returnDataMsg string) (kubeconfig string) {
    // 首先获取请求的类型
    requestMethod := c.Request.Method
    var err error
    // var returnData config.ReturnData
    info.ReturnData.Msg = returnDataMsg
    info.ReturnData.Status = 200
    if requestMethod == "GET" {
        err = c.ShouldBindQuery(&info)
    } else if requestMethod == "POST" {
        err = c.ShouldBindJSON(&info)
    } else {
        err = errors.New("不支持的请求类型")
    }
    logs.Debug(map[string]interface{}{"info": info}, "数据绑定结果")
    if err != nil {
        msg := "请求出错: " + err.Error()
        info.ReturnData.Msg = msg
        info.ReturnData.Status = 400
        logs.Error(nil, msg)
        c.JSON(http.StatusOK, info.ReturnData)
        return
    }
    // 获取kubeconfig
    kubeconfig = config.ClusterKubeconfig[info.ClusterId]

    //我们的接口工具只需要接收个kubeconfig文件就可以实现增删改查了
    return kubeconfig
}

// Create Info中的增删改查方法,重写kubeutils中的增删改查方法
func (i *Info) Create(c *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    //Create里面传参是namespace
    err := kubeUtilsInterface.Create(i.Namespace)
    if err != nil {
        msg := "创建失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    }
    c.JSON(200, i.ReturnData)
}

func (i *Info) Update(r *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    err := kubeUtilsInterface.Update(i.Namespace)
    if err != nil {
        msg := "更新失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    }
    r.JSON(200, i.ReturnData)
}
func (i *Info) List(c *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    items, err := kubeUtilsInterface.List(i.Namespace, i.LabelSelector, i.FieldSelector)
    if err != nil {
        msg := "查询失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    } else {
        i.ReturnData.Data = make(map[string]interface{})
        i.ReturnData.Data["items"] = items
    }
    c.JSON(200, i.ReturnData)
}

func (i *Info) Get(c *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    item, err := kubeUtilsInterface.Get(i.Namespace, i.Name)
    if err != nil {
        msg := "查询失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    } else {
        i.ReturnData.Data = make(map[string]interface{})
        i.ReturnData.Data["item"] = item
    }
    c.JSON(200, i.ReturnData)
}

func (i *Info) Delete(c *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    var gracePeriodSeconds int64
    if i.Force {
        // 强制删除
        var s int64 = 0
        gracePeriodSeconds = s
    }
    err := kubeUtilsInterface.Delete(i.Namespace, i.Name, &gracePeriodSeconds)
    if err != nil {
        msg := "删除失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    }
    c.JSON(200, i.ReturnData)
}

func (i *Info) DeleteList(c *gin.Context, kubeUtilsInterface kubeutils.KubeUtilser) {
    var gracePeriodSeconds int64
    if i.Force {
        // 强制删除
        var s int64 = 0
        gracePeriodSeconds = s
    }
    err := kubeUtilsInterface.DeleteList(i.Namespace, i.BasicInfo.DeleteList, &gracePeriodSeconds)
    if err != nil {
        msg := "删除失败: " + err.Error()
        i.ReturnData.Msg = msg
        i.ReturnData.Status = 400
        logs.Error(nil, msg)
    }
    c.JSON(200, i.ReturnData)
}

// BasicInit 这个函数用来返回通用的clientset,集群信息和error
func BasicInit(c *gin.Context, item interface{}) (clientset *kubernetes.Clientset, basicInfo BasicInfo, err error) {
    basicInfo = BasicInfo{}
    //根据传参,来确定Item的类型,可以接收任意的资源
    basicInfo.Item = item
    // 首先获取请求的类型,根据不同的请求类型来使用不同的方式绑定数据
    requestMethod := c.Request.Method
    if requestMethod == "GET" {
        err = c.ShouldBindQuery(&basicInfo)
    } else if requestMethod == "POST" {
        err = c.ShouldBindJSON(&basicInfo)
    } else {
        err = errors.New("不支持的请求类型")
    }
    logs.Debug(map[string]interface{}{"basicInfo": basicInfo}, "数据绑定结果")
    if err != nil {
        msg := "请求出错: " + err.Error()
        return nil, basicInfo, errors.New(msg)
    }
    //如果前端不传namespace,就用默认的命名空间
    if basicInfo.Namespace == "" {
        basicInfo.Namespace = "default"
    }
    // 获取kubeconfig
    kubeconfig := config.ClusterKubeconfig[basicInfo.ClusterId]
    restConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeconfig))
    if err != nil {
        msg := "解析kubeconfig错误: " + err.Error()
        return nil, basicInfo, errors.New(msg)
    }
    //创建客户端
    clientset, err = kubernetes.NewForConfig(restConfig)
    if err != nil {
        msg := "创建clientset失败: " + err.Error()
        return nil, basicInfo, errors.New(msg)
    }
    return clientset, basicInfo, nil
}

3. 创建pod功能实现

pod/creaet.go

go 复制代码
package pod

import (
    "github.com/gin-gonic/gin"
    "github.com/littlefun91/kubeutils/kubeutils"
    "jingtian/krm-backend/controllers"
    "jingtian/krm-backend/utils/logs"
    corev1 "k8s.io/api/core/v1"
)

// Create 创建namespace函数
func Create(c *gin.Context) {
    logs.Debug(nil, "创建pod")
    var pod corev1.Pod
    var info controllers.Info
    info.Item = &pod
    kubeconfig := controllers.NewInfo(c, &info, "pod创建成功")

    //改为接口形式的创建
    var kubeUtilser kubeutils.KubeUtilser
    instance := kubeutils.NewPod(kubeconfig, &pod)
    // 把实例复制给kubeUtilser
    kubeUtilser = instance
    // 使用kubeUtilser创建资源
    info.Create(c, kubeUtilser)
}

执行创建请求

yaml 复制代码
{
    "clusterId":"cluster01",
    "namespace":"jingtian",
    "item": {
        "apiVersion": "v1",
        "kind": "Pod",
        "metadata": {
            "labels": {
                "app": "web6"
            },
            "name": "web6"
        },
        "spec": {
            "containers": [
                {
                    "env": [
                        {
                            "name": "GIN_MODE",
                            "value": "release"
                        },
                        {
                            "name": "LOG_LEVEL",
                            "value": "info"
                        }
                    ],
                    "image": "web:v4",
                    "imagePullPolicy": "IfNotPresent",
                    "name": "myweb",
                    "ports": [
                        {
                            "containerPort": 8080,
                            "protocol": "TCP"
                        }
                    ]

                }
            ]
        }
    }
}

k8s集群查看,pod创建成功

4. 查询pod列表功能实现

go 复制代码
package pod

import (
    "github.com/gin-gonic/gin"
    "github.com/littlefun91/kubeutils/kubeutils"
    "jingtian/krm-backend/controllers"
    "jingtian/krm-backend/utils/logs"
)

func List(c *gin.Context) {
    logs.Debug(nil, "列出pod列表")
    //声明结构体,用结构体的方法创建资源
    var info controllers.Info
    //newInfo里面传默认的returndata.msg
    kubeconfig := controllers.NewInfo(c, &info, "pod查询成功")

    var kubeUtilser kubeutils.KubeUtilser
    instance := kubeutils.NewPod(kubeconfig, nil)
    // 把实例复制给kubeUtilser
    kubeUtilser = instance
    // 使用kubeUtilser查询资源
    info.List(c, kubeUtilser)

}

查询成功

5. 获取pod详情功能实现

go 复制代码
 package pod

import (
    "github.com/gin-gonic/gin"
    "github.com/littlefun91/kubeutils/kubeutils"
    "jingtian/krm-backend/controllers"
    "jingtian/krm-backend/utils/logs"
)

func Get(c *gin.Context) {
    logs.Debug(nil, "获取pod详情")
    //声明结构体,用结构体的方法创建资源
    var info controllers.Info
    //newInfo里面传默认的returndata.msg
    kubeconfig := controllers.NewInfo(c, &info, "pod查询详情成功")

    var kubeUtilser kubeutils.KubeUtilser
    instance := kubeutils.NewPod(kubeconfig, nil)
    // 把实例复制给kubeUtilser
    kubeUtilser = instance
    // 使用kubeUtilser查询资源
    info.Get(c, kubeUtilser)

}

postman请求

6. 更新pod功能

一般,工作中我们也很少去更新pod。暂时不支持更新pod操作,响应给前端。

go 复制代码
package pod

import (
    "github.com/gin-gonic/gin"
    "jingtian/krm-backend/config"
    "jingtian/krm-backend/utils/logs"
)

func Update(c *gin.Context) {
    logs.Debug(nil, "更新pod")
    var returnData config.ReturnData
    returnData.Msg = "Pod暂不支持更新操作"
    returnData.Status = 200
    c.JSON(200, returnData)
}

7. 删除单个pod和批量删除pod功能

go 复制代码
package pod

import (
    "github.com/gin-gonic/gin"
    "github.com/littlefun91/kubeutils/kubeutils"
    "jingtian/krm-backend/controllers"
    "jingtian/krm-backend/utils/logs"
)

// Delete 删除命名空间
func Delete(c *gin.Context) {
    logs.Debug(nil, "删除单个pod")
    //声明结构体,用结构体的方法创建资源
    var info controllers.Info
    //newInfo里面传默认的returndata.msg
    kubeconfig := controllers.NewInfo(c, &info, "pod删除成功")

    var kubeUtilser kubeutils.KubeUtilser
    instance := kubeutils.NewPod(kubeconfig, nil)
    // 把实例复制给kubeUtilser
    kubeUtilser = instance
    // 使用kubeUtilser查询资源
    info.Delete(c, kubeUtilser)

}

// DeleteList 批量删除
func DeleteList(c *gin.Context) {
    logs.Debug(nil, "批量删除pod")
    //声明结构体,用结构体的方法创建资源
    var info controllers.Info
    //newInfo里面传默认的returndata.msg
    kubeconfig := controllers.NewInfo(c, &info, "pod批量删除成功")

    var kubeUtilser kubeutils.KubeUtilser
    instance := kubeutils.NewPod(kubeconfig, nil)
    // 把实例复制给kubeUtilser
    kubeUtilser = instance
    // 使用kubeUtilser查询资源
    info.DeleteList(c, kubeUtilser)

}

看下目前jingtian命名空间下的pod

postman执行删除单个pod

集群查看,删除单个pod成功

批量删除pod

集群查看,批量删除pod成功

相关推荐
why15123 分钟前
腾讯(QQ浏览器)后端开发
开发语言·后端·golang
张帅涛_6661 小时前
golang goroutine(协程)和 channel(管道) 案例解析
jvm·golang·go
zxnbmk3 小时前
pod内部共享命名空间与k8s命名空间是一个东西吗?
云原生·容器·kubernetes·namespaces
一颗知足的心4 小时前
Go语言之路————指针、结构体、方法
开发语言·后端·golang
LKAI.5 小时前
k8s存储动态供给StorageClass
docker·微服务·云原生·容器·kubernetes
言之。7 小时前
【Go语言】ORM(对象关系映射)库
开发语言·后端·golang
席万里7 小时前
Go语言企业级项目使用dlv调试
服务器·开发语言·golang
孔令飞7 小时前
使用 Go 与 Redis Streams 构建可靠的事件驱动系统
redis·ai·云原生·golang·kubernetes
yuanlaile8 小时前
Go全栈_Golang、Gin实战、Gorm实战、Go_Socket、Redis、Elasticsearch、微服务、K8s、RabbitMQ全家桶
linux·redis·golang·k8s·rabbitmq·gin
阿里云云原生9 小时前
理工科 MCP Server 神器,补足人工智能幻觉短板
云原生