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>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。