本文承接上文
每期一个小窍门: 使用Gin 与 client-go 操作k8s (上)

后面应该还会有个下 应该是个operator的全程demo

项目结构如下

在这里插入图片描述

client.go

package client

import (
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"superclient/conf"
	"sync"
)

type MyClient struct {
	ClientSet       *kubernetes.Clientset
	DiscoveryClient *discovery.DiscoveryClient
}

var (
	clientInstance *MyClient = nil
	lock                     = sync.Mutex{}
	config         *rest.Config
)

func GetMyClient() (mc MyClient) {
	var (
		err error
	)
	config, err = clientcmd.BuildConfigFromFlags("", conf.Kubeconfig)
	if err != nil {
		return
	}
	mc.ClientSet, err = kubernetes.NewForConfig(config)
	if err != nil {
		return
	}
	mc.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(config)
	return
}
func (m *MyClient) ClientSet2() *kubernetes.Clientset {
	return m.ClientSet
}

func GetHttpConfig() *rest.Config {
	return config
}

informer.go
package informer

import (
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/informers"
	"superclient/core/pkg/client"
	"time"
)

var (
	sif informers.SharedInformerFactory
)

func NewSharedInformerFactory(stopCh <-chan struct{}) error {

	// 加载定制化客户端
	var (
		myClient client.MyClient
	)

	myClient = client.GetMyClient()

	// 实例化 sharedInformerFactory
	sif = informers.NewSharedInformerFactory(myClient.ClientSet2(), time.Second*10)

	// 制作 gvr
	gvrs := []schema.GroupVersionResource{
		{Group: "", Version: "v1", Resource: "pods"},
		{Group: "", Version: "v1", Resource: "services"},
		{Group: "", Version: "v1", Resource: "namespaces"},

		{Group: "apps", Version: "v1", Resource: "deployments"},
		{Group: "apps", Version: "v1", Resource: "statefulsets"},
		{Group: "apps", Version: "v1", Resource: "daemonsets"},
	}

	// 通过gvr 指定启动哪些informer
	for _, gvr := range gvrs {
		_, err := sif.ForResource(gvr)
		if err != nil {
			return err
		}
	}

	// 启动所有informer
	sif.Start(stopCh)

	// 等待informer 全量同步数据完成
	sif.WaitForCacheSync(stopCh)

	return nil
}

func Setup(stopCh <-chan struct{}) (err error) {
	err = NewSharedInformerFactory(stopCh)
	if err != nil {
		return err
	}
	return nil
}

func Get() informers.SharedInformerFactory {
	return sif
}

三个rest

  1. 查询pods
  2. 动态拼接 gvr 自动匹配indexer 并返回查询结果
  3. 路由转发到 apiserver 内容由apiserver 返回
mian.go
package main

import (
	"github.com/gin-gonic/gin"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/proxy"
	"k8s.io/client-go/rest"
	"net/http"
	"superclient/core/pkg/client"
	"superclient/core/pkg/informer"
)

func main() {

	stopCh := make(chan struct{})
	err := informer.Setup(stopCh)
	if err != nil {
		panic(err.Error())
	}

	// 启动Gin web服务
	// 实例化 Gin
	g := gin.Default()

	// 写路由
	// 直接查询某一种资源数据的
	g.GET("/pod/list", func(c *gin.Context) {

		items, err := informer.Get().Core().V1().Pods().Lister().List(labels.Everything())
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code":    40000, // 20000 的返回值表示正常,其他表示错误
				"message": err.Error(),
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"code":    20000, // 20000 的返回值表示正常,其他表示错误
			"message": "success",
			"data":    items,
		})
	})

	g.GET("/:resource/:group/:version", func(context *gin.Context) {

		gvr := schema.GroupVersionResource{
			Group:    context.Param("group"),
			Version:  context.Param("version"),
			Resource: context.Param("resource"),
		}
		informer, err := informer.Get().ForResource(gvr)

		if err != nil {
			return
		}
		pods, err := informer.Lister().List(labels.Everything())
		if err != nil {
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code": 20000,
			"data": pods,
		})
	})

	g.Any("/apis/*action", func(context *gin.Context) {

		t, err := rest.TransportFor(client.GetHttpConfig())
		if err != nil {
			panic(err.Error())
		}
		s := *context.Request.URL
		s.Host = "47.98.168.126:6443"
		s.Scheme = "https"
		httpProxy := proxy.NewUpgradeAwareHandler(&s, t, true, false, nil)
		httpProxy.UpgradeTransport = proxy.NewUpgradeRequestRoundTripper(t, t)
		httpProxy.ServeHTTP(context.Writer, context.Request)

		context.JSON(http.StatusOK, gin.H{
			"code":    20000,
			"message": "success",
			"data":    nil,
		})
	})
	_ = g.Run(":8080")
}

不论是请求转发到apiserver 还是动态gvr参数的请求 都是可以的
在这里插入图片描述
在这里插入图片描述

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