Skip to content

Pod管理 原创

1、功能

35543557025faf0bd11be0c31be7864c MD5

2、类型转换

2.1、定义类型

internal\pkg\k8s\pod\common.go,写入以下内容:

go
package k8s

import (
	"time"

	corev1 "k8s.io/api/core/v1"
)

type PodCell corev1.Pod

func (p PodCell) GetCreation() time.Time {
	return p.CreationTimestamp.Time
}

func (p PodCell) GetName() string {
	return p.Name
}

我们定义了 PodCell 类型,然后实现了 GetCreationGetName 方法,这样 corev1.Pod 类型就能转换成 PodCell 类型,而 PodCell 又实现了 DataCell 接口,所以 corev1.Pod 可以转换成 DataCell 类型。

2.2、实现类型转换

internal\pkg\k8s\pod\common.go,写入以下内容:

go
package pod

import (
	"time"

	"github.com/joker-bai/hawkeye/internal/pkg/k8s/dataselect"
	corev1 "k8s.io/api/core/v1"
)

......

// toCells corev1.Pod 类型 转换成 DataCell 类型
// @description: Pod类型转换成DataCell
func toCells(pods []corev1.Pod) []dataselect.DataCell {
	cells := make([]dataselect.DataCell, len(pods))
	for i := range pods {
		cells[i] = PodCell(pods[i])
	}
	return cells
}

// fromCells DataCell 类型转换成 corev1.Pod 类型
// @description: DataCell类型转换成Pod
func fromCells(cells []dataselect.DataCell) []corev1.Pod {
	pods := make([]corev1.Pod, len(cells))
	for i := range cells {
		pods[i] = corev1.Pod(cells[i].(PodCell))
	}
	return pods
}

实现了 PodsToCellsCellsToPods 两个方法,这两个方法就是实现类型转换的。

2.3 实现增删改查方法

列出所有 Pod

internal\pkg\k8s\pod\list.go新增如下代码,实现查询集群所有 Pod 操作。

go
package pod

import (
	"context"

	"github.com/joker-bai/hawkeye/global"
	"github.com/joker-bai/hawkeye/internal/pkg/k8s/dataselect"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GetPodList(name, namespace string, page, limit int) ([]corev1.Pod, error) {
	pods, err := global.K8S.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, err
	}

	// 对数据进行分页排序
	selector := dataselect.DataSelector{
		GenericDataList: toCells(pods.Items),
		DataSelectQuery: &dataselect.DataSelectQuery{
			Filter: &dataselect.FilterQuery{
				Name: name,
			},
			Paginate: &dataselect.PaginateQuery{
				Page:  page,
				Limit: limit,
			},
		},
	}

	// 过滤
	filterd := selector.Filter()

	// 排序、分页
	data := filterd.Sort().Paginate()

	return fromCells(data.GenericDataList), nil
}

更新 Pod

internal\pkg\k8s\pod\update.go中新增以下代码:

go
package pod

