程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Kubernetes API-资源结构化和非结构化

发表于 2023-09-08 | 分类于 Kubernetes | 0 | 阅读次数 1962

在 Kubernetes 和相关的客户端库中,结构化对象和非结构化对象指的是如何处理和表示 Kubernetes 资源对象,它们有着不同的用法和用例。

基本概念

结构化对象(Structured Objects)

结构化对象指的是那些已经明确定义了其结构(属性和类型)的 Kubernetes API 对象。这些对象通常用具体的 Go 结构体来表示,每个结构体都对应于 Kubernetes API 中定义的一个资源类型(如 Pod、Deployment、Service 等)。这些结构化对象允许静态类型检查,以及 IDE 的代码完成功能,因为所有属性和方法在编译时都已经定义好了。

例如,下面是一个结构化的 Deployment 对象的示例:

deployment := &appsv1.Deployment{
    ObjectMeta: metav1.ObjectMeta{
        Name: "example-deployment",
    },
    Spec: appsv1.DeploymentSpec{
        // ... deployment spec configuration
    },
    // ... other fields
}

非结构化对象(Unstructured Objects)

非结构化对象则是一种灵活的表示方法,它使用 map[string]interface{} 数据结构来通用地表示 Kubernetes API 中的任何资源对象,而不需要一个预先定义的 Go 结构体。

下面是一个非结构化的对象的示例:

unstructuredObj := &unstructured.Unstructured{
    Object: map[string]interface{}{
        "apiVersion": "apps/v1",
        "kind":       "Deployment",
        "metadata": map[string]interface{}{
            "name": "example-deployment",
        },
        // ... other fields in a format of map
    },
}

// 资源对象的 GVK 可以这样设置
unstructuredObj.SetGroupVersionKind(schema.GroupVersionKind{
    Group:   "apps",
    Version: "v1",
    Kind:    "Deployment",
})

比较与联系

  • unstructured.Unstructured 直接解码的内容是 YAML/JSON,使用 unstructured.Unstructured 可以方便地操作任意类型的资源,在处理动态内容或者编写不具体依赖于资源具体类型的通用工具时非常有用,比如给不同资源打上同样的标签。如果使用结构体对象,则需要处理不同类型,而使用非结构化对象,那么只需要一个循环。

    var manifest = `
    apiVersion: v1
    kind: pod
    metadata:
      name: web
    spec:
      ...
    `
    // convert yaml to unstructured
    obj := &unstructured.Unstructured{}
    dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
    dec.Decode([]byte(manifest), nil, obj)
    
    labels := obj.GetLabels()
    labels["owner"]="xxx"
    obj.SetLabels(labels)
    
    dynamicClient.Resource().Namespace(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
    
  • 对于结构化对象来说,它们有着严格的类型校验。通过各种 clientset 可以方便地实现 API 资源对象增删改查,主要用于静态客户端。而对于使用 unstructured.Unstructured 类型的对象来说,不需要了解各个字段是怎么定义的,只需要从 YAML/JSON 转化为 unstructured.Unstructured 对象或者干脆直接定义 map[string]interface{} 来表示 Kubernetes API 对象即可,主要用于动态客户端。

    // 使用静态客户端与结构化对象来创建 Pod 对象
    import "k8s.io/client-go/kubernetes"
    
    clientset, err := kubernetes.NewForConfig(config)
    
    pod := &Corev1.Pod{}
    pod.Name = "web"
    pod.Spec = pod.PodSpec{
    	...
    }
    
    clientset.CoreV1().Pods(apiv1.NamespaceDefault).Create(pod)
    
    // 使用动态客户端与非结构化创建 Pod 对象
    import "k8s.io/client-go/dynamic"
    
    client, _ := dynamic.NewForConfig(config)
    podGVR := schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}
    
    pod := &unstructured.Unstructured{
    	Object: map[string]interface{}{
    		"apiVersion": "v1",
    		"kind":       "Pod",
    		"metadata": map[string]interface{}{
    			"name": "web",
    		},
    		"spec": map[string]interface{}{
    			"serviceAccount": "default",
    			...
    		}
    	}
    }
    
    client.Resource(podGVR).Namespace(namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
    
  • unstructured.Unstructured 对象也可以和具体资源对象相互转换,这个主要是借助了 Go 的反射机制,依赖于 runtime.UnstructuredConverter 接口,该接口定义了 unstructured.Unstructured 对象与具体资源对象的相互转换方法。同时,包中也内置了 runtime.DefaultUnstructuredConverter,其实现了 runtime.unstructuredConverter 接口。

    type UnstructuredConverter interface {
    	ToUnstructured(obj interface{}) (map[string]interface{}, error)
    	FromUnstructured(u map[string]interface{}, obj interface{}) error
    }
    
    DefaultUnstructuredConverter = &unstructuredConverter{
    		mismatchDetection: parseBool(os.Getenv("KUBE_PATCH_CONVERSION_DETECTOR")),
    		comparison: conversion.EqualitiesOrDie(
    			func(a, b time.Time) bool {
    				return a.UTC() == b.UTC()
    			},
    		),
    	}
    
  • 但是,无论使用哪种方式,最终都会调用 Kubernetes 的 RESTful API,比如上面创建 Pod 的例子最后都是执行 POST /api/v1/namespaces/{namespace}/pods/{name} 请求。

runtime.Object

Pod、Service、Deployment 等结构化对象,都实现了 runtime.Object 接口。

  • 每个 API 资源对象都继承了 metav1.TypeMeta,TypeMeta 实现了 GetObjectKind() 方法,因此默认实现了 GetObjectKind() 方法。
  • 每个 API 资源对象,都将由工具自动生成 DeepCopyObject() 方法,定义在 zz_generated.deepcopy.go 文件中。

因此,runtime.Object 接口可以表示任何类型的结构化资源对象。

type Object interface {
	GetObjectKind() schema.ObjectKind
	DeepCopyObject() Object
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ConfigMap) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

unstructured.Unstructured

非结构化资源对象使用 unstructured.Unstructured 表示,如下所示。

type Unstructured struct {
	// Object is a JSON compatible map with string, float, int, bool, []interface{}, or
	// map[string]interface{} children.
	Object map[string]interface{}
}

unstructured.Unstructured 实现了存取类型元信息与对象元信息的方法,也实现了 runtime.Unstructured 接口中的所有方法。

// 存取类型元信息和对象元信息的方法
func (u *Unstructured) GetAPIVersion() string {
	return getNestedString(u.Object, "apiVersion")
}

func (u *Unstructured) SetAPIVersion(version string) {
	u.setNestedField(version, "apiVersion")
}

func (u *Unstructured) GetKind() string {
	return getNestedString(u.Object, "kind")
}

func (u *Unstructured) SetKind(kind string) {
	u.setNestedField(kind, "kind")
}
...

// runtime.Unstructured 接口
type Unstructured interface {
	Object
  
	NewEmptyInstance() Unstructured

	UnstructuredContent() map[string]interface{}
	
	SetUnstructuredContent(map[string]interface{})

	IsList() bool

	EachListItem(func(Object) error) error
}
卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/243
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Kubernetes
Kubernetes API-整体概述
Kubernetes API 资源-Event
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%