kubernetes platform后端开发-项目初始

一、项目介绍

项目简介:Kubernetes Platform 是一个基于 Go 语言开发的 Kubernetes 集群管理平台,利用 Kubernetes 官方提供的 client-go 库进行构建。该平台旨在简化 Kubernetes 集群的日常操作和管理工作,提供一个友好的用户界面,使得用户无需直接与 kubectl 或 Kubernetes API 交互,即可执行各种集群管理任务。

核心特征:
  • 集群概览:提供集群的实时状态显示,包括节点、Pods、服务等关键信息。
  • 资源管理:允许用户创建、更新、删除和查看各种 Kubernetes 资源,例如部署、服务、配置映射等。
  • 日志查看:提供集群日志的检索和查看功能,帮助用户快速定位问题。
  • 监控与警告:集成监控工具,展示集群性能指标,并在出现潜在问题时提供警告通知。
  • 权限控制:支持 Kubernetes 的 RBAC,确保用户根据其角色访问和管理相应的资源。(未完成)
  • 多集群支持:可以同时管理和切换多个 Kubernetes 集群,适用于跨区域或多云环境。
  • 插件化架构:方便扩展新功能,用户可以根据需求定制和扩展平台。
技术栈:
  • Go语言:使用 Go 语言进行开发,确保了代码的高性能和高并发处理能力。
  • client-go:Kubernetes 官方的 Go 客户端库,用于与 Kubernetes API 服务器进行交互。
  • 前端框架:Vue3、ElementUIPlus。
  • 数据库:Mysql
  • 容器化与编排:(如Docker和Kubernetes,用于部署和运行管理平台)
部署环境
  • Golang3.6+
  • Mysql8.0

mysql数据导入:db/create.sql

默认密码:admin/123456

image

image

二、项目目录

image

  • apps:业务处理层
  • config:加载配置文件
  • db:初始化数据库的脚本
  • docs:项目文档
  • etc:项目需要的配置
  • exception:异常处理
  • ioc:使用ioc注册解决对象依赖问题
  • middle:中间件
  • response:响应统一处理
  • router:后端路由
  • test:单元测试
  • utils:自实现类

三、ioc注册容器

ioc/iocStore.go

package ioc

import (
    "fmt"
)

type IocContainer struct {
    store map[string]IocObject
}

func (c *IocContainer) Init() error {
    fmt.Println(c.store)
    for _, obj := range c.store {
        if err := obj.Init(); err != nil {
            return err
        }
    }
    return nil
}
func (c *IocContainer) Register(obj IocObject) {
    fmt.Println(obj.Name())
    c.store[obj.Name()] = obj
}

func (c *IocContainer) GetObj(name string) IocObject {
    fmt.Println(c.store)
    return c.store[name]
}

ioc/interface.go

package ioc

type IocObject interface {
    Init() error
    Name() string
}

ioc/controller.go

package ioc

func Controller() *IocContainer {
    return controllerContainer
}

var controllerContainer = &IocContainer{
    store: map[string]IocObject{},
}

ioc/api.go

package ioc

func ApiHandler() *IocContainer {
    return ApiHandlerContainer
}

var ApiHandlerContainer = &IocContainer{
    store: map[string]IocObject{},
}

四、异常处理

exception/exception.go

package exception

import (
    "fmt"
    "net/http"
)

//
//  APIException
//  @Description: 业务自定义异常
//
type APIException struct {
    Code     int    `json:"code"`
    Message  string `json:"message"`
    Data     any    `json:"data"`
    HttpCode int    `json:"http_code"`
}

/*
 * Error
 * @Description: 实现error接口
 * @receiver e
 * @return string
 */
func (e *APIException) Error() string {
    return e.Message
}

func NewApiException(code int, format string, a ...any) *APIException {
    return &APIException{
        Code:     code,
        Message:  fmt.Sprintf(format, a...),
        HttpCode: http.StatusOK,
    }
}

exception/business.go

package exception

/*
 * NewJsonMarshalFailed
 * @Description: Json反序列化失败异常,异常码500
 * @param format
 * @param a
 * @return *APIException
 */
func NewJsonMarshalFailed(format string, a ...any) *APIException {
    return NewApiException(600, format, a...)
}

