golang+vue3 实现 在web展示 k8s机器的pod,svc,ingress
golang 后台代码
package main
import (
"context"
"fmt"
"k8s.io/client-go/tools/clientcmd"
"net/http"
"os/user"
"github.com/gin-gonic/gin"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
func CorsMiddleware() gin.HandlerFunc {
return func(context *gin.Context) {
method := context.Request.Method
// 因为是内网环境,所以可以直接把所有域名设置进去,但是按理来说不能这样
context.Header("Access-Control-Allow-Origin", context.GetHeader("Origin"))
context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
context.Header("Access-Control-Allow-Credentials", "true")
if method == "OPTIONS" {
context.AbortWithStatus(http.StatusNoContent)
}
context.Next()
}
}
func main() {
u , _ := user.Current()
home := u.HomeDir
k8sConfig, err := clientcmd.BuildConfigFromFlags("", fmt.Sprintf("%s/.kube/config", home)) // 使用 kubectl 默认配置 ~/.kube/config
if err != nil {
fmt.Printf("%v", err)
return
}
// 创建一个k8s客户端
clientset, err := kubernetes.NewForConfig(k8sConfig)
if err != nil {
panic(any(err))
}
// 创建 Gin 路由器
r := gin.Default()
r.Use(CorsMiddleware())
r.GET("/api/namespaces", func(c *gin.Context) {
// 获取所有 Namespace 下的 Pod 列表
podList, err := clientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 将 Pod 列表转换为 JSON 格式并返回给前端
c.JSON(http.StatusOK, podList)
})
// 定义获取 Pod 列表的 API 接口
r.GET("/api/pods", func(c *gin.Context) {
// 获取所有 Namespace 下的 Pod 列表
podList, err := clientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 将 Pod 列表转换为 JSON 格式并返回给前端
c.JSON(http.StatusOK, podList)
})
// 定义获取 Service 列表的 API 接口
r.GET("/api/services", func(c *gin.Context) {
// 获取所有 Namespace 下的 Service 列表
serviceList, err := clientset.CoreV1().Services("").List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 将 Service 列表转换为 JSON 格式并返回给前端
c.JSON(http.StatusOK, serviceList)
})
// 定义获取 Ingress 列表的 API 接口
r.GET("/api/ingresses", func(c *gin.Context) {
// 获取所有 Namespace 下的 Ingress 列表
ingressList, err := clientset.ExtensionsV1beta1().Ingresses("").List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 将 Ingress 列表转换为 JSON 格式并返回给前端
c.JSON(http.StatusOK, ingressList)
})
r.GET("/api/pods/:namespace", func(c *gin.Context) {
namespace := c.Param("namespace")
pods, err := clientset.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"pods": pods.Items})
})
r.GET("/api/services/:namespace", func(c *gin.Context) {
namespace := c.Param("namespace")
services, err := clientset.CoreV1().Services(namespace).List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"services": services.Items})
})
r.GET("/api/ingresses/:namespace", func(c *gin.Context) {
namespace := c.Param("namespace")
ingresses, err := clientset.ExtensionsV1beta1().Ingresses(namespace).List(context.Background(), metav1.ListOptions{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"ingresses": ingresses.Items})
})
// 启动 Gin 服务器
if err := r.Run(":8080"); err != nil {
panic(any(err))
}
}
ingress获取有点问题
vue3 前端代码
App.vue
<template>
<div id="app">
<Resources />
</div>
</template>
<script>
import Resources from "./components/Resources.vue";
export default {
components: {
Resources,
},
};
</script>
Resources.vue
<template>
<div class="container">
<h1>Kubernetes Dashboard</h1>
<div class="namespace-selector">
<el-select v-model="selectedNamespace" placeholder="Select a namespace" @change="loadPods(selectedNamespace),loadServices(selectedNamespace),loadIngresses(selectedNamespace)">
<el-option v-for="namespace in namespaces" :key="namespace" :label="namespace.metadata.name"
:value="namespace.metadata.name"/>
</el-select>
</div>
<div>
<el-tabs type="border-card" class="demo-tabs">
<el-tab-pane>
<template #label>
<span class="custom-tabs-label">
<el-icon><calendar/></el-icon>
<span>Pods</span>
</span>
</template>
<div class="data-display">
<el-table :data="pods" stripe>
<el-table-column prop="metadata.name" label="Name"></el-table-column>
<el-table-column prop="status.phase" label="Status"></el-table-column>
<el-table-column prop="status.podIP" label="IP"></el-table-column>
<el-table-column prop="status.hostIP" label="HostIP"></el-table-column>
<el-table-column prop="status.startTime" label="Created At"></el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="Service">
<div class="data-display">
<el-table :data="services" stripe>
<el-table-column prop="metadata.name" label="Name"></el-table-column>
<el-table-column prop="spec.type" label="Type"></el-table-column>
<el-table-column prop="spec.clusterIP" label="Cluster IP"></el-table-column>
<el-table-column prop="spec.ports[0].port" label="Port"></el-table-column>
<el-table-column prop="spec.ports[0].targetPort" label="TargetPort"></el-table-column>
<el-table-column prop="metadata.creationTimestamp" label="Created At"></el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="Ingress">
<div class="data-display">
<el-table :data="ingresses" stripe>
<el-table-column prop="name" label="Name"></el-table-column>
<el-table-column prop="host" label="Host"></el-table-column>
<el-table-column prop="path" label="Path"></el-table-column>
<el-table-column prop="backendServiceName" label="Backend Service"></el-table-column>
<el-table-column prop="creationTimestamp" label="Created At"></el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="Task">Task</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import {Calendar} from '@element-plus/icons-vue'
import axios from 'axios'
export default {
name: 'App',
data() {
return {
namespaces: [],
selectedNamespace: '',
pods: [],
services: [],
ingresses: [],
}
},
mounted() {
console.log(233)
this.loadNamespaces()
this.loadPods("default")
this.loadServices('default')
this.loadIngresses('default')
},
methods: {
loadNamespaces() {
let _that = this
axios.get('http://127.0.0.1:8080/api/namespaces')
.then(response => {
console.log(response.data.items)
_that.namespaces = response.data.items
_that.selectedNamespace = _that.namespaces[0].metadata.name
})
.catch(error => {
console.error(error)
})
},
loadPods(namespace) {
axios.get(`http://127.0.0.1:8080/api/pods/${namespace}`)
.then(response => {
console.log(response)
this.pods = response.data.pods
})
.catch(error => {
console.error(error)
})
},
loadIngresses(namespace) {
axios.get(`http://127.0.0.1:8080/api/ingresses/${namespace}`)
.then(response => {
this.ingresses = response.data.data.items
})
.catch(error => {
console.error(error)
})
},
loadServices(namespace) {
axios.get(`http://127.0.0.1:8080/api/services/${namespace}`)
.then(response => {
this.services = response.data.services
})
.catch(error => {
console.error(error)
})
},
}
}
</script>
<style>
.demo-tabs > .el-tabs__content {
padding: 32px;
color: #6b778c;
font-size: 32px;
font-weight: 600;
}
.demo-tabs .custom-tabs-label .el-icon {
vertical-align: middle;
}
.demo-tabs .custom-tabs-label span {
vertical-align: middle;
margin-left: 4px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.namespace-selector {
margin-bottom: 16px;
}
.data-display {
display: flex;
flex-wrap: wrap;
margin: -16px;
}
.el-table {
flex: 1;
margin: 16px;
}
</style>
推荐阅读
prometheus结合consul+confd实现动态注册服务和动态更新配置告警规则
如上配置的缺点是,所有的注册节点都会归类到consul-node-exporter这个工作类别下面,有时候想对注册的服务进行分类,比如mysql为一类,oracle为一类,就要修改配置为:
台湾省委书记阅读 223
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -> Preference-> Settings(如果装了中文插件包应该是 文件 -> 选项 -> 设置),搜索 eslint,点击 Edit in setting.json
谭光志赞 34阅读 20.8k评论 9
vue UI框架比较
最好基于vue2.0PC端:因为用过的是饿了么UI,所以比较以饿了么UI为基础element UI 饿了么UI支持vue2.x80分优点:组件的API方法、属性等封装的较为完善缺点:样式有些生硬,不够炫酷美观N3 N3支持vue2.x70分优点:...
chinawzc赞 22阅读 39.9k评论 17
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...
原谅我一生不羁放歌搞文艺赞 14阅读 20.1k评论 9
用了那么久的 SVG,你还没有入门吗?
其实在大部分的项目中都有 直接 或 间接 使用到 SVG 和 Canvas,但是在大多数时候我们只是选择 简单了解 或 直接跳过,这有问题吗?没有问题,毕竟砖还是要搬的!
熊的猫赞 17阅读 1.6k评论 2
嘿,vue中keep-alive有个「大坑」你可能还不知道
背景是这样的,我们使用vue2开发一个在线客服使用的IM应用,基本布局是左边是访客列表,右边是访客对话,为了让对话加载更友好,我们将对话的路由使用<keep-alive>缓存起来。但是如果将所有对话都缓存,未...
wuwhs赞 12阅读 2.6k
golang学习之旅——解开心中的go mod疑惑
在go1.16版本发布后,go module由原来的默认值 auto 变为 on 了,这意味着后续开发中,go更推荐用go module 模式开发,而不是gopath模式开发了。
Keson赞 11阅读 14.9k
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。