基于 Client-go 操作 namespace 资源配额设计

前情提要

基于 K8s/k3s 进行二次开发设计时,需要开发人员比较频繁的操作接口进行资源调度查询操作的工作,本文将围绕 client-go 创建自定义配额的 namespace 进行展开,从而梳理 client-go 创建资源的一些注意事项,从而形成一定指导意义的文档材料。

实践指南

接下来将会通过以下方面展开创建存在资源限制的命名空间操作,查看资源监听和一些配置的规格要求。

环境要求

  1. Go 1.16+
  2. K8s/K3s 集群
  3. client-go:1.18.3
go get k8s.io/client-go/...

后台操作

1 创建名字空间,创建一个单独的名字空间,以便于隔离练习中创建的资源与集群的其他资源

kubectl create namespace quota-mem-cpu-example

2 创建ResourceQuota对象(quota-mem-cpu.yaml)

apiVersion: v1 
kind: ResourceQuota 
metadata: 
  name: mem-cpu-demo
spec: 
  hard: 
    pods: "4" 
    requests.cpu: "1" 
    requests.memory: 1Gi 
    limits.cpu: "2" 
    limits.memory: 2Gi

注: 资源规格的层次有 pod,cpu,memory 和存储,常规限制的资源有 cpu 和 memory.

3 关联命名空间和资源配额

kubectl create -f quota-mem-cpu.yaml --namespace=quota-mem-cpu-example

4 查询配额资源对象相信

# 查看所有的配额资源
kubectl  get ResourceQuotas -A
# 查看资源配额描述(方式一)
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
# 查看资源配额描述(方式二)
kubectl  get ResourceQuotas -n quota-mem-cpu-example   mem-cpu-demo  -oyaml

接口查询

1 获取 K8S/k3s 集群的接口调用权限
参考: https://www.cnblogs.com/vpc123/articles/14519068.html
2 获取 K8S/k3s 集群的 clientset 句柄

package main

import (
    "context"
    "fmt"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "sigs.k8s.io/controller-runtime/pkg/log"
)

type Config struct {
    Host  string
    Token string
    Port  int
}

func main()  {

    clientSet,_:=NewKubernetesClient(&Config{
       Host:  "192.168.139.134",
       Port:  6443,
       Token: "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikg3THcwRzVHTkdQNDREUi1fRjlQOE45NjBUd29pZDQydEs4Tmd1SFJpNnMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tbWpudmsiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNjdiNGZjM2ItZGEyZS00OTdhLWJmOTEtZGFmYWU3NmU5ZTU3Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.kW_8iz1GpZPWL2hqDd2Jhkc-rLEX5QPKYrDCmEATyhl_834rmxRg9PJBmRhPY6T7IL58JP9ffUXlF-m65A3H8nOi47dVoAOy9jAPul8C0jS2uZrXYB4zrz_XwXfoonK4lEJtiT86ULd3M3lrUXvEI5kR8ywn3fRBTz5hVRbs0lrgfmFRY_87zELZuBFjSi-pAZTNr_lrAUtBT3Q3h3JyDXHdUJzqoWM-WcszNAZD2wJDV06PpSkNxMOCl6l0BNvUmaY3uLODb5-2yiywasfI9Ue6vKIYEmisNTk48mvbaoIEO34Gg7N1DnvFsO7raoiV_NZ_1KCJDYnxw0jC88Cr0w",
    })

    namespaceList, err := clientSet.CoreV1().Namespaces().List(context.TODO(),metav1.ListOptions{})
    if err!=nil{
        log.Log.Info(err.Error())
    }
    //namespaces:=GetAllNamespace(clientset)
    var namespaces []string
    fmt.Println("******************")

    for _,nsList := range namespaceList.Items {
        fmt.Println(nsList.Name)
        namespaces=append(namespaces, nsList.Name)
    }

    fmt.Println("******************")

}


func NewKubernetesClient(c *Config) (*kubernetes.Clientset, error) {
    kubeConf := &rest.Config{
        Host:        fmt.Sprintf("%s:%d", c.Host, c.Port),
        BearerToken: c.Token,
        TLSClientConfig: rest.TLSClientConfig{
            Insecure: true,
        },
    }
    return kubernetes.NewForConfig(kubeConf)
}

// GetAllNamespace get all namespace in cluster.
func GetAllNamespace(clientset *kubernetes.Clientset) ([]string){
    var namespaces []string
    namespaceList, err := clientset.CoreV1().Namespaces().List(context.TODO(),metav1.ListOptions{})

    if err != nil {
        log.Log.Info("***************err*****************")
        log.Log.Info(err.Error())
    }else{
        //fmt.Printf(namespaces[0])
        for _,nsList := range namespaceList.Items {
            namespaces=append(namespaces, nsList.Name)
        }
    }

    return namespaces
}

说明: 将代码中的 toekn & ip 信息更新成为自己的集群的对应正确的关键字段信息即可通过上述的方式获取到自己集群的句柄,并开始调用接口实现 K8s 集群内的资源查询和调度实现。

3 创建具有资源配额的命名空间

# 创建全新的命名空间
// create namespace.
namespaceClient := clientset.CoreV1().Namespaces()
namespace := &corev1.Namespace{
	ObjectMeta: metav1.ObjectMeta{
		Name: r.NamespaceName,
	},
}
_, err := namespaceClient.Create(context.TODO(),namespace,metav1.CreateOptions{})
if err != nil {
	log.V(2).Info(err.Error())
	return false
}else{
	log.V(1).Info("Create namesapce SuccessFul.")
}


# 关联资源配额
// create ResourceQuotas
quotaTest:=clientset.CoreV1().ResourceQuotas(r.NamespaceName)
quota := &corev1.ResourceQuota{
	ObjectMeta: metav1.ObjectMeta{
		Name: "quota-"+r.NamespaceName,
	},
	Spec:corev1.ResourceQuotaSpec{
		Hard: map[corev1.ResourceName]resource.Quantity{
			corev1.ResourceLimitsCPU : resource.MustParse(clusterObjectActor.Spec.Resources.Limits.Cpu().String()),
			corev1.ResourceLimitsMemory : resource.MustParse(clusterObjectActor.Spec.Resources.Limits.Memory().String()),
			corev1.ResourceRequestsCPU: resource.MustParse(clusterObjectActor.Spec.Resources.Requests.Cpu().String()),
			corev1.ResourceRequestsMemory: resource.MustParse(clusterObjectActor.Spec.Resources.Requests.Memory().String()),
		},
	},
}

_, err1 := quotaTest.Create(context.TODO(),quota,metav1.CreateOptions{})
if err1 != nil {
	log.V(2).Info(err1.Error())
	return false
}else{
	log.V(1).Info("Create quota SuccessFul.")
}

注: 当前仅仅配置资源 cpu&memory ,根据开发需求进行设计出满足自己的需求即可,上述代码仅做讲解不适合直接在环境中直接运行,需要调整以后进行代码的更替实现自有环境的运行调用测试。

拓展阅读

client-go 开发接口: https://v1-19.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#resourcequota-v1-core
k8s 官方文档: https://kubernetes.io/zh/docs/concepts/policy/resource-quotas/

posted @ 2021-04-11 00:13  流雨声  阅读(1698)  评论(1编辑  收藏  举报