/*
 * NewUpdatePodsFailed
 * @Description:  更新pod信息失败,异常码501
 * @param format
 * @param a
 * @return *APIException
 */
func NewUpdatePodsFailed(format string, a ...any) *APIException {
    return NewApiException(501, format, a...)
}

/*
 * NewGetContainersFailed
 * @Description: 获取容器信息失败,异常码502
 * @param format
 * @param a
 * @return *APIException
 */
func NewGetContainersFailed(format string, a ...any) *APIException {
    return NewApiException(502, format, a...)
}

/*
 * NewGetPodLogsFailed
 * @Description: 获取pod日志失败,异常码503
 * @param format
 * @param a
 * @return *APIException
 */
func NewGetPodLogsFailed(format string, a ...any) *APIException {
    return NewApiException(503, format, a...)
}

/*
 * NewGetPodListFailed
 * @Description: 获取pod列表失败,异常码504
 * @param format
 * @param a
 * @return *APIException
 */
func NewGetPodListFailed(format string, a ...any) *APIException {
    return NewApiException(504, format, a...)
}

/*
 * NewGetPaginateFailed
 * @Description: 获取分页数据失败,异常码505
 * @param format
 * @param a
 * @return *APIException
 */
func NewGetPaginateFailed(format string, a ...any) *APIException {
    return NewApiException(505, format, a...)
}

/*
 * NewDescribePodFailed
 * @Description: 获取pod详细信息失败,异常码506
 * @param format
 * @param a
 * @return *APIException
 */
func NewDescribePodFailed(format string, a ...any) *APIException {
    return NewApiException(506, format, a...)
}

/*
 * NewDeletePodFailed
 * @Description: 删除pod失败,异常码507
 * @param format
 * @param a
 * @return *APIException
 */
func NewDeletePodFailed(format string, a ...any) *APIException {
    return NewApiException(507, format, a...)
}

func NewGetNamespacePodsCountFailed(format string, a ...any) *APIException {
    return NewApiException(508, format, a...)
}
func CreateDeploymentListFailed(format string, a ...any) *APIException {
    return NewApiException(499, format, a...)
}
func GetDeploymentListFailed(format string, a ...any) *APIException {
    return NewApiException(509, format, a...)
}

func DescribeDeploymentFailed(format string, a ...any) *APIException {
    return NewApiException(510, format, a...)
}
func GetDeploymentScaleFailed(format string, a ...any) *APIException {
    return NewApiException(511, format, a...)
}
func UpdateDeploymentScaleFailed(format string, a ...any) *APIException {
    return NewApiException(512, format, a...)
}
func DeleteDeploymentFailed(format string, a ...any) *APIException {
    return NewApiException(513, format, a...)
}
func UpdateDeploymentFailed(format string, a ...any) *APIException {
    return NewApiException(514, format, a...)
}

func JsonUmarshalFailed(format string, a ...any) *APIException {
    return NewApiException(515, format, a...)
}
func GetDaemonSetListFailed(format string, a ...any) *APIException {
    return NewApiException(516, format, a...)
}
func DescribeDaemonSetFailed(format string, a ...any) *APIException {
    return NewApiException(517, format, a...)
}
func DeleteDaemonSetFailed(format string, a ...any) *APIException {
    return NewApiException(518, format, a...)
}
func UpdateDaemonSetFailed(format string, a ...any) *APIException {
    return NewApiException(519, format, a...)
}
func CreateDaemonSetFailed(format string, a ...any) *APIException {
    return NewApiException(520, format, a...)
}
func CreateStatefulSetFailed(format string, a ...any) *APIException {
    return NewApiException(521, format, a...)
}
func GetStatefulSetListFailed(format string, a ...any) *APIException {
    return NewApiException(522, format, a...)
}
func DescribeStatefulSetFailed(format string, a ...any) *APIException {
    return NewApiException(523, format, a...)
}
func DeleteStatefulSetFailed(format string, a ...any) *APIException {
    return NewApiException(524, format, a...)
}
func UpdateStatefulSetFailed(format string, a ...any) *APIException {
    return NewApiException(525, format, a...)
}
func GetNodeListFailed(format string, a ...any) *APIException {
    return NewApiException(526, format, a...)
}
func DescribeNodeListFailed(format string, a ...any) *APIException {
    return NewApiException(527, format, a...)
}
func InvalidParameter(format string, a ...any) *APIException {
    return NewApiException(528, format, a...)
}
func GetNamespaceFailed(format string, a ...any) *APIException {
    return NewApiException(529, format, a...)
}
func DescribeNamespaceFailed(format string, a ...any) *APIException {
    return NewApiException(530, format, a...)
}
func DeleteNamespaceFailed(format string, a ...any) *APIException {
    return NewApiException(531, format, a...)
}
func CreateNamespaceFailed(format string, a ...any) *APIException {
    return NewApiException(532, format, a...)
}
func CreatePVFailed(format string, a ...any) *APIException {
    return NewApiException(533, format, a...)
}
func DeletePVFailed(format string, a ...any) *APIException {
    return NewApiException(534, format, a...)
}
func GetPVListFailed(format string, a ...any) *APIException {
    return NewApiException(535, format, a...)
}
func DescribePVFailed(format string, a ...any) *APIException {
    return NewApiException(536, format, a...)
}

