Golang+Vue2 construye el sistema de gestión de fondo K8S desde cero (5) - Registro de contenedor y salida continua

Tabla de contenido

descripción general

extremo posterior

Interfaz

lograr efecto

Resumir


descripción general

En el último capítulo, nos dimos cuenta de la visualización de la lista de implementación, etc., y cuando se agregaron, eliminaron o modificaron algunos recursos, la nueva lista se volvería a representar y cargar automáticamente.

Lo que este capítulo quiere lograr es capturar los registros del Contenedor (opcional) en el Pod a través de go-client y enviarlos continuamente a la consola.

extremo posterior

Los registros también se obtienen a través de la interfaz API.

Es solo que la interfaz define una conexión larga y no devuelve ningún dato.

Los parámetros requeridos son espacio de nombres, nombre de pod, nombre de contenedor

Luego obtenga rest.request de acuerdo con go-client

Luego obtenga el flujo de solicitud para obtener io.Reader

func (this *PodLogsCtl) GetLogs(c *gin.Context) {
	ns := c.DefaultQuery("ns", "default")
	podname := c.DefaultQuery("podname", "")
	cname := c.DefaultQuery("cname", "")
	req := this.Client.CoreV1().Pods(ns).GetLogs(podname, &v1.PodLogOptions{
		Container: cname,
        //follow为true代表的是流式获取,否则只返回单次日志
		Follow:    true,
	})
	//单次获取
	//res, err := req.DoRaw(context.Background())
	//goft.Error(err)
	//return gin.H{
	//	"code": 20000,
	//	"data": string(res),
	//}
	//流式获取
	//gin会给每个请求都起一个协程,不设超时时间就会阻塞在read,导致每刷新一次多一个协程
	cc, _ := context.WithTimeout(context.Background(), time.Minute*5)
    //通过request的流获取到ioReader
	reader,_ := req.Stream(cc)
    //延迟reader的关闭
	defer reader.Close()
	for {
		b := make([]byte, 1024)
		n, err := reader.Read(b)
		if err != nil && err == io.EOF {
			break
		}
		if n > 0 {
			//长连接分段传输
			c.Writer.Write(b[0:n])
			c.Writer.(http.Flusher).Flush()
		}
	}
	return
}

Luego, solo use segmentos de bytes para obtener del lector, y escriba esta parte de los datos en el escritor de contexto y empújelo con Flush, el front-end puede recibir la información

Interfaz

Siguiente vistazo a la parte delantera

Debido a que es una conexión larga, para la solicitud de front-end de la parte de depuración conjunta de front-end y back-end, mi enfoque es crear una conexión larga dedicada longrequest.js

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 0 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

La diferencia con el archivo original request.js es que el tiempo de espera de axios utilizado para la solicitud se establece en 0 (el valor predeterminado es 5000, 0 significa que no hay tiempo de espera)

Por lo tanto, en el archivo Vue, hay una introducción como esta

//这里使用了长连接,无超时时间
import request from '@/utils/longrequest';

He agregado una columna de operación a la lista de Pod, que tiene un enlace a la página de registro. Haga clic en él para ir a la interfaz de visualización de registros del Pod correspondiente. Esta interfaz está oculta en la barra de navegación del índice.

Las etiquetas se definen así:

<router-link :to="{name:'Podlogs',params:{ns:scope.row.NameSpace,name:scope.row.Name}}"> <el-link  >日志<i class="el-icon-view el-icon--right"></i></el-link></router-link>

Se dirigió al componente llamado Podlogs y pasó el espacio de nombres y el nombre en los datos de la fila como parámetros al componente Vue.

En la función del sistema creado del componente Podlogs, debe recoger los parámetros enrutados

this.Name = this.$route.params.name
this.NameSpace = this.$route.params.ns

De acuerdo con estos parámetros, podemos solicitar nuevamente a la API de backend para obtener la lista de Contenedores en el Pod correspondiente, para que el usuario pueda seleccionar el contenedor que necesita para ver el Log en la interfaz.

Esto lleva a nuestro diseño de interfaz, que es muy simple. Posteriormente, la optimización de la visualización se puede realizar mediante la introducción de estilos de terceros.

<template>
  <div>
    <div style="padding-left: 20px;padding-top:30px">
      容器: <el-select  @change="containerChange"  placeholder="选择容器"
                      v-model="selectedContainer">
      <el-option v-for="c in containers "
                 :label="c.Name"
                 :value="c.Name"/>
    </el-select>
    </div>
    <div class="logs">
      {
   
   {logs}}
    </div>
  </div>
</template>
<style>
    .logs{
      overflow: auto;

      margin:10px auto;
      min-height: 200px;
      max-height: 400px;
      border: solid 1px black;
      background-color: #454545;
      padding: 10px;

      color:#27aa5e;
      line-height: 21pt;
      white-space: pre;
      width: 90%
    }
</style>

Entre ellos, cuando cambia el valor en el cuadro de selección del contenedor, la función vinculada se llamará automáticamente

Esta función nos solicitará que implementemos una buena conexión larga en el backend para obtener la API de registro. Ver la función a continuación

containerChange(){
  const ns=this.NameSpace
  const podname=this.Name
  const cname=this.selectedContainer
  request({
    url: '/v1/pods/logs?ns=' + ns + '&podname=' +podname + '&cname=' +cname,
    method: 'GET',
    //长连接等待后端传输数据,常用于下载进度条
    onDownloadProgress: e => {
      const dataChunk = e.currentTarget.response;
      this.logs+=dataChunk
    }
  });

}

Aquí solicitaremos a través de la solicitud que definimos anteriormente.

Vale la pena mencionar que aquí se usa el método onDownloadProgress. Este método se usa a menudo para mostrar la barra de progreso a través de una larga conexión entre el front-end y el back-end. También es aplicable aquí. Solo necesita agregar el contenido de registro obtenido. a los datos para la interpolación cuando se disparan las variables de la expresión.

lograr efecto

Resumir

La captura de registro del pod se puede realizar fácilmente a través de una conexión larga. En el próximo capítulo, usaremos la biblioteca websocket y xterm para realizar el terminal remoto del pod.

Supongo que te gusta

Origin blog.csdn.net/kingu_crimson/article/details/127503106
Recomendado
Clasificación