import (
	"context"
	"encoding/json"

	"github.com/joker-bai/hawkeye/global"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// UpdatePod 更新Pod
func UpdatePod(namespace, content string) error {
	var pod corev1.Pod
	// 反序列化Content
	if err := json.Unmarshal([]byte(content), &pod); err != nil {
		return err
	}

	if _, err := global.K8S.CoreV1().Pods(namespace).Update(context.TODO(), &pod, metav1.UpdateOptions{}); err != nil {
		return err
	}
	return nil
}

删除 Pod

internal\pkg\k8s\pod\delete.go中新增以下代码:

go
package pod

import (
	"context"

	"github.com/joker-bai/hawkeye/global"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// DeletePod 删除Pod
func DeletePod(name, namespace string) error {
	err := global.K8S.CoreV1().Pods(name).Delete(context.TODO(), name, metav1.DeleteOptions{})
	if err != nil {
		return err
	}
	return nil
}

获取 Pod 详情

internal\pkg\k8s\pod\detail.go中新增以下代码:

go
package pod

import (
	"context"

	"github.com/joker-bai/hawkeye/global"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// GetPodDetail 获取Pod详情
func GetPodDetail(name, namespace string) (*corev1.Pod, error) {
	pod, err := global.K8S.CoreV1().Pods(name).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return pod, nil
}

获取 Pod 日志

internal\pkg\k8s\pod\log.go增加以下内容:

go
package pod

import (
	"bytes"
	"context"
	"io"

	"github.com/joker-bai/hawkeye/global"
	corev1 "k8s.io/api/core/v1"
)

func GetPodLog(name, namespace, container string, tailLine int64) (string, error) {
	options := &corev1.PodLogOptions{
		Container: container,
		TailLines: &tailLine,
	}
	req := global.K8S.CoreV1().Pods(namespace).GetLogs(name, options)
	podLog, err := req.Stream(context.TODO())
	if err != nil {
		return "", err
	}

	defer podLog.Close()

	// 将 response body 写入到缓冲区,目的是为了转换成可读的string类型
	buff := new(bytes.Buffer)
	_, err = io.Copy(buff, podLog)
	if err != nil {
		return "", err
	}
	log := buff.String()

	return log, nil
}

获取容器相关操作

由于获取容器名是大部分控制器都需要,所以将它们放到 common 包里。

internal\pkg\k8s\common\pod.go中新增以下代码:

go
package common

import corev1 "k8s.io/api/core/v1"

// GetContainerNames 获取容器名
func GetContainerNames(podTemplate *corev1.PodSpec) []string {
	var containerNames []string
	for _, container := range podTemplate.Containers {
		containerNames = append(containerNames, container.Name)
	}
	return containerNames
}

// GetInitContainerNames 获取Init容器名
func GetInitContainerNames(podTemplate *corev1.PodSpec) []string {
	var initContainerNames []string
	for _, container := range podTemplate.InitContainers {
		initContainerNames = append(initContainerNames, container.Name)
	}
	return initContainerNames
}

// GetContainerImages 获取容器的镜像
func GetContainerImages(podTemplate *corev1.PodSpec) []string {
	var containerImages []string
	for _, container := range podTemplate.Containers {
		containerImages = append(containerImages, container.Image)
	}
	return containerImages
}

// GetInitContainerImages 获取Init容器的镜像
func GetInitContainerImages(podTemplate *corev1.PodSpec) []string {
	var initContainerImages []string
	for _, container := range podTemplate.InitContainers {
		initContainerImages = append(initContainerImages, container.Image)
	}
	return initContainerImages
}

主要是获取容器名和容器镜像的操作。

这里没有创建 Pod 的操作,在正常情况下,不会单独创建 Pod。

3、实现 services 方法

这里同一把上面所有方法都实现。

3.1、请求参数校验

首先,在internal\app\requests\common.go中增加 K8s 公共的字段,如下:

go
type K8sCommonRequest struct {
	Name      string `json:"name" form:"name" valid:"name"`
	Namespace string `json:"namespace" form:"namespace" valid:"namespace"`
}

func ValidK8sCommonRequest(data interface{}, ctx *gin.Context) map[string][]string {
	rules := govalidator.MapData{
		"name":      []string{"required"},
		"namespace": []string{"required"},
	}
	messages := govalidator.MapData{
		"name": []string{
			"required: name不能为空",
		},
		"namespace": []string{
			"required: namespace不能为空",
		},
	}

	// 校验入参
	return app.ValidateOptions(data, rules, messages)
}

internal/app/requests 目录中新增 k8s_pod.go 文件,写入如下代码实现各功能模块的参数校验:

go
package requests

import (
	"github.com/gin-gonic/gin"
	"github.com/joker-bai/hawkeye/pkg/app"
	"github.com/thedevsaddam/govalidator"
)

type K8sPodListRequest struct {
	K8sCommonRequest
	Page  int `json:"page" form:"page" valid:"page"`    // 页数
	Limit int `json:"limit" form:"limit" valid:"limit"` // 每页条数
}

func ValidK8sPodLisRequest(data interface{}, ctx *gin.Context) map[string][]string {
	rules := govalidator.MapData{
		"namespace": []string{"required"},
		"page":      []string{"required"},
		"limit":     []string{"required"},
	}
	messages := govalidator.MapData{
		"namespace": []string{
			"required: namespace不能为空",
		},
		"page": []string{
			"required: page不能为空",
		},
		"limit": []string{
			"required: limit不能为空",
		},
	}

	// 校验入参

	return app.ValidateOptions(data, rules, messages)
}

type K8sPodUpdateRequest struct {
	Namespace string `json:"namespace,omitempty" form:"namespace" valid:"namespace"`
	Content   string `json:"content,omitempty" form:"content" valid:"content"`
}

func ValidK8sPodUpdateRequest(data interface{}, ctx *gin.Context) map[string][]string {
	rules := govalidator.MapData{
		"namespace": []string{"required"},
		"content":   []string{"required"},
	}
	messages := govalidator.MapData{
		"namespace": []string{
			"required: namespace 不能为空",
		},
		"content": []string{
			"required: content 不能为空",
		},
	}

	// 校验入参

	return app.ValidateOptions(data, rules, messages)
}

3.2、实现 services 具体方法

internal/app/services/k8s_pod.go 文件中,新增如下代码:

go
package services

import (
	"github.com/joker-bai/hawkeye/internal/app/requests"
	"github.com/joker-bai/hawkeye/internal/pkg/k8s/common"
	"github.com/joker-bai/hawkeye/internal/pkg/k8s/pod"
	corev1 "k8s.io/api/core/v1"
)

// K8sPodList 获取Pod列表
func (s *Services) K8sPodList(param *requests.K8sPodListRequest) ([]corev1.Pod, error) {
	pods, err := pod.GetPodList(param.Name, param.Namespace, param.Page, param.Limit)
	if err != nil {
		return nil, err
	}
	return pods, nil
}

// K8sPodDelete 从Pod列表中删除Pod
func (s *Services) K8sPodDelete(param *requests.K8sCommonRequest) error {
	err := pod.DeletePod(param.Name, param.Namespace)
	if err != nil {
		return err
	}
	return nil
}

// K8sPodUpdate 更新Pod
func (s *Services) K8sPodUpdate(param *requests.K8sPodUpdateRequest) error {
	err := pod.UpdatePod(param.Namespace, param.Content)
	if err != nil {
		return err
	}
	return nil
}

// GetContainerNames 获取容器名称列表
func (s *Services) GetContainerNames(param *requests.K8sCommonRequest) ([]string, error) {
	// 先获取Pod详情
	pod, err := pod.GetPodDetail(param.Name, param.Namespace)
	if err != nil {
		return nil, err
	}

	// 获取container
	containers := common.GetContainerNames(&pod.Spec)
	return containers, nil
}

// GetInitContainerNames 获取Init容器名称列表
func (s *Services) GetInitContainerNames(param *requests.K8sCommonRequest) ([]string, error) {
	// 先获取Pod详情
	pod, err := pod.GetPodDetail(param.Name, param.Namespace)
	if err != nil {
		return nil, err
	}

	// 获取container
	containers := common.GetInitContainerNames(&pod.Spec)
	return containers, nil
}

// GetContainerImages 获取容器镜像名称列表
func (s *Services) GetContainerImages(param *requests.K8sCommonRequest) ([]string, error) {
	// 先获取Pod详情
	pod, err := pod.GetPodDetail(param.Name, param.Namespace)
	if err != nil {
		return nil, err
	}

	// 获取container
	images := common.GetContainerImages(&pod.Spec)
	return images, nil
}

// GetInitContainerImages 获取Init容器镜像名称列表
func (s *Services) GetInitContainerImages(param *requests.K8sCommonRequest) ([]string, error) {
	// 先获取Pod详情
	pod, err := pod.GetPodDetail(param.Name, param.Namespace)
	if err != nil {
		return nil, err
	}

	// 获取container
	images := common.GetInitContainerImages(&pod.Spec)
	return images, nil
}

// GetPodLogs 获取Pod日志
func (s *Services) GetPodLogs(param *requests.K8sPodLogRequest) (string, error) {
	log, err := pod.GetPodLog(param.Name, param.Namespace, param.Container, param.TailLine)
	if err != nil {
		return "", nil
	}
	return log, nil
}

4、实现控制器方法

internal\app\controllers\api\v1\k8s\pod.go 文件中写入以下内容:

go
package k8s

import (
	"github.com/gin-gonic/gin"
	"github.com/joker-bai/hawkeye/global"
	"github.com/joker-bai/hawkeye/internal/app/requests"
	"github.com/joker-bai/hawkeye/internal/app/services"
	"github.com/joker-bai/hawkeye/pkg/app"
	"github.com/joker-bai/hawkeye/pkg/errorcode"
	"go.uber.org/zap"
)

type PodController struct{}

// List godoc
// @Summary 列出K8s Pod
// @Description 列出K8s Pod
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Param page query int true "页码"
// @Param limit query int true "每页数量"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/list [get]
func (k *PodController) List(ctx *gin.Context) {
	param := requests.K8sPodListRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sPodLisRequest); !ok {
		return
	}

	svc := services.New(ctx)
	pods, err := svc.K8sPodList(&param)
	if err != nil {
		global.Log.Error("获取Pod列表失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sPodListFail)
		return
	}

	response.ToResponseList(pods, len(pods))
}

// Update godoc
// @Summary 更新Pod
// @Description 更新Pod
// @Tags K8s Pod管理
// @Produce json
// @Param body body requests.K8sPodUpdateRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/update [post]
func (k *PodController) Update(ctx *gin.Context) {
	param := requests.K8sPodUpdateRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sPodUpdateRequest); !ok {
		return
	}

	svc := services.New(ctx)
	err := svc.K8sPodUpdate(&param)
	if err != nil {
		global.Log.Error("更新Pod失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sPodUpdateFail)
		return
	}

	response.ToResponse(gin.H{
		"msg": "Pod更新成功",
	})
}

// Delete godoc
// @Summary 删除Pod
// @Description 删除Pod
// @Tags K8s Pod管理
// @Produce json
// @Param body body requests.K8sCommonRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/delete [post]
func (k *PodController) Delete(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	err := svc.K8sPodDelete(&param)
	if err != nil {
		global.Log.Error("删除Pods失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sPodDeleteFail)
		return
	}

	response.ToResponse(gin.H{
		"msg": "Pod删除成功",
	})
}

// Detail godoc
// @Summary 获取Pod的详情
// @Description 获取Pod的详情
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Job名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/detail [get]
func (k *PodController) Detail(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	pod, err := svc.K8sPodDetail(&param)
	if err != nil {
		global.Log.Error("获取获取Pod的详情失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sPodDetailFail)
		return
	}

	response.ToResponse(gin.H{
		"data": pod,
		"msg":  "获取Pod的详情成功",
	})
}

// GetContainerName godoc
// @Summary 获取Pod的容器名
// @Description 获取Pod的容器名
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/container_name [get]
func (k *PodController) GetContainerName(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	containers, err := svc.GetContainerNames(&param)
	if err != nil {
		global.Log.Error("获取Pod容器名失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sGetContainerName)
		return
	}

	response.ToResponseList(containers, len(containers))
}

// GetInitContainerName godoc
// @Summary 获取Pod的Init容器名
// @Description 获取Pod的Init容器名
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/init_container_name [get]
func (k *PodController) GetInitContainerName(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	containers, err := svc.GetInitContainerNames(&param)
	if err != nil {
		global.Log.Error("获取Pod的Init容器名失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sGetInitContainerName)
		return
	}

	response.ToResponseList(containers, len(containers))
}

// GetContainerImage godoc
// @Summary 获取Pod的容器镜像
// @Description 获取Pod的容器镜像
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/container_image [get]
func (k *PodController) GetContainerImage(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	iamges, err := svc.GetContainerImages(&param)
	if err != nil {
		global.Log.Error("获取Pod容器镜像失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sGetContainerImage)
		return
	}

	response.ToResponseList(iamges, len(iamges))
}

// GetInitContainerImage godoc
// @Summary 获取Pod的Init容器镜像
// @Description 获取Pod的Init容器镜像
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/init_container_image [get]
func (k *PodController) GetInitContainerImage(ctx *gin.Context) {
	param := requests.K8sCommonRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sCommonRequest); !ok {
		return
	}

	svc := services.New(ctx)
	images, err := svc.GetInitContainerImages(&param)
	if err != nil {
		global.Log.Error("获取Pod的Init容器名失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sGetInitContainerImage)
		return
	}

	response.ToResponseList(images, len(images))
}

// GetContainerLog godoc
// @Summary 获取Pod的容器日志
// @Description 获取Pod的容器日志
// @Tags K8s Pod管理
// @Produce json
// @Param name query string false "Pod名" maxlength(100)
// @Param namespace query string false "命名空间" maxlength(100)
// @Param container query string false "容器" maxlength(100)
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/k8s/pod/container_log [get]
func (k *PodController) GetContainerLog(ctx *gin.Context) {
	param := requests.K8sPodLogRequest{}
	response := app.NewResponse(ctx)

	if ok := app.Validate(ctx, &param, requests.ValidK8sPodLogRequest); !ok {
		return
	}

	svc := services.New(ctx)
	logs, err := svc.GetPodLogs(&param)
	if err != nil {
		global.Log.Error("获取Pod的Init容器名失败", zap.String("error", err.Error()))
		response.ToErrorResponse(errorcode.ErrorK8sGetContainerLog)
		return
	}

	response.ToResponse(gin.H{
		"data": logs,
	})
}

再到 pkg/errorcode/k8s.go 文件中新增 Pod 操作的错误码:

go
package errorcode

var (
	// K8s集群管理错误码
	......

	// K8s Pod错误码
	ErrorK8sPodUpdateFail         = NewError(500011, "更新K8s Pod失败")
	ErrorK8sPodDeleteFail         = NewError(500012, "删除K8s Pod失败")
	ErrorK8sPodListFail           = NewError(500013, "获取K8s Pod列表失败")
	ErrorK8sPodDetailFail         = NewError(500014, "获取K8s Pod详情失败")
	ErrorK8sGetContainerName      = NewError(500015, "获取K8s Pod容器名失败")
	ErrorK8sGetContainerImage     = NewError(500016, "获取K8s Pod容器镜像失败")
	ErrorK8sGetInitContainerName  = NewError(500017, "获取K8s Pod Init容器名失败")
	ErrorK8sGetInitContainerImage = NewError(500018, "获取K8s Pod Init容器镜像失败")
	ErrorK8sGetContainerLog       = NewError(500019, "获取K8s Pod 容器日志失败")
)

5、新增路由

在 internal/app/routers/k8s.go 文件中实现路由方法,如下:

go
package routers

import (
	"github.com/gin-gonic/gin"
	v1 "github.com/joker-bai/kubemana/internal/app/controllers/api/v1"
)

type K8sRouter struct{}

func (r *K8sRouter) Inject(router *gin.RouterGroup) {

	k8s := router.Group("/k8s")
	{
		// K8s集群管理
		.....

		// Pod管理
		kp := new(k8s.PodController)
		ks.POST("/pod/update", kp.Update)
		ks.POST("/pod/delete", kp.Delete)
		ks.GET("/pod/list", kp.List)
		ks.GET("/pod/container_name", kp.GetContainerName)
		ks.GET("/pod/init_container_name", kp.GetInitContainerName)
		ks.GET("/pod/container_image", kp.GetContainerImage)
		ks.GET("/pod/init_container_image", kp.GetInitContainerImage)
		ks.GET("/pod/container_log", kp.GetContainerLog)
	}
}

6、测试一下

(1)先初始化集群

先使用集群初始化接口初始化集群,如下:

9fe8a9b2416b9335f08b670079f6e9a1 MD5

(2)测试 Pod 列表

使用列出 Pod 接口测试如下:

a10b2a889453ad09ad6e4232cc7232b6 MD5

最近更新