func DescribeSVCFailed(format string, a ...any) *APIException {
    return NewApiException(537, format, a...)
}
func GetSVCListFailed(format string, a ...any) *APIException {
    return NewApiException(538, format, a...)
}
func DeleteSVCFailed(format string, a ...any) *APIException {
    return NewApiException(539, format, a...)
}
func CreateSVCFailed(format string, a ...any) *APIException {
    return NewApiException(540, format, a...)
}
func UpdateSVCFailed(format string, a ...any) *APIException {
    return NewApiException(541, format, a...)
}

func DescribeIngressFailed(format string, a ...any) *APIException {
    return NewApiException(542, format, a...)
}
func GetIngressListFailed(format string, a ...any) *APIException {
    return NewApiException(543, format, a...)
}
func DeleteIngressFailed(format string, a ...any) *APIException {
    return NewApiException(544, format, a...)
}
func CreateIngressFailed(format string, a ...any) *APIException {
    return NewApiException(545, format, a...)
}
func UpdateIngressFailed(format string, a ...any) *APIException {
    return NewApiException(546, format, a...)
}
func GetConfigmapListFailed(format string, a ...any) *APIException {
    return NewApiException(547, format, a...)
}
func DescribeConfigmapListFailed(format string, a ...any) *APIException {
    return NewApiException(548, format, a...)
}
func UpdateConfigmapFailed(format string, a ...any) *APIException {
    return NewApiException(549, format, a...)
}
func DeleteConfigmapFailed(format string, a ...any) *APIException {
    return NewApiException(550, format, a...)
}
func CreateConfigmapFailed(format string, a ...any) *APIException {
    return NewApiException(551, format, a...)
}

func GetSecretListFailed(format string, a ...any) *APIException {
    return NewApiException(552, format, a...)
}
func DescribeSecretListFailed(format string, a ...any) *APIException {
    return NewApiException(553, format, a...)
}
func UpdateSecretFailed(format string, a ...any) *APIException {
    return NewApiException(554, format, a...)
}
func DeleteSecretFailed(format string, a ...any) *APIException {
    return NewApiException(555, format, a...)
}
func CreateSecretFailed(format string, a ...any) *APIException {
    return NewApiException(556, format, a...)
}

func GetPVCListFailed(format string, a ...any) *APIException {
    return NewApiException(557, format, a...)
}
func DescribePVCFailed(format string, a ...any) *APIException {
    return NewApiException(558, format, a...)
}
func UpdatePVCFailed(format string, a ...any) *APIException {
    return NewApiException(559, format, a...)
}
func DeletePVCFailed(format string, a ...any) *APIException {
    return NewApiException(560, format, a...)
}
func CreatePVCFailed(format string, a ...any) *APIException {
    return NewApiException(561, format, a...)
}
func CreateWorkFlowFailed(format string, a ...any) *APIException {
    return NewApiException(562, format, a...)
}
func DeleteWorkFlowFailed(format string, a ...any) *APIException {
    return NewApiException(563, format, a...)
}

