如何反序列化 Kubernetes YAML 文件

9
我该如何将Kubernetes YAML文件反序列化成Go结构体?我查看了kubectl的代码,但是每个YAML文件都会出现错误。
no kind "Deployment" is registered for version "apps/v1beta1"

这是一个 MWE 示例:
package main

import (
    "fmt"

    "k8s.io/client-go/pkg/api"
)

var service = `
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
`

func main() {
    decode := api.Codecs.UniversalDecoder().Decode
    //decode := api.Codecs.UniversalDeserializer().Decode

    obj, _, err := decode([]byte(service), nil, nil)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%#v\n", obj)
}

我正在使用客户端版本2.0.0glide.yaml看起来像这样:

package: test/stackoverflow
import:
- package: k8s.io/client-go
  version: ^2.0.0

以下是关于kubectl的参考资料: 很遗憾,对我来说文档非常混乱,所以我不知道如何解决这个问题。 编辑: 其他资源类型也存在此问题:
  • no kind "Service" is registered for version "v1"

想要尝试使用Go dep吗?https://hackernoon.com/using-go-dep-as-a-project-maintainer-641d1f3006d7 - Michael Hausenblas
这与依赖管理无关。 - svenwltr
是的,我知道(因此我在下面回答了),但是我试图鼓励人们转向更具未来性的替代方案 ;) - Michael Hausenblas
3个回答

5
您需要导入_“k8s.io/client-go/pkg/apis/extensions/install”,否则模式为空,另请参阅文档
完整的工作示例如下:
$ go get -u github.com/golang/dep/cmd/dep
$ dep init
$ go run main.go

以下是 main.go 的代码:

package main

import (
    "fmt"

    "k8s.io/client-go/pkg/api"
    _ "k8s.io/client-go/pkg/api/install"
    _ "k8s.io/client-go/pkg/apis/extensions/install"
)

var deployment = `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 2
template:
  metadata:
    labels:
      run: my-nginx
  spec:
    containers:
    - name: my-nginx
      image: nginx
      ports:
      - containerPort: 80
`

func main() {
    // decode := api.Codecs.UniversalDecoder().Decode
    decode := api.Codecs.UniversalDeserializer().Decode

    obj, _, err := decode([]byte(deployment), nil, nil)
    if err != nil {
        fmt.Printf("%#v", err)
    }

    fmt.Printf("%#v\n", obj)
}

请注意,我还为您导入了_ "k8s.io/client-go/pkg/api/install",以便您可以使用v1中的对象,例如pod或service。
编辑:感谢我的同事Stefan Schimanski提出了最初的解决方案。

嗨@MichaelHausenblas,我正在尝试使这个工作(解析k8s yaml以使用Go结构),但无法使用dep(或vndr)使其工作。复制您完全相同的示例并运行“dep init”会得到以下结果:未满足k8s.io/apimachinery的任何版本约束条件:master:无法更新已检出的版本::命令失败:[git checkout 1168e538ea3ccf444854d1fdd5681d2d876680a7]:退出状态128(下一个评论) - Alberto Megía
release-1.6: 无法更新已检出的版本:命令失败:[git checkout 35be0db31bd6e5635ef6366708dc2b137392f6a2]:退出状态128 release-1.7: 无法更新已检出的版本:命令失败:[git checkout 8ab5f3d8a330c2e9baaf84e39042db8d49034ae2]:退出状态128 - Alberto Megía
好的,我已经成功修复了它,导入了"k8s.io/client-go/pkg/api"、"k8s.io/client-go/pkg/api/install"、"k8s.io/client-go/pkg/apis/apps/install"和"k8s.io/client-go/pkg/apis/extensions/install"。但是如果我运行它,会得到一堆 # github.com/amegianeg/example/vendor/k8s.io/client-go/pkg/api 的错误信息,其中vendor/k8s.io/client-go/pkg/api/types.generated.go:633:在调用r.DecodeBytes时参数太多,有([]byte, bool, bool),需要([]byte, bool)。 - Alberto Megía
1
@MichaelHausenblas看起来上面的示例已经过时了,因为 import _ "k8s.io/client-go/pkg/api/install" 不再起作用。同时点击文档会显示“未找到”。请您更新一下。 - Abhishek Kashyap
9
接受的答案已过时 - 不再有k8s.io/client-go/api/install包。 请参见GitHub讨论以获取修正版本:https://github.com/kubernetes/client-go/issues/193#issuecomment-377140518 - yname
显示剩余3条评论

1

我一直在使用api machinery的k8s.io/apimachinery/pkg/util/yaml来解码Kubernetes的部署和服务清单。

import (
   "fmt"
   "bytes"
   appsv1 "k8s.io/api/apps/v1"
    k8Yaml "k8s.io/apimachinery/pkg/util/yaml"
)
...

d := &appsv1.Deployment{}
dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(deploymentManifest)), 1000)

if err := dec.Decode(&d); err != nil {
        return nil, err
}

fmt.Printf("%+v", d)

如何获取特定 Pod 的 deployment.yaml/service.yaml 文件? - Harmeet Kaur
如果您拥有pod对象,可以检查ownerReferences以获取拥有该pod的replicaSet。在replicaset对象中,检查ownerReferences的值以获取deployment。 - Ramiro Berrelleza
服务比较棘手,你可以使用 Pod 上的标签在服务中查找匹配项,但效率不是很高。 - Ramiro Berrelleza

0
import (
    "fmt"
    "gopkg.in/yaml.v2"
    "log"
    //corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/runtime/serializer/json"
    "k8s.io/client-go/kubernetes/scheme"
    v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
)

....

func ParseYaml2(yaml []byte) (v1alpha1.Application, error) {
    // Create a YAML serializer.  JSON is a subset of YAML, so is supported too.
    s := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme,
        scheme.Scheme)

    // Decode the YAML to an object.
    var app v1alpha1.Application
    _, _, err := s.Decode(yaml, nil, &app)
    if err != nil {
        panic(err)
    }
    //fmt.Printf("%#v\n", app)
    return app, err
}
---
go.mod
// https://github.com/argoproj/argo-cd/issues/4055
replace github.com/argoproj/argo-cd => github.com/argoproj/argo-cd v1.5.5

var yaml2 = []byte(`
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
...

var app v1alpha1.Application
app,err := ParseYaml2(yaml2)
// Types from https://github.com/argoproj/argo-cd/blob/master/pkg/apis/application/v1alpha1/types.go
    fmt.Printf("--- t:\n%s\n\n", app.Spec.Source.Path)
    fmt.Printf("--- t:\n%s\n\n", app.Spec.Source.Helm.ValueFiles)
----

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接