前端: Vue+element plus
后端: go+gin
后端
Go 快速入门
Gin Web框架
K8s管理系统项目实战[API开发]
项目背景,整体设计,Client-go,框架搭建
一、项目背景
随着容器技术的广泛应用,kubernetes逐渐成为业内的核心技术,是容器编排技术的首选工具。而k8s管理平台在日常的容器维护中也发挥着举足轻重的作用,但随着k8s的定制化功能越来越多,dashboard已经无法满足日常的维护需求,且dashboard的源码学习成本较高,抽象程度较高,二次发成本也就比较高。
本项目使用当下较主流的前端vue+element plus及后端go+gin框架,打造与dashboard对标的k8s管理功能,且可定制化程度高,可根据自身需求,进行灵活定制开发。
二、前后端分离概述
前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式( 也可以中间加一个node.js)有效的进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务( 多种客户端,例如:浏览器,车载终端,安卓,IOS等等)打下坚实的基础。这个步要是系统架构从进化成人的必经之路。
前后分离的优势 :
1.可以实现真正的前后端解耦,前端服务器使用nginx。
2.发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象
3.在大并发情况下,可以同时水平扩展前后端服务器
4.增加代码的维护性&易读性(前后端耦在一起的代码读起来相当费劲 )
5.提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖
三、功能设计
四、client-go介绍
1、简介
client-go是kubernetes官方提供的go语言的客户端库,go应用使用该库可以访问kubernetes的API Server,这样我们就能通过编程来对kubermetes资源进行增删改查操作:
除了提供丰富的API用于操kubernetes资源,client-go还为controller和operator提供了重要支持client-go的informer机制可以将controller关注的资源变化及时带给此controller,使controller能够及时响应变化。
通过client-go提供的客户端对象与kubernetes的API Server进行交豆,而client-go提供了以下四种客户端对象
(1)RESTClient:这是最基础的客户端对象,仅对HTTPRequest进行了封装,实现RESTFul风格API,这个对象的使用并不方便,因为很多参数都要使用者来设置,于是client-go基于RESTClient又实现了三种新的客户端对象;
(2)ClientSet;把Resoure和Version也封装成方法了,用起亲更简单直接,一个资源是一个客户端,多个资源就对应了多个客户端所以ClientSet就是多个客户端的集合了,这样就理解了,不过ClientSet只能访问内置资源,访问不了自定义资源
(3)DynamiClient;可以访问内置资源和自定义资源,个人感觉有点像Java的集合操作,拿出的内容是Object类型,按实际情况自己去做强制转换,当然了也会有强转失败的风险:
(4)DiscoveryClient: 用于发现kubernetes的API Server支持的Group、Version、Resources等信息;
// kubectl api-resources
2、代码示例
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
metav1 "k8s.io/apimeachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // windows
}
func main() {
// 声明kubeconfig配置文件
var kubeconfig *string
// 获取home环境变量,拿到$HOME/.kube/config配置文件
if home := homeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optinal) absolute path to the kubeconfig file")
} else {
// 否则就根据kubeconfig传到config的路径
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
// 将kubeconfig格式化为rest.config类型
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// 通过config创建clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// 通过client-go sdk获取pods列表,命名空间是default
pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
// 打印出pods列表的长度
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
}
3、常用方法
// 获取pod列表
podList, err := K8S.ClientSet.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
// 获取pod详情
pod, err := K8S.ClientSet.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.ListOptions{})
// 删除pod
err = K8S.ClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metav1.DeleteOptions{})
// 更新pod(完整yaml)
pod, err = K8S.ClientSet.CoreV1().Pods(namespace).Update(context.TODO(), pod, metav1.UpdateOptions{})
// 获取deployment副本数
scale, err := K8S.ClientSet.AppsV1().Deployment(namespace).GetScale(context.TODO(), deploymentName, metav1.GetOption{})
// 创建deployment
deployment, err = K8S.ClientSet.AppsV1().Deployments(data.Namespace).Create(context.TODO(), deployment, metav1.CreateOption{})
// 更新deployment(部分yaml)
deployment, err = K8S.ClientSet.AppsV1().Deployments(namespace).Patch(context.TODO(), deploymentName, "application/strategic-merge-patch-json", patchByte, metav1.PatchOption{})
初始化
创建项目
D:\Workspace\Go\src\k8s-platform
main.go
安装模块
go get k8s.io/client-go/tools/clientcmd
go get k8s.io/api/core/v1
go get k8s.io/apimachinery/pkg/apis/meta/v1
go get github.com/gin-gonic/gin
go get github.com/wonderivan/logger
go get gorm.io/gorm
go get gorm.io/driver/sqlite
go get gorm.io/driver/mysql
PS D:\Workspace\Go\src\k8s-platform> go mod init k8s-platform
go: creating new go.mod: module k8s-platform
go: to add module requirements and sums:
go mod tidy
main.go
package main
import (
"context"
"fmt"
"os"
metav1 "k8s.io/apimeachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // windows
}
func main() {
// // 声明kubeconfig配置文件
// var kubeconfig *string
// // 获取home环境变量,拿到$HOME/.kube/config配置文件
// if home := homeDir(); home != "" {
// kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optinal) absolute path to the kubeconfig file")
// } else {
// // 否则就根据kubeconfig传到config的路径
// kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
// }
// flag.Parse()
// 将kubeconfig格式化为rest.config类型
// config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
config, err := clientcmd.BuildConfigFromFlags("", "C:\\Users\\Administrator\\.kube\\config")
if err != nil {
panic(err.Error())
}
// 通过config创建clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// 通过client-go sdk获取pods列表,命名空间是default
podList, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
// // 打印出pods列表的长度
// fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
for _, pod := range podList.Items {
fmt.Println(pod.Name, pod.Namespace)
}
}
五、项目目录结构
项目目录含义
目录名 作用
config 定义全局配置,如:监听地址,管理员账号等
controller controller层,定义路由规则及接口入参和响应
service 服务层,处理接口的业务逻辑
dao 数据库操作,包含数据的增删改查
model 定义数据库表的字段
db 用于初始化数据库连接及配置
middle 中间件层,添加全局的逻辑处理,如跨域,jwt验证等
utils 工具目录,定义常用工具,如token解析,文件操作等
go.mod 定义项目的依赖包以及版本
main.go 项目主入口,main函数
创建目录
controller config service dao db model middle utils
六、框架搭建