golang 后盾代码
package mainimport ( "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>