头图

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>

image.png


锅包肉
89 声望17 粉丝

这个人很懒,没有什么说的。