【问题标题】:Parse YAML manifests to Kubernetes []client.Object将 YAML 清单解析为 Kubernetes []client.Object
【发布时间】:2021-11-15 02:19:30
【问题描述】:

我有一个 YAML 文件,它定义了多个不同类型的 Kubernetes 资源(根据 YAML 规范,用 --- 分隔):

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # ...
spec:
  # ...
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # ...
rules:
  # ...
---
# etc

现在,我想将此列表解析为 client.Object 实例的切片,因此我可以应用一些过滤和转换,并最终使用

将它们发送到集群
myClient.Patch( # myClient is a client.Client instance
  ctx,
  object,       # object needs to be a client.Object
  client.Apply,
  client.ForceOwnership,
  client.FieldOwner("my.operator.acme.inc"),
)

但是,我终其一生都无法弄清楚如何从 YAML 文档转到 []client.Object。以下让我几乎在那里:

results := make([]client.Object, 0)

scheme := runtime.NewScheme()
clientgoscheme.AddToScheme(scheme)
apiextensionsv1beta1.AddToScheme(scheme)
apiextensionsv1.AddToScheme(scheme)

decode := serializer.NewCodecFactory(scheme).UniversalDeserializer().Decode
data, err := ioutil.ReadAll(reader)
if err != nil {
    return nil, err
}
for _, doc := range strings.Split(string(data), "---") {
    object, gvk, err := decode([]byte(doc), nil, nil)
    if err != nil {
        return nil, err
    }

    // object is now a runtime.Object, and gvk is a schema.GroupVersionKind
    // taken together, they have all the information I need to expose a
    // client.Object (I think) but I have no idea how to actually construct a
    // type that implements that interface

    result = append(result, ?????)

}

return result, nil

当然,我对其他解析器实现完全开放,但我还没有找到任何能让我更进一步的东西。但这似乎必须在 Kubernetes 世界中是一个已解决的问题......那我该怎么做呢?

【问题讨论】:

  • @Inian 请注意,YAML 文件包含不同资源类型的多个清单(我不想将自己锁定为仅支持某些类型;任何我没有特定逻辑的东西都应该通过到集群,所以我需要支持解析任何类型,包括在 YAML 文件中定义的 CRD 的自定义资源)。据我所知,您所链接的问题的答案仅显示了如何解析为比 runtime.Object 更好的类型,前提是您在编译时知道要反序列化的类型。
  • (不假设的答案,编译时,正在反序列化的资源类型,正是我在这里所做的......)

标签: go kubernetes


【解决方案1】:

我终于可以让它工作了!方法如下:

import (
    "k8s.io/client-go/kubernetes/scheme"
    "sigs.k8s.io/controller-runtime/pkg/client"

    apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
)

func deserialize(data []byte) (*client.Object, error) {
    apiextensionsv1.AddToScheme(scheme.Scheme)
    apiextensionsv1beta1.AddToScheme(scheme.Scheme)
    decoder := scheme.Codecs.UniversalDeserializer()

    runtimeObject, groupVersionKind, err := decoder.Decode(data, nil, nil)
    if err != nil {
        return nil, err
    }

    return runtime
}

有几件事看起来很关键(但我不确定我的理解是否 100% 正确):

  • 虽然decoder.Decode 的声明返回类型是(runtime.Object, *scheme.GroupVersionKind, error),但该元组返回的第一项实际上是client.Object,可以毫无问题地进行转换。
  • 通过在添加apiextensions.k8s.io 组之前使用scheme.Scheme 作为基线,我可以免费注册所有“标准”资源。
  • 如果我使用scheme.Codecs.UniversalDecoder(),我会收到关于 no kind "CustomResourceDefinition" is registered for the internal version of group "apiextensions.k8s.io" in scheme "pkg/runtime/scheme.go:100" 的错误,并且返回的groupVersionKind 实例显示__internal 的版本。不知道为什么会发生这种情况,或者当我改用 UniversalDeserializer() 时,为什么它不会发生

【讨论】:

    猜你喜欢
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多