【云原生开发】K8S集群管理后端开发设计与实现

在这里插入图片描述

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

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

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

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

在这里插入图片描述

文章目录

  • K8S集群管理后端开发设计与实现
    • 1、incluster命名空间的检测与创建
    • 2、集群管理的路由配置
    • 3、实现添加更新集群功能
    • 4、 结构体转化成map工具包
    • 5、删除集群
    • 6、集群列表查询
    • 7、获取集群详情

K8S集群管理后端开发设计与实现

集群管理包含在前端添加,更新,删除,查询所有集群,查询集群详情等功能实现。

1、incluster命名空间的检测与创建

根据之前的架构规划,我们的元数据存储在inCluster这个K8S集群中的krm名称空间,程序启动的时候,先检查krm这个命名空间是否存在,不存在的话我们就创建这个命名空间
在这里插入图片描述

设个默认值,并可以通过环境变量获取
在这里插入图片描述

检查命名空间需要在程序运行前执行,因此我们需要创建个controller,来做初始化检查操作

package initcontrollerimport (_ "jingtian/krm-backend/config" //调用里面的init函数,将日志格式初始化"jingtian/krm-backend/utils/logs"
)// 只写个init函数,用来检查配置
func init() {//这里面需要初始化incluster的kubeconfig,创建客户端。创建元数据的命名空间logs.Debug(nil, "初始化incluster数据...")// 1. 通过kubeconfig创建client-go客户端// 2. 检查元数据命名空间是否创建,如有,提醒下元数据命名空间未创建。如没有,就创建命名空间MetadataInit()
}

在这里插入图片描述

在initcontroller包里面,创建个initcluster.go,用来检测命名空间是否创建,如未创建,即刻创建。

package initcontrollerimport ("context""jingtian/krm-backend/config""jingtian/krm-backend/utils/logs"corev1 "k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func MetadataInit() {logs.Debug(nil, "初始化元数据命名空间")// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略kubeconfig, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {logs.Error(map[string]interface{}{"msg": err.Error()}, "inCluster kubeconfig加载失败")panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(kubeconfig)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {logs.Error(map[string]interface{}{"msg": err.Error()}, "inCluster客户端创建失败")panic(err.Error())}// 获取K8S的版本号// ServerVersion() (*version.Info, error)inClusterVersion, _ := clientset.Discovery().ServerVersion()// 3.检查命名空间是否存在_, err = clientset.CoreV1().Namespaces().Get(context.TODO(), config.MetadataNamespace, metav1.GetOptions{})if err != nil {// 不存在元数据命名空间logs.Info(nil, "元数据命名空间不存在,准备创建....")// 创建元数据命名空间var metadataNamespace corev1.NamespacemetadataNamespace.Name = config.MetadataNamespace_, err = clientset.CoreV1().Namespaces().Create(context.TODO(), &metadataNamespace, metav1.CreateOptions{})if err != nil {logs.Error(map[string]interface{}{"msg": err.Error()}, "元数据命名空间创建失败")panic(err.Error())}logs.Info(map[string]interface{}{"Namespace": config.MetadataNamespace, "inCluster版本": inClusterVersion.String()}, "元数据命名空间创建成功")} else {// 已经存在namespacelogs.Info(map[string]interface{}{"Namespace": config.MetadataNamespace, "inCluster版本": inClusterVersion.String()}, "元数据命名空间已存在")}
}

在这里插入图片描述

运行程序,元数据命名空间创建成功
在这里插入图片描述

在K8S集群查看命名空间,可见命名空间创建成功
在这里插入图片描述

2、集群管理的路由配置

我们得路由要在routers目录下去管理
在这里插入图片描述

并且通过routers.go文件实现路由的注册
在这里插入图片描述

创建集群管理的路由和控制器

routers.go

