GoのKubernetesオブジェクトをYAMLからDeserializeする

Go で Kubernetes まわりのツールを作るときに YAML を読んで Kubernetes オブジェクトにしたいということがあったので調べました。

コードは Gist にアップしました。 https://gist.github.com/nownabe/4345d9b68f323ba30905c9dfe3460006

Kubernetes のオブジェクトというのは Kubernetes のソースで定義されている struct のことです。こんなやつ。

// A namespace provides a scope for Names.
// Use of multiple namespaces is optional
type Namespace struct {
	metav1.TypeMeta
	// +optional
	metav1.ObjectMeta

	// Spec defines the behavior of the Namespace.
	// +optional
	Spec NamespaceSpec

	// Status describes the current status of a Namespace
	// +optional
	Status NamespaceStatus
}

https://godoc.org/k8s.io/api/core/v1#Namespace

YAML はこんなやつですね。

apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace

この YAML を上の Namespace struct によろしく Deserialize する方法です。

まずは Deserializer を手に入れます。

import (
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/serializer"
)

func main() {
    // SerializeとDeserializeの方法を定義するやつ
    // https://godoc.org/k8s.io/apimachinery/pkg/runtime#Scheme
    scheme := runtime.NewScheme()

    // Deserializerとかをくれるやつ
    // https://godoc.org/k8s.io/apimachinery/pkg/runtime/serializer#CodecFactory
    codecFactory := serializer.NewCodecFactory(scheme)

    // Deserializer
    // https://godoc.org/k8s.io/apimachinery/pkg/runtime#Decoder
    deserializer := codecFactory.UniversalDeserializer()
}

UniversalDeserializer() は JSON とか YAML とかを 自動で認識 して Deserialize してくれるやつをくれます。これを使っておけば問題ないと思いますが、それぞれのシリアライズ形式専用の Deserializer も簡単に手に入ります。1

いずれにしても runtime.Decoder という interface のインスタンスが得られます。

type Decoder interface {
    Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error)
}

https://godoc.org/k8s.io/apimachinery/pkg/runtime#Decoder

Decode メソッドで Deserialize するわけですが、それぞれの引数はこんな感じになってます。

  • data []byte: Deserialize したいデータ。YAML とか
  • defaults *schema.GroupVersionKind: nil でよい。よくわからないときに使われるデフォルト値。Group、Version、Kind それぞれの文字列が入る 構造体
  • into Object: Deserialize したい オブジェクト。Namespace とかの struct のポインタがこの interface を実装している。

例えば Namespace の YAML を Namespace struct に Deserialize するのはこんな感じになります。

package main

import (
        "fmt"
        "io/ioutil"

        corev1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/apimachinery/pkg/runtime/serializer"
)

func main() {
        scheme := runtime.NewScheme()
        codecFactory := serializer.NewCodecFactory(scheme)
        deserializer := codecFactory.UniversalDeserializer()

        yaml, err := ioutil.ReadFile("namespace.yaml")
        if err != nil {
                panic(err)
        }

        object, _, err := deserializer.Decode(yaml, nil, &corev1.Namespace{})
        if err != nil {
                panic(err)
        }
        namespace := object.(*corev1.Namespace)
        fmt.Printf("Name: %s\n", namespace.ObjectMeta.GetName())
}

他のオブジェクトも同様にできます。Gistのコード には Deployment のサンプルもあります。

オブジェクトについては k8s.io/apiのgodoc にあります。

Footnotes

  1. この辺 とか この辺 とか ↩