func ValidateFailed(format string, a ...any) *APIException {
    return NewApiException(564, format, a...)
}
func CreateUserFailed(format string, a ...any) *APIException {
    return NewApiException(565, format, a...)
}
func DescribeUserFailed(format string, a ...any) *APIException {
    return NewApiException(566, format, a...)
}
func DeleteUserFailed(format string, a ...any) *APIException {
    return NewApiException(567, format, a...)
}

func UpdateUserFailed(format string, a ...any) *APIException {
    return NewApiException(568, format, a...)
}
func GetUserListFailed(format string, a ...any) *APIException {
    return NewApiException(569, format, a...)
}
func GetUserGroupListFailed(format string, a ...any) *APIException {
    return NewApiException(570, format, a...)
}
func DescribeUserGroupListFailed(format string, a ...any) *APIException {
    return NewApiException(570, format, a...)
}
func DeleteUserGroupFailed(format string, a ...any) *APIException {
    return NewApiException(571, format, a...)
}
func FindPermissionsFailed(format string, a ...any) *APIException {
    return NewApiException(572, format, a...)
}
func DeleteUserToGroupFailed(format string, a ...any) *APIException {
    return NewApiException(573, format, a...)
}
func DescribeUserToGroupFailed(format string, a ...any) *APIException {
    return NewApiException(574, format, a...)
}
func SignTokenFailed(format string, a ...any) *APIException {
    return NewApiException(575, format, a...)
}
func TokenValidationFailed(format string, a ...any) *APIException {
    return NewApiException(576, format, a...)
}
func CheckPasswordFailed(format string, a ...any) *APIException {
    return NewApiException(577, format, a...)
}

五、加载config文件,获取client-set实例

apps/k8sclient/client.go

package k8sclient

import (
    "fmt"
    "k8s-platform/config"
    "k8s-platform/ioc"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "os"
)

//
//  k8sClient
//  @Description:  k8sclient结构体包含了kubernetes.Clientset,这是与k8s API通信的主要方式
//
type K8sClient struct {
    ClientSet *kubernetes.Clientset
}

func init() {
    ioc.Controller().Register(&K8sClient{})
}

/*
 * NewK8sClient
 * @Description:  构造函数返回
 * @return *k8sClient
 */
func NewK8sClient() *K8sClient {
    return &K8sClient{}
}

/*
 * Init
 * @Description: Init方法初始化k8sclient 实例,它会设置客户端与kubetnetes集群通信所需的全部配置
 * @receiver c
 */
func (c *K8sClient) Init() error {
    homeDir, _ := os.UserHomeDir() // 获取当前用户的 home 目录

    // 使用clientcmd 构建配置。涉及到读取kubeconfig文件并处理覆盖和默认值
    restConf, err := clientcmd.BuildConfigFromFlags("", homeDir+"/"+config.KUBE_CONFIG)
    if err != nil {
        //log.Fatal(err)
        return err
    }
    // 通过之前构建的配置创建Clientset,它提供了对API的访问
    clientset, err := kubernetes.NewForConfig(restConf)
    if err != nil {
        //log.Panic(err)
        return err
    }
    c.ClientSet = clientset
    aa := ioc.Controller().GetObj(config.IOC_KUBECLIENT)
    fmt.Println(aa)
    return nil
}
func (c *K8sClient) Name() string {
    return config.IOC_KUBECLIENT
}

六、路由配置

package router

import (
    "github.com/gin-gonic/gin"
    "k8s-platform/apps/k8sclient/http"
    http2 "k8s-platform/apps/user/http"
    http3 "k8s-platform/apps/workflow/http"
    "k8s-platform/config"
    "k8s-platform/ioc"
    "k8s-platform/middle"
)

//
//  GinRouter
//  @Description: 初始化Gin
//
type GinRouter struct {
}

func NewRouter() *GinRouter {
    return &GinRouter{}
}
func init() {
    ioc.ApiHandler().Register(&GinRouter{})
}
func (r *GinRouter) Init() error {
    return nil
}
func (r *GinRouter) Name() string {
    return config.APIHANDLER_IOCNAME
}

/*
 * InitApiHandler
 * @Description: API Handler函数
 * @receiver r
 * @param router
 */
func (r *GinRouter) InitApiHandler(router *gin.Engine) {
    router.Use(middle.Cors())
    api := router.Group("/api/v1/kubernetes")
    api.Use(middle.JWTMiddleware())
    {
        pods := api.Group("/pods")
        {
            pods.GET("/", http.PodHttpHandler.GetPodListHandler)
            pods.GET("/detail", http.PodHttpHandler.DescribePod)
            pods.DELETE("/", http.PodHttpHandler.DeletePod)
            pods.GET("/container", http.PodHttpHandler.GetContainerInfo)
            pods.GET("/logs", http.PodHttpHandler.GetPodLogs)
            pods.GET("/numnp", http.PodHttpHandler.GetNamespacePodsCount)
            pods.GET("/deployForPod", http.PodHttpHandler.GetPodsListByDeployment)
            pods.GET("/daemonsetForPod", http.PodHttpHandler.GetPodsListByDaemonset)
            pods.GET("/statefulForPod", http.PodHttpHandler.GetPodsListByStatefulset)

            pods.PUT("/", http.PodHttpHandler.UpdatePod)
        }

        deployments := api.Group("/deployments")
        {
            deployments.GET("/", http.DeploymentHttpHandler.GetDeploymentList)
            deployments.GET("/detail", http.DeploymentHttpHandler.DescribeDeployment)
            deployments.POST("/scale", http.DeploymentHttpHandler.UpdateDeploymentScale)
            deployments.DELETE("/", http.DeploymentHttpHandler.DeleteDeployment)
            deployments.POST("/restart", http.DeploymentHttpHandler.RestartDeployment)
            deployments.PUT("/", http.DeploymentHttpHandler.UpdateDeployment)
            deployments.GET("/numdp", http.DeploymentHttpHandler.GetNamespaceDeploymentCount)
            deployments.POST("/", http.DeploymentHttpHandler.CreateDeployment)
        }

        daemonsets := api.Group("/daemonsets")
        {
            daemonsets.GET("/", http.DaemonsetHttpHandler.GetDaemonSetList)
            daemonsets.DELETE("/", http.DaemonsetHttpHandler.DeleteDaemonSet)
            daemonsets.PUT("/", http.DaemonsetHttpHandler.UpdateDaemonSet)
            daemonsets.GET("/detail", http.DaemonsetHttpHandler.DescribeDaemonSet)
            daemonsets.POST("/", http.DaemonsetHttpHandler.CreateDaemonSet)
        }

        statefulsets := api.Group("/statefulsets")
        {
            statefulsets.GET("/", http.StatefulSetHttpHandler.GetStatefulSetList)
            statefulsets.GET("/detail", http.StatefulSetHttpHandler.DescribeStatefulSet)
            statefulsets.PUT("/", http.StatefulSetHttpHandler.UpdateStatefulSet)
            statefulsets.DELETE("/", http.StatefulSetHttpHandler.DeleteStatefulset)
            statefulsets.POST("/", http.StatefulSetHttpHandler.CreateStatefulset)
        }

        nodes := api.Group("/nodes")
        {
            nodes.GET("/", http.NodeHttpHandler.GetNodeList)
            nodes.GET("/detail", http.NodeHttpHandler.DescribeNode)
        }

        namespaces := api.Group("/namespaces")
        {
            namespaces.GET("/", http.NamespaceHttpHandler.GetNamespaceList)
            namespaces.DELETE("/:name", http.NamespaceHttpHandler.DeleteNamespace)
            namespaces.POST("/", http.NamespaceHttpHandler.CreateNamespace)
            namespaces.GET("/detail", http.NamespaceHttpHandler.DescribeNamespace)
            namespaces.PUT("/", http.NamespaceHttpHandler.UpdateNamespace)
        }

        persistentvolumes := api.Group("/pv")
        {
            persistentvolumes.GET("/", http.PVHttpHandler.GetPvListHandler)
            persistentvolumes.GET("/detail", http.PVHttpHandler.DescribePV)
            persistentvolumes.DELETE("/", http.PVHttpHandler.DeletePersistentVolume)
        }

        services := api.Group("/services")
        {
            services.GET("/", http.ServiceHttpHandler.GetServiceListHandler)
            services.POST("/", http.ServiceHttpHandler.CreateService)
            services.DELETE("/", http.ServiceHttpHandler.DeleteService)
            services.PUT("/", http.ServiceHttpHandler.UpdateService)
            services.GET("/detail", http.ServiceHttpHandler.DescribeService)
        }

        ingress := api.Group("/ingress")
        {
            ingress.GET("/", http.IngressHttpHandler.GetIngressListHandler)
            ingress.GET("/detail", http.IngressHttpHandler.DescribeIngress)
            ingress.POST("/", http.IngressHttpHandler.CreateIngress)
            ingress.DELETE("/", http.IngressHttpHandler.DeleteIngress)
            ingress.PUT("/", http.IngressHttpHandler.UpdateIngress)
        }

        configmap := api.Group("/configmap")
        {
            configmap.GET("/", http.ConfigmapHttpHandler.GetConfigmapList)
            configmap.GET("/detail", http.ConfigmapHttpHandler.DescribeConfigmap)
            configmap.POST("/", http.ConfigmapHttpHandler.CreateConfigmap)
            configmap.DELETE("/", http.ConfigmapHttpHandler.DeleteConfigmap)
            configmap.PUT("/", http.ConfigmapHttpHandler.UpdateConfigmap)
        }

        secret := api.Group("/secret")
        {
            secret.GET("/", http.SecretHttpHandler.GetSecretList)
            secret.GET("/detail", http.SecretHttpHandler.DescribeSecret)
            secret.POST("/", http.SecretHttpHandler.CreateSecret)
            secret.DELETE("/", http.SecretHttpHandler.DeleteSecret)
            secret.PUT("/", http.SecretHttpHandler.UpdateSecret)
        }

        pvc := api.Group("/pvc")
        {
            pvc.GET("/", http.PVCHttpHandler.GetPvcList)
            pvc.GET("/detail", http.PVCHttpHandler.DescribePvc)
            pvc.POST("/", http.PVCHttpHandler.CreatePvc)
            pvc.DELETE("/", http.PVCHttpHandler.DeletePvc)
            pvc.PUT("/", http.PVCHttpHandler.UpdatePvc)
        }
    }
    workflow := router.Group("/api/v1/workflow")
    workflow.Use(middle.JWTMiddleware())
    {
        workflow.GET("/", http3.NewWorkflowHttpHandler().GetWorkflowList)
        workflow.POST("/", http3.NewWorkflowHttpHandler().CreateWorkflow)
        workflow.DELETE("/:id", http3.NewWorkflowHttpHandler().DeleteWorkflow)

    }
    user := router.Group("/api/v1/users")
    user.Use(middle.JWTMiddleware())
    {
        user.GET("/", http2.NewUserHttpHandler().GetUserList)
        user.GET("/:id", http2.NewUserHttpHandler().DescribeUser)
        user.DELETE("/", http2.NewUserHttpHandler().DeleteUser)
        user.POST("/", http2.NewUserHttpHandler().CreateUser)
        user.PUT("/:id", http2.NewUserHttpHandler().UpdateUser)
        user.GET("/groups/:id", http2.NewUserHttpHandler().GetUserHaveGroup)
        user.GET("/permissions/:id", http2.NewUserHttpHandler().GetUserPermissions)
        user.POST("/association", http2.NewUserHttpHandler().AddUserToGroup)
    }

    group := router.Group("/api/v1/groups")
    group.Use(middle.JWTMiddleware())
    {
        group.GET("/", http2.NewUserHttpHandler().GetUserGroupList)
        group.GET("/:id", http2.NewUserHttpHandler().DescribeUserGroup)
        group.DELETE("/:id", http2.NewUserHttpHandler().DeleteUserGroup)
        group.POST("/", http2.NewUserHttpHandler().CreateUserGroup)
        group.PUT("/:id", http2.NewUserHttpHandler().UpdateUserGroup)
        group.PUT("/permissions/:id", http2.NewUserHttpHandler().SetGroupPermissions)
    }

    login := router.Group("/api/v1/login")
    {
        login.POST("/", http2.NewUserHttpHandler().Login)
    }

    router.GET("/", r.Index)
}
func (r *GinRouter) Index(c *gin.Context) {
    c.JSON(200, gin.H{
        "code":    200,
        "message": "success",
    })
}