なになれ

IT系のことを記録していきます

Kubernetes Nativeなプログラムを作る際に知っておくべきこと

kubectl pluginという形でKubernetes Nativeなプログラムを作りました。

github.com

その際に前提知識としてKubernetes APIの理解が必要だと感じました。
本投稿では、Kubernetes Nativeなプログラムを作る際に知っておくべき知識を紹介します。
なお、Goおよびclient-goを利用する前提での内容になります。

Kubernetes APIについて

Kubernetes APIには、KindなどAPIに関連するいくつかの要素があります。
プログラムを書く際には、これらを理解する必要があると思います。

Kind

Pod,DeploymentといったKubernetes Resourceの種類を表します。
GoにおけるKubernetesのクライアントライブラリであるclient-goでは、このKind毎に型が用意されています。

例えば、Podの型は以下のように定義されています。

type Pod struct {
    metav1.TypeMeta `json:",inline"`
    // Standard object's metadata.
    // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    // +optional
    metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

    // Specification of the desired behavior of the pod.
    // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
    // +optional
    Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

    // Most recently observed status of the pod.
    // This data may not be up to date.
    // Populated by the system.
    // Read-only.
    // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
    // +optional
    Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

これはKubernetesマニフェストの構造と一致します。

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: example
spec:
  containers:
  - name: nginx
    image: nginx:latest
status:
  phase: Running

Group

Kubernetes Resourceをグループ分けする要素になります。
apps,batchといったGroup名があります。

Version

APIのバージョンを表します。
開発が進む毎にv1alpha,v1beta,v1という段階があります。

Resource

Kubernetes API Serverのエンドポイントを構成する1要素になります。
例えば、以下のようにDeploymentリソースのエンドポイントがあります。

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

deploymentsに当たる部分がResourceになります。

GroupVersionKind(GVK)

Group,Version,Kindを用いて、Kubernetes Resourceを特定します。

GroupVersionResource(GVR)

Group,Version,Resourceを用いて、Kubernetes Resourceを特定します。
Kubernetes API ServerのREST形式エンドポイントと対応しています。

REST Mapping

GVKからGVRに変換する仕組みです。

利用方法は以下のとおりです。
ここでは、GVK形式のDeploymentリソースをGVRに変換しています。

...
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
dc, err := discovery.NewDiscoveryClientForConfig(config)
mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc))
mapping, err := mapper.RESTMapping(schema.GroupKind{
  Group: "apps",
  Kind:  "Deployment",
}, "v1")
...

mapping.ResourceがGVRの値になります。
discoveryを使い、どのようなResourceが定義されているかをKubernetes API Serverに問い合わせた上でREST形式にマッピングするようです。
そのため、このような手順を踏みます。

Scheme

Go上でGroup,Version,Kind,Resourceといった値を扱うためのPackageです。
k8s.io/apimachinery/pkg/runtime/schemaで定義されています。

Typed Client

Kindの項で説明したとおり、Kubernetes Resource用の型が定義されています。
その型に従ってResourceを扱うclientです。

例えば、Deploymentリソースを扱う場合、以下のような記述になります。

...
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
clientset, err := kubernetes.NewForConfig(config)
deploymentsClient := clientset.AppsV1().Deployments(apiv1.NamespaceDefault)
deploymentsClient.List(context.TODO(), metav1.ListOptions{})
...

Get,Listといったデータを取得するメソッドを使うと、Deployment型のデータを取得可能です。
Deployment型のデータを用意して、Create,Update,Deleteといったデータを変更するメソッドを利用します。

Dynamic Client

特定の型によらずに動的にKubernetes Resourceを扱うclientです。
このclientでは、unstructured.Unstructured型を扱います。この型の実態はmap[string]interface{}型でどのような値でも受け入れる形になっています。

例えば、Deploymentリソースを扱う場合、以下のような記述になります。

...
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
client, err := dynamic.NewForConfig(config)
deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
client.Resource(deploymentRes).Namespace(namespace).List(context.TODO(), metav1.ListOptions{})
...

Dynamic Clientで取得した値はunstructured.Unstructured型になるので汎用的に扱うことができます。

まとめ

Kubernetes APIを扱う上での前提知識といった内容を紹介しました。
Kubernetesを単純に利用しているだけだと、KubernetesにはAPIがあるというくらいの理解しかできていなかったです。
Kubernetes Nativeなプログラムを作ることでより深くKubernetesを理解できました。
これらの知識はCustom Resourceを作る際に役立つ内容だと思います。

参考