// Package routers 路由层 管理程序的路由信息
package routersimport ("github.com/gin-gonic/gin""jingtian/krm-backend/routers/auth""jingtian/krm-backend/routers/cluster"
)// RegisterRouters 需要将main.go里面的路由引擎r传过来
// 写个注册路由的方法
func RegisterRouters(r *gin.Engine) {//登录的路由配置//1. 登录: login//2. 登出: loginout//3. 路由分组 /api/auth/login  /api/auth/loginoutapiGroup := r.Group("/api")auth.RegisterSubRouter(apiGroup)cluster.RegisterSubRouter(apiGroup)}

在这里插入图片描述

cluster.go

package clusterimport ("github.com/gin-gonic/gin""jingtian/krm-backend/controllers/cluster"
)// 实现添加集群的接口
func add(authGroup *gin.RouterGroup) {//具体逻辑写到控制器controller里面authGroup.POST("/add", cluster.Add)
}// 实现更新集群的接口
func update(authGroup *gin.RouterGroup) {//具体逻辑写到控制器controller里面authGroup.POST("/update", cluster.Update)
}// 删除集群
func deleteCluster(clusterGroup *gin.RouterGroup) {clusterGroup.GET("/delete", cluster.DeleteCluster)
}// 获取集群信息
func get(clusterGroup *gin.RouterGroup) {clusterGroup.GET("/get", cluster.Get)
}// 列出所有集群
func list(clusterGroup *gin.RouterGroup) {clusterGroup.GET("/list", cluster.List)
}// RegisterSubRouter 认证子路由
func RegisterSubRouter(g *gin.RouterGroup) {//配置登录功能路由策略clusterGroup := g.Group("/cluster")add(clusterGroup)update(clusterGroup)deleteCluster(clusterGroup)get(clusterGroup)list(clusterGroup)}

在这里插入图片描述

控制器
在这里插入图片描述

由于除了登录和登出的其他接口,都要携带token才能访问,所以我们先登录,生成token,携带token发出请求
在这里插入图片描述

携带token请求测试
在这里插入图片描述

请求能走到添加集群的控制器
在这里插入图片描述

3、实现添加更新集群功能

怎么实现添加集群呢? 前端可能会让我们输入一些集群的信息,比如集群的名字,集群的ID,kubeconfig等。前端把这些信息提交给后端,然后后端再根据这些信息来创建集群
gin框架可以将前端传来的json数据和结构体进行绑定,然后通过结构体进行创建资源等其他操作。

我们先创建个结构体,来声明创建一个集群所需要的字段。我们将结构体的定义放在controller/cluster.go中

package clusterimport ("k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)// MyClusterInfo 主要用于查询操作
type MyClusterInfo struct {Id          string `json:"id"`DisplayName string `json:"displayName"` //集群的别名City        string `json:"city"`District    string `json:"district"`
}// MyClusterStatus 定义一个结构体,用于描述集群的状态
// 集群可用,状态就是Active 不可用,状态就是InActive
type MyClusterStatus struct {MyClusterInfoVersion string `json:"version"`Status  string `json:"status"`
}// MyClusterConfig 定义一个结构体,用于描述创建集群所用的配置信息
type MyClusterConfig struct {MyClusterInfoKubeconfig string `json:"kubeconfig"` //集群的配置资源
}// GetClusterStatus 结构体的方法,用于判断集群的状态
func (cfg *MyClusterConfig) GetClusterStatus() (MyClusterStatus, error) {// 判断集群是否是正常clusterStatus := MyClusterStatus{}clusterStatus.MyClusterInfo = cfg.MyClusterInfo//此时,需要检测集群实时状态,所以需要重新连接集群// 创建一个clientset,从前端传来的kubeconfig字符串来连接集群,这也是out-cluster方式创建客户端// func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error)// 接收的参数是字节类型restConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(cfg.Kubeconfig))if err != nil {clusterStatus.Version = "Unavailable Version"clusterStatus.Status = "InActive"return clusterStatus, err}clientset, err := kubernetes.NewForConfig(restConfig)if err != nil {clusterStatus.Version = "Unavailable Version"clusterStatus.Status = "InActive"return clusterStatus, err}//客户端工具创建成功后,获取版本信息serverVersion, err := clientset.Discovery().ServerVersion()if err != nil {return clusterStatus, err}//集群正常就将集群的版本和状态返回clusterVersion := serverVersion.String()clusterStatus.Version = clusterVersionclusterStatus.Status = "Active"return clusterStatus, nil
}

在这里插入图片描述

由于添加和更新集群,所用的参数差不多,所以我们将添加和更新写到一个函数中AddOrUpdate.go,根据传参,来区分是添加还是更新

package clusterimport ("context""fmt""github.com/gin-gonic/gin""jingtian/krm-backend/config""jingtian/krm-backend/utils""jingtian/krm-backend/utils/logs"corev1 "k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""net/http"
)// method: update,  create
func addOrUpdate(c *gin.Context, method string) {var arg stringif method == "Create" {arg = "添加"} else if method == "Update" {arg = "更新"}// 声明一个集群配置clusterConfig := MyClusterConfig{}returnData := config.NewReturnData()if err := c.ShouldBindJSON(&clusterConfig); err != nil {msg := arg + "集群的配置信息不完整: " + err.Error()returnData.Status = 400returnData.Msg = msgc.JSON(200, returnData)return}// 判断集群是否正常,写个函数去连接集群,如果能获取到集群的版本,说明集群是正常的// 这个函数写在哪呢,应该写在MyClusterConfig这个结构体的方法中clusterStatus, err := clusterConfig.GetClusterStatus()if err != nil {msg := "无法获取集群信息: " + err.Error()returnData.Status = 400returnData.Msg = msgc.JSON(http.StatusOK, returnData)logs.Error(map[string]interface{}{"error": err.Error()}, arg+"集群失败,无法获取集群信息")return}logs.Info(map[string]interface{}{"集群名称": clusterConfig.DisplayName, "集群ID": clusterConfig.Id}, "开始"+arg+"集群")// 创建一个集群配置的secret 保存集群信息var clusterConfigSecret corev1.SecretclusterConfigSecret.Name = clusterConfig.IdclusterConfigSecret.Labels = make(map[string]string)clusterConfigSecret.Labels[config.ClusterConfigSecretLabelKey] = config.ClusterConfigSecretLabelValue// 添加注释,保存集群的配置信息clusterConfigSecret.Annotations = make(map[string]string)// 把集群的状态结构体转成map。我们专门写个工具函数来实现结构体与map的转换m, err := utils.Struct2Map(clusterStatus)if err != nil {logs.Error(nil, err.Error())return}clusterConfigSecret.Annotations = m// 保存kubeconfig,我们保存到StringData里面的。我们点进去secret查看//里面有Data和StringData两种,Data是需要加密的才能使用,StringData我们可以传字符串,当我们查看secret的时候自动加密//Data map[string][]byte `json:"data,omitempty" protobuf:"bytes,2,rep,name=data"`//StringData map[string]string `json:"stringData,omitempty" protobuf:"bytes,4,rep,name=stringData"`//如果在 data 和 stringData 中设置了同一个字段,则使用来自 stringData 中的值clusterConfigSecret.StringData = make(map[string]string)clusterConfigSecret.StringData["kubeconfig"] = clusterConfig.Kubeconfig// 创建secretif method == "Create" {_, err = config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).Create(context.TODO(), &clusterConfigSecret, metav1.CreateOptions{})} else if method == "Update" {//更新_, err = config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).Update(context.TODO(), &clusterConfigSecret, metav1.UpdateOptions{})}if err != nil {// 说明创建失败logs.Error(map[string]interface{}{"集群ID": clusterConfig.Id, "集群名字:": clusterConfig.DisplayName, "msg": err.Error()}, "集群"+arg+"失败")msg := arg + "集群失败: " + err.Error()returnData.Msg = msgreturnData.Status = 400c.JSON(200, returnData)return}//创建or更新成功//map需要先初始化config.ClusterKubeconfig = make(map[string]string)config.ClusterKubeconfig[clusterConfig.Id] = clusterConfig.Kubeconfigfmt.Println("当前集群配置:", config.ClusterKubeconfig)logs.Info(map[string]interface{}{"集群ID": clusterConfig.Id, "集群名字:": clusterConfig.DisplayName}, "集群"+arg+"成功")returnData.Status = 200returnData.Msg = arg + "成功"c.JSON(200, returnData)
}

在这里插入图片描述

add.go中
在这里插入图片描述

update.go中
在这里插入图片描述

4、 结构体转化成map工具包

结构体转换成map工具类utils/utils.go

// Package utils 工具层
package utilsimport "encoding/json"func Struct2Map(s interface{}) (map[string]string, error) {j, _ := json.Marshal(s) //先将结构体转换成字节m := make(map[string]string)err := json.Unmarshal(j, &m) //将字节转化成mapif err != nil {return nil, err}return m, nil
}

在这里插入图片描述

测试添加集群接口
看下绑定的结构体,来确定前端传的数据
在这里插入图片描述

在这里插入图片描述

postman请求
我们先不传kubeconfig,可以看到检测到集群不正常,无法添加
在这里插入图片描述

我们把集群的~/.kube/config填进去
在这里插入图片描述

注意,需要把换行符改成\n。不然postman无法传参
在这里插入图片描述

再次请求
在这里插入图片描述

k8s集群查看secret,添加成功
在这里插入图片描述

查看详情
在这里插入图片描述

更新集群
只需要在请求处,将URL改成update,然后修改字段即可
在这里插入图片描述

5、删除集群

删除集群,只需要根据集群ID,将对应的secret删除掉即可
删除集群的控制器deleteCluster.go

package clusterimport ("context""github.com/gin-gonic/gin""jingtian/krm-backend/config""jingtian/krm-backend/utils/logs"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)func DeleteCluster(c *gin.Context) {logs.Debug(nil, "删除集群")// 1.根据传来的id来删除secretclusterId := c.Query("id")// 2.删除secreterr := config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).Delete(context.TODO(), clusterId, metav1.DeleteOptions{})// 定义响应格式returnData := config.NewReturnData()if err != nil {logs.Error(map[string]interface{}{"id": clusterId, "message": err.Error()}, "删除失败")// 说明删除集群失败msg := "集群删除失败: " + err.Error()returnData.Status = 400returnData.Msg = msg} else {logs.Warning(map[string]interface{}{"id": clusterId}, "删除成功")// 说明删除成功returnData.Status = 200returnData.Msg = "删除成功"delete(config.ClusterKubeconfig, clusterId)}//响应给前端c.JSON(200, returnData)
}

在这里插入图片描述

请求
在这里插入图片描述

k8s查看,删除成功
在这里插入图片描述

6、集群列表查询

集群列表查询,就是查询所有的secret列表,将secret列表返回给前端就可以了
我们先通过postman创建几个secret,模拟几个集群
在这里插入图片描述

查看secret
在这里插入图片描述

我们把secret都查询出来,但是我们不要把secret的所有信息都传给前端,因为可能会不安全,所以尽量不要把kubeconfig传给前端
我们只需要传annotations里面的数据就行了
在这里插入图片描述

因此,我们在查询到secret列表时,需要处理下
查询的时候,可以过滤

//根据指定标签,过滤出我们添加的集群
listOptions := metav1.ListOptions{LabelSelector: config.ClusterConfigSecretLabelKey + "=" + config.ClusterConfigSecretLabelValue,
}
secretList, err := config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).List(context.TODO(), listOptions)

ListOptions里面可以根据LabelSelector或者FieldSelector等过滤
在这里插入图片描述

查询集群列表list.go完整代码

package clusterimport ("context""github.com/gin-gonic/gin""jingtian/krm-backend/config""jingtian/krm-backend/utils/logs"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)func List(c *gin.Context) {logs.Debug(nil, "列出集群列表")//根据指定标签,过滤出我们添加的集群listOptions := metav1.ListOptions{LabelSelector: config.ClusterConfigSecretLabelKey + "=" + config.ClusterConfigSecretLabelValue,}secretList, err := config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).List(context.TODO(), listOptions)returnData := config.NewReturnData()if err != nil {logs.Info(map[string]interface{}{"message": err.Error()}, "查询集群列表失败")// 查询失败msg := "查询失败: " + err.Error()returnData.Status = 400returnData.Msg = msgc.JSON(200, returnData)return}// 优化数据返回的结构,将annotions里面的map以切片的形式传给前端var clusterList []map[string]stringfor _, v := range secretList.Items {anno := v.AnnotationsclusterList = append(clusterList, anno)}returnData.Msg = "查询成功"returnData.Data["items"] = clusterListc.JSON(200, returnData)}

在这里插入图片描述

postman请求,拿到集群列表
在这里插入图片描述

7、获取集群详情

我们查询一个集群的配置的时候,需要用到get,还有就是编辑一个集群的时候,也需要用到查询集群的详情。
我们可以根据集群id来获取到secret,返回给前端

控制器get.go

package clusterimport ("context""fmt""github.com/gin-gonic/gin""jingtian/krm-backend/config""jingtian/krm-backend/utils/logs"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""net/http"
)func Get(c *gin.Context) {logs.Debug(nil, "获取集群详情")// 1.根据传来的id来获取集群详情clusterId := c.Query("id")returnData := config.NewReturnData()// 2.获取集群的详细信息secretDetail, err := config.InClusterClientSet.CoreV1().Secrets(config.MetadataNamespace).Get(context.TODO(), clusterId, metav1.GetOptions{})if err != nil {logs.Error(map[string]interface{}{"id": clusterId, "message": err.Error()}, "获取集群信息失败")returnData.Status = 400returnData.Msg = "获取集群详情失败 " + err.Error()} else {returnData.Msg = "集群详情查询成功"fmt.Println("secretDetail是什么", secretDetail)clusterConfigMap := secretDetail.Annotations// Data map[string][]byte `json:"data,omitempty" protobuf:"bytes,2,rep,name=data"` Data 键是字符串,值是字节// 通过string将值转化成字符串//获取的时候不可以用StringData,因为secret里面没有这个字段。只有Data字段clusterConfigMap["kubeconfig"] = string(secretDetail.Data["kubeconfig"])returnData.Data["item"] = clusterConfigMap}c.JSON(http.StatusOK, returnData)}

postman请求,查询到集群详情数据
在这里插入图片描述

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

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

相关文章

爱普生SG-8201CG可编程振荡器的应用领域

在科技飞速发展的今天,电子设备的性能和稳定性成为各个行业关注的焦点。爱普生 SG - 8201CG 可编程振荡器以其卓越的性能,在众多领域中大放异彩,成为推动行业进步的关键力量。 1.通信领域:高速通信的精准守护者 在通信领域&…

计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session

文章目录 一、HTTP协议的特点1.1 特点1.2 HTTP是不保存状态的协议,如何保存用户状态? 二、浏览器中输入URL返回页面过程(重)三、HTTP状态码四、HTTP相关协议对比4.1 HTTP和HTTPS的区别(重)4.2 HTTP1.0和HTTP1.1的区别…

基于Spring Boot的网上商品订单转手系统设计与实现,LW+源码+讲解

摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装网上商品订单转手系统软件来发挥其高效地信息处理的作用&a…

设备的设计流程和风险评估

为了保证机器的安全性,在机器设计和开发过程中必须降低风险。该过程如下列流程图所示。 风险评估的含义以及如何进行

【MATLAB源码-第209期】基于matlab的MSK调制解调仿真,对比三种解调方法的误码率分别是相干解调,1比特差分,2比特差分。

操作环境: MATLAB 2022a 1、算法描述 最小频移键控(Minimum Shift Keying,简称MSK)是一种特殊的连续相位频移键控(CPFSK),它以其频谱效率高、抗干扰能力强而著称,广泛应用于无线通…

Git 的分支管理

一、分支介绍 1、分支是什么 Git作为一个分布式版本控制系统,提供了强大而灵活的分支管理功能,使得开发团队能够高效地协作开发、管理不同的功能和版本。 2、为什么有分支 一般情况下主分支(master/main)应始终保持可部署的状…

论文速读:简化目标检测的无源域适应-有效的自我训练策略和性能洞察(ECCV2024)

中文标题:简化目标检测的无源域适应:有效的自我训练策略和性能洞察 原文标题:Simplifying Source-Free Domain Adaptation for Object Detection: Effective Self-Training Strategies and Performance Insights 此篇文章为论文速读&#xff…

mac找到主目录下的文件夹

访达-(上方状态栏显示)-然后在

FFmpeg 4.3 音视频-多路H265监控录放C++开发十二:在屏幕上显示多路视频播放,可以有不同的分辨率,格式和帧率。

上图是在安防领域的要求,一般都是一个屏幕上有显示多个摄像头捕捉到的画面,这一节,我们是从文件中读取多个文件,显示在屏幕上。 一 改动UI文件 这里我们要添加两个label,为了区分我们设置一下背景色(这个是…

RK3576 LINUX RKNN SDK 测试

安装Conda工具 安装 Miniforge Conda wget -c https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh chmod 777 Miniforge3-Linux-x86_64.sh bash Miniforge3-Linux-x86_64.shsource ~/miniforge3/bin/activate # Miniforge 安装的…

新能源行业必会基础知识-----电力现货市场理论篇-----主目录-----持续更新

新能源行业知识体系-------主目录-----持续更新https://blog.csdn.net/grd_java/article/details/140004020 这本书是2023年出版的,是当下了解国内电力市场最好的途径了。 电力现货市场理论篇 一、电力市场概述1. 电力市场总体架构2. 电力市场模式选择3. 电力市场建…

docker 拉取MySQL8.0镜像以及安装

目录 一、docker安装MySQL镜像 搜索images 拉取MySQL镜像 二、数据挂载 在/root/mysql/conf中创建 *.cnf 文件 创建容器,将数据,日志,配置文件映射到本机 检查MySQL是否启动成功: 三、DBeaver数据库连接 问题一、Public Key Retrieval is not allowed 问题…

#Prompt | AI | LLM # 人类如何写出LLM理解的Prompt

一、如何写好Prompt 结构化Prompt 结构化Prompt是对信息进行组织,使其遵循特定模式和规则,以便于有效理解信息。常用模块包括: Role: 指定角色,使模型聚焦于特定领域。Profile: 包括作者、版本、语言和描述。Goals: 描述Prompt的…

vue计算属性

概念:基于现有的数据,计算出来新属性。并依赖数据的变化,自动重新计算 使用场景: 语法:声明在computed配置项中,一个计算属性对应一个函数,使用起来和普通属性一样使用{{计算属性名}} 代码&…

playground.tensorflow神经网络可视化工具

playground.tensorflow 是一个可视化工具,用于帮助用户理解深度学习和神经网络的基本原理。它通过交互式界面使用户能够构建、训练和可视化简单的神经网络模型。以下是一些主要的数学模型和公式原理,它们在这个平台中被应用: 1. 线性模型 线…

Zabbix监控架构

目录 1. Zabbix监控架构-CS架构 2. Zabbix极速上手指南 主机规划 2.1 部署ngxphp环境并测试 检查安装结果 2.2 部署数据库 2.3 编译安装zabbix-server服务端及后续配置 2.4 部署前端代码代码进行访问 前端的配置文件(连接数据库与主机名等信息) 2.5 欢迎来到zabbix 2…

后台管理系统:登录页

本次项目为后台管理系统,在本系统内第一个页面是登录页面 登录页的各种功能介绍 作为登录页需要具有的功能有:点击登录时记录账户密码,对比账户密码的正确性,提示用户当前状态,登录完成后跳转至首页等功能。 一、网页设…

go语言解决rtsp协议只播放部分的问题(业务问题)

背景 之前不是写过一个项目嘛,就之前有更改过存储对接的项目 go语言对接S3存储的SDK(支持minio和OSS) 这个项目主要的业务是就一个,点播rtsp协议的码流,视频来源在存储服务器上。 这次的问题是rtsp协议只播放部分,需要我们进行排…

移位寄存器设计—FDRE、SRL16E及原语约束

信号处理中,实现数据对齐时,常常对单bit或多bit信号进行打拍操作,这个可以通过移位寄存器实现,SLICEM中的SRL即为移位寄存器。 这里主要记录下不同写法的效果。 1 //同步复位2 module static_multi_bit_sreg_poor #(3 parame…

Linux学习笔记之虚拟机操作

Linux简介 Linux是一种开源、免费的操作系统,其稳定性、安全性、处理多并发得到业界认可。Linux在服务器领域可以说是最强的,并且具有可定制,可裁剪,适用于嵌入式领域的特点。对于linux系统,它最大的的特点就是一切皆…