如何反序列化 Kubernetes YAML 文件

huangapple go评论119阅读模式
英文:

How to deserialize Kubernetes YAML file

问题

你可以使用client-go库中的yaml包来将Kubernetes的YAML文件反序列化为Go结构体。以下是一个示例代码:

package main

import (
	"fmt"

	"k8s.io/apimachinery/pkg/util/yaml"
)

type Deployment struct {
	APIVersion string `yaml:"apiVersion"`
	Kind       string `yaml:"kind"`
	Metadata   struct {
		Name string `yaml:"name"`
	} `yaml:"metadata"`
	Spec struct {
		Replicas int `yaml:"replicas"`
		Template struct {
			Metadata struct {
				Labels struct {
					Run string `yaml:"run"`
				} `yaml:"labels"`
			} `yaml:"metadata"`
			Spec struct {
				Containers []struct {
					Name  string `yaml:"name"`
					Image string `yaml:"image"`
					Ports []struct {
						ContainerPort int `yaml:"containerPort"`
					} `yaml:"ports"`
				} `yaml:"containers"`
			} `yaml:"spec"`
		} `yaml:"template"`
	} `yaml:"spec"`
}

func main() {
	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
`

	var deployment Deployment
	err := yaml.Unmarshal([]byte(service), &deployment)
	if err != nil {
		panic(err)
	}

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

这个示例代码定义了一个与你提供的YAML文件结构相匹配的Go结构体Deployment。你可以使用yaml.Unmarshal函数将YAML文件反序列化为该结构体。

请注意,你需要在代码中导入k8s.io/apimachinery/pkg/util/yaml包来使用yaml.Unmarshal函数。

希望这可以帮助到你!

英文:

How can I deserialize a Kubernetes YAML file into an Go struct? I took a look into the kubectl code, but somehow I get an error for every YAML file:

no kind "Deployment" is registered for version "apps/v1beta1"

This is an 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)
}

I am using client version 2.0.0. The glide.yaml looks like this:

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

These are the references to kubectl:

Unfortunately, the docs are very confusing to me, so I have no idea how to tackle this problem.

Edit:

This problem also exists with other resource types:

  • no kind "Service" is registered for version "v1"

答案1

得分: 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中的对象,例如pods或services。

编辑:感谢我的同事Stefan Schimanski提出了最初的解决方案。

英文:

You need to import _ "k8s.io/client-go/pkg/apis/extensions/install" otherwise the schema is empty, see also docs.

The complete working example is:

$ go get -u github.com/golang/dep/cmd/dep
$ dep init
$ go run main.go

With the following 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)
}

Note that I also imported _ "k8s.io/client-go/pkg/api/install" for you so that you can use objects in v1 such as pods or services.

EDIT: Kudos to my colleague Stefan Schimanski who proposed the initial solution.

答案2

得分: 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)
英文:

I've been using api machinery'sk8s.io/apimachinery/pkg/util/yaml to decode kubernete's deployment and service manifests.

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)

答案3

得分: 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) {
	// 创建一个YAML序列化器。JSON是YAML的子集,所以也支持。
	s := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme,
		scheme.Scheme)

	// 将YAML解码为对象。
	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)
----

<details>
<summary>英文:</summary>

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, &amp;app)
if err != nil {
	panic(err)
}
//fmt.Printf(&quot;%#v\n&quot;, 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)




</details>



huangapple
  • 本文由 发表于 2017年6月1日 19:41:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/44306554.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定