Kubernetes client-go使用方式
在Kubernetes
上,通常需要Client
来访问Kubernetes
中的对象,目前最常用的是RESTClient
, DynamicClient
和ClientSet
这三种Client
。
最基础的RESTClient
RESTClient
是Kubernetes
最基础的Client
,直接负责与Request
(RESTClient
中的概念)打交道。下面的Demo
就描述如何生成一个RESTClient
,并用该RESTClient
获取某具体Pod
的详细信息。
package main
import (
"flag"
"fmt"
"k8s.io/client-go/pkg/runtime"
"k8s.io/client-go/pkg/runtime/serializer"
"k8s.io/client-go/pkg/api"
v1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/api/unversioned"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := flag.String("kubeconfig", "/root/.kube/config", "Path to a kube config. Only required if out-of-cluster.")
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
fmt.Println("BuildConfigFromFlags error")
}
groupversion := &unversioned.GroupVersion{"", "v1"} // group version
config.GroupVersion = groupversion
config.APIPath = "/api" // api path : api or apis
config.ContentType = runtime.ContentTypeJSON //content type : json or yaml
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs}
restClient, err := rest.RESTClientFor(config)
if err != nil {
fmt.Println("RESTClientFor error")
}
pod := v1.Pod{} // response 数据序列化为 对象object
err = restClient.Get().Resource("pods").Namespace("default").Name("nginx-153451235-bw4j7").Do().Into(&pod)
if err != nil {
fmt.Println("error")
}
fmt.Println(pod)
}
DynamicClient
DynamicClient
是对RESTClient
的封装,支持动态设置访问类型
。 解决RESTClient
需要自己设置请求各属性,用起来很不方便的痛点
package main
import (
"flag"
"fmt"
"reflect"
"encoding/json"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/api/unversioned"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/rest"
)
func main() {
kubeconfig := flag.String("kubeconfig", "/root/.kube/config", "Path to a kube config. Only required if out-of-cluster.")
fmt.Println(kubeconfig)
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
fmt.Println("error1")
}
// 生成dynamicClient
gv := &unversioned.GroupVersion{"", "v1"}
resource := &unversioned.APIResource{Name: "pods", Namespaced: true}
config.ContentConfig = rest.ContentConfig{GroupVersion: gv}
config.APIPath = "/api"
dynamicClient, err := dynamic.NewClient(config)
if err != nil {
fmt.Println("dynamic NewCLient error")
}
// 获取所有namespace的pod列表
obj, err := dynamicClient.Resource(resource, "").List(&v1.ListOptions{})
if err != nil {
fmt.Println("dynamicClient Resource error")
}
js, err := json.Marshal(reflect.ValueOf(obj).Elem().Interface())
if err != nil {
fmt.Println("error")
}
podlist := v1.PodList{}
json.Unmarshal(js, &podlist)
fmt.Println(podlist)
fmt.Println("------------------------")
// 获取具体具体pod
obj, err = dynamicClient.Resource(resource, "default").Get("nginx-153451235-bw4j7")
if err != nil {
fmt.Println("dynamicClient Resource error")
}
js, err = json.Marshal(obj)
if err != nil {
fmt.Println("error")
}
pod := v1.Pod{}
json.Unmarshal(js, &pod)
fmt.Println(pod)
}
ClientSet
ClientSet
也是对RESTClient
的一种封装,与DynamicClient
不同的是,ClientSet
支持衍生出具体资源的Client
,如PodClient
、NodeClient
等。ClientSet
是Kubernetes
用的最多的Client
类型 。
package main
import (
"flag"
"fmt"
apiv1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := flag.String("kubeconfig", "/root/.kube/config", "Path to a kube config. Only required if out-of-cluster.")
fmt.Println(kubeconfig)
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
fmt.Println("error")
}
// 生成clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Println("error")
}
// 生成podCLient
podClient := clientset.Core().Pods("")
pods, err := podClient.List(apiv1.ListOptions{})
if err != nil {
fmt.Println("error")
}
for _, pod := range pods.Items {
fmt.Println(pod)
}
}
案例:如何访问自定义CRD
以 customlimitranges
CRD 为例: 技术方案之 对 Kubernetes Pod进程网络带宽 流量控制
部署 自定义CRD: customlimitranges.custom.cmss.com
dongjiang@MacBook Pro:crds $ kubectl get crds customlimitranges.custom.cmss.com
NAME CREATED AT
customlimitranges.custom.cmss.com 2023-01-10T05:17:47Z
dongjiang@MacBook Pro:crds $ kubectl describe crds customlimitranges.custom.cmss.com
Name: customlimitranges.custom.cmss.com
Namespace:
Labels: <none>
Annotations: <none>
API Version: apiextensions.k8s.io/v1
Kind: CustomResourceDefinition
Metadata:
Creation Timestamp: 2023-01-10T05:17:47Z
Generation: 1
Managed Fields:
API Version: apiextensions.k8s.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
....
dongjiang@MacBook Pro:crd $ kubectl api-resources | grep "cmss"
customlimitranges clr custom.cmss.com/v1 true CustomLimitRange
使用 DynamicClient
操作 CRD
package main
import (
"bufio"
"context"
"flag"
"fmt"
"os"
"path/filepath"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/client-go/util/retry"
)
func main() {
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
namespace := "default"
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err)
}
client, err := dynamic.NewForConfig(config)
if err != nil {
panic(err)
}
CRDRes := schema.GroupVersionResource{Group: "custom.cmss.com", Version: "v1", Resource: "customlimitranges"}
crd := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "custom.cmss.com/v1",
"kind": "CustomLimitRange",
"metadata": map[string]interface{}{
"name": "demo-crd",
},
"spec": map[string]interface{}{
"limitrange": map[string]interface{}{
"type": "pod",
"max": map[string]interface{}{
"ingress-bandwidth": "1G",
"egress-bandwidth": "1G",
},
"min": map[string]interface{}{
"ingress-bandwidth": "10M",
"egress-bandwidth": "10M",
},
"default": map[string]interface{}{
"ingress-bandwidth": "128M",
"egress-bandwidth": "128M",
},
},
},
},
}
// Create CRD
fmt.Println("Creating CRD...")
result, err := client.Resource(CRDRes).Namespace(namespace).Create(context.TODO(), crd, metav1.CreateOptions{})
if err != nil {
fmt.Printf("result: %v, err: %v", result, err)
panic(err)
}
fmt.Printf("Created CRD %q.\n", result.GetName())
// Update CRD
prompt()
fmt.Println("Updating CRD...")
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
result, getErr := client.Resource(CRDRes).Namespace(namespace).Get(context.TODO(), "demo-crd", metav1.GetOptions{})
if getErr != nil {
panic(fmt.Errorf("failed to get latest version of CRD: %v", getErr))
}
// update limitrange to max.ingress-bandwidth = 2G
if err := unstructured.SetNestedField(result.Object, "2G", "spec", "limitrange", "max", "ingress-bandwidth"); err != nil {
panic(fmt.Errorf("failed to set max.ingress-bandwidth value: %v", err))
}
// update limitrange to min.egress-bandwidth = 1M
if err := unstructured.SetNestedField(result.Object, "1M", "spec", "limitrange", "min", "egress-bandwidth"); err != nil {
panic(fmt.Errorf("failed to set max.ingress-bandwidth value: %v", err))
}
_, updateErr := client.Resource(CRDRes).Namespace(namespace).Update(context.TODO(), result, metav1.UpdateOptions{})
return updateErr
})
if retryErr != nil {
panic(fmt.Errorf("update failed: %v", retryErr))
}
fmt.Println("Updated CRD...")
// List CRD
prompt()
fmt.Printf("Listing CRD in namespace %q:\n", apiv1.NamespaceDefault)
list, err := client.Resource(CRDRes).Namespace(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err)
}
for _, d := range list.Items {
fmt.Printf(" * %s (%v)\n", d.GetName(), d)
}
// Delete CRD
prompt()
fmt.Println("Deleting CRD ...")
deletePolicy := metav1.DeletePropagationForeground
deleteOptions := metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
if err := client.Resource(CRDRes).Namespace(namespace).Delete(context.TODO(), "demo-crd", deleteOptions); err != nil {
panic(err)
}
fmt.Println("Deleted CRD.")
}
func prompt() {
fmt.Printf("-> Press Return key to continue.")
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
break
}
if err := scanner.Err(); err != nil {
panic(err)
}
fmt.Println()
}
结果:
dongjiang@MacBook Pro:dynamicclient $ ./dynamicclient -kubeconfig=/Users/dongjiang/Library/Application\ Support/Lens/kubeconfigs/510622b4-0ca1-4448-991d-ca4a0dcf89fd
Creating CRD...
Created CRD "demo-crd".
-> Press Return key to continue.
Updating CRD...
Updated CRD...
-> Press Return key to continue.
Listing CRD in namespace "default":
* demo-crd ({map[apiVersion:custom.cmss.com/v1 kind:CustomLimitRange metadata:map[creationTimestamp:2023-01-10T06:31:19Z generation:2 managedFields:[map[apiVersion:custom.cmss.com/v1 fieldsType:FieldsV1 fieldsV1:map[f:spec:map[.:map[] f:limitrange:map[.:map[] f:default:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:max:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:min:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:type:map[]]]] manager:dynamicclient operation:Update time:2023-01-10T06:31:19Z]] name:demo-crd namespace:default resourceVersion:48348363 selfLink:/apis/custom.cmss.com/v1/namespaces/default/customlimitranges/demo-crd uid:ab3e8e1b-6640-47c5-99ad-1422f34c8b6b] spec:map[limitrange:map[default:map[egress-bandwidth:128M ingress-bandwidth:128M] max:map[egress-bandwidth:1G ingress-bandwidth:2G] min:map[egress-bandwidth:1M ingress-bandwidth:10M] type:pod]]]})
* test-rangelimit ({map[apiVersion:custom.cmss.com/v1 kind:CustomLimitRange metadata:map[annotations:map[kubectl.kubernetes.io/last-applied-configuration:{"apiVersion":"custom.cmss.com/v1","kind":"CustomLimitRange","metadata":{"annotations":{},"name":"test-rangelimit","namespace":"default"},"spec":{"limitrange":{"default":{"egress-bandwidth":"128000k","ingress-bandwidth":"500M"},"max":{"egress-bandwidth":"1G","ingress-bandwidth":"1G"},"min":{"egress-bandwidth":"100M","ingress-bandwidth":"100M"},"type":"Pod"}}}
] creationTimestamp:2023-01-10T06:09:55Z generation:1 managedFields:[map[apiVersion:custom.cmss.com/v1 fieldsType:FieldsV1 fieldsV1:map[f:metadata:map[f:annotations:map[.:map[] f:kubectl.kubernetes.io/last-applied-configuration:map[]]] f:spec:map[.:map[] f:limitrange:map[.:map[] f:default:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:max:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:min:map[.:map[] f:egress-bandwidth:map[] f:ingress-bandwidth:map[]] f:type:map[]]]] manager:kubectl-client-side-apply operation:Update time:2023-01-10T06:09:55Z]] name:test-rangelimit namespace:default resourceVersion:48340023 selfLink:/apis/custom.cmss.com/v1/namespaces/default/customlimitranges/test-rangelimit uid:09fe7ad8-1efe-4742-85c1-919645476be1] spec:map[limitrange:map[default:map[egress-bandwidth:128000k ingress-bandwidth:500M] max:map[egress-bandwidth:1G ingress-bandwidth:1G] min:map[egress-bandwidth:100M ingress-bandwidth:100M] type:Pod]]]})
-> Press Return key to continue.
Deleting CRD ...
Deleted CRD.
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付