TECHSTEP

ITインフラ関連の記事を公開してます。

【メモ】KYAMLについて調べてみる

今回はKYAMLというKubernetes向けYAMLのサブセットについて少し調べてみました。

きっかけ

先日Kubernetes v1.34に関するページが公開されました。ここ最近のリリース情報を追いかけられてなかったので久しぶりに見ていたところ、 KYAML という見慣れない単語を見かけました。気になって調べてみたのが今回の記事の経緯です。

kubernetes.io

KYAMLとは

KYAMLとは、Kubernetes向けのYAMLとして、KubernetesのリソースをYAML形式のファイルで管理する際の課題を軽減することが目的で作られた形式です。

※KYAMLがいつ頃に登場したかはわかりませんが、Kustomizeの2019年のPRでKYAMLに関するものがあるのは確認しました。

github.com

KYAMLでは以下のような仕様が設定されています。これらは従来の定義ファイル形式の課題を軽減するためのものです。

  • マッピング(キーと値のペア)には常に {} を使用する。
  • リスト(配列)には常に [] を使用する。
  • 文字列の値は常にダブルクォート "" で囲む。
  • キーは、曖昧になる可能性がない限りクォートしない。
  • コメント (#) を使用できる。
  • 末尾のカンマを許容する。

KubernetesのリソースをIaCで管理する場合、おそらく現在はYAMLまたはJSON形式のファイルが最もよく使われているかと思います。しかしYAML/JSONを使うことで、いくつかの課題があります。

YAMLの課題1: 意図しない型変換

ここでは The Norway Problem という問題を少し紹介します。これは、世界各国の国名を国名コードで順に記載すると、YAMLノルウェーを表す NO という文字列を False と変換する問題です。

# YAMLファイルでこういった定義をすると
countries:
- GB
- IE
- FR
- DE
- NO

# NOがfalseと解釈されます。
>>> from pyyaml import load
>>> load(the_configuration)
{'countries': ['GB', 'IE', 'FR', 'DE', False]}

hitchdev.com

このような意図しない型変換を避けるため、KYAMLでは文字列の値を常に ”” で囲むというルールを設けています。

YAMLの課題2: インデントが複雑になる

これはリソースの定義ファイルが巨大になるほど顕在化する問題です。例えばArgoCDをインストールする時に使う定義ファイルの一つを見てみると、本記事執筆時点で352行の分量があります。

github.com

ArgoCDに限らず、現状多くのOSSYAML形式でマニフェストファイルを提供しています。YAMLはインデントの位置でデータ構造が決まるため、インデントがずれていると正常に解釈されなくなります。これは行数が増えるほど気づくのが困難になります。

KYAMLではリストには [] 、マップには {} を常に使います。この括弧内ではインデントがずれていてもデータ構造を正しく解釈するため、インデントが複雑になるという課題を部分的に軽減してくれます。

JSONの課題1: コメントアウトできない

YAMLJSONを比較すると、コメントアウトの可否は大きな違いの一つです。コメントアウトが使えることで、コードからでは読み取るのが難しい設定の意図なども記載でき、可読性やメンテナンス性の向上に貢献します。

JSONコメントアウトをサポートしておらず、利用するにはYAMLなど別の形式に移行するかJSONC (JSON with Comments) などの拡張形式を使う必要があります。多くのOSSの定義ファイルでYAMLが使われているのは、JSONコメントアウトをサポートしていないことも一つの要因ではないかと考えています。

KYAMLではコメントアウトを有効にすることで、JSONの持つ課題を解消します。

JSONの課題2: 末尾カンマが許容されない

JSONでは末尾のカンマも許容されていません。この仕様があると、例えばあるオプションの定義を追加しようとしたとき、以下のような作業が必要となります。これは手動作業時のタイプミスの原因にもなりますし、自動化プログラムでファイルを扱うときのロジックも複雑になります。

またJSONファイルをGitでバージョン管理する場合も、本来差分として確認したい「設定項目の追加」だけでなく、「既存項目の末尾へのカンマ追加」という不要な差分が表示されるため、レビュアーにとってはノイズになります。

KYAMLでは末尾のカンマを許容することで、こういった課題を解消します。

KYAML形式のファイルでPodを起動する

最後に、実際にKYAML形式の定義ファイルを使ってNginx Podを起動します。クラスターは何でもよいですが、今回はAmazon EKS (Auto Mode) ver 1.33を使用しました。

[cloudshell-user@ip-10-135-0-67 ~]$ kubectl get all -A
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   pod/metrics-server-6545cd44cd-ns9tj   0/1     Pending   0          16s
kube-system   pod/metrics-server-6545cd44cd-zzzps   0/1     Pending   0          16s

NAMESPACE     NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
default       service/kubernetes                  ClusterIP   10.100.0.1      <none>        443/TCP   8m42s
kube-system   service/eks-extension-metrics-api   ClusterIP   10.100.212.22   <none>        443/TCP   8m40s
kube-system   service/metrics-server              ClusterIP   10.100.254.51   <none>        443/TCP   17s

NAMESPACE     NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/metrics-server   0/2     2            0           17s

NAMESPACE     NAME                                        DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/metrics-server-6545cd44cd   2         2         0       17s
[cloudshell-user@ip-10-135-0-67 ~]$ 

クラスターを作成後に以下のような定義ファイルを用意し、kubectl経由でデプロイします。

[cloudshell-user@ip-10-135-0-67 ~]$ cat nginx.kyaml 
{
  apiVersion: "v1",
  kind: "Pod",
  metadata: {
    name: "nginx-kyaml-example",
    labels: {
      app: "nginx",
    },
  },
  spec: {
    containers: [
      {
        name: "nginx",
        image: "nginx:stable",
        ports: [
          {
            containerPort: 80,
          },
        ],
      },
    ],
  },
}

[cloudshell-user@ip-10-135-0-67 ~]$ kubectl apply -f nginx.kyaml 
pod/nginx-kyaml-example created

問題なくPodが起動することを確認できます。

[cloudshell-user@ip-10-135-0-67 ~]$ kubectl get pods -A
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
default       nginx-kyaml-example               1/1     Running   0          54s
kube-system   metrics-server-6545cd44cd-ns9tj   1/1     Running   0          3m3s
kube-system   metrics-server-6545cd44cd-zzzps   1/1     Running   0          3m3s
[cloudshell-user@ip-10-135-0-67 ~]$ 

なおkubectlはver 1.33時点ではkyaml形式の出力をサポートしておらず、ver 1.34でこの機能が追加される予定とのことです。

[cloudshell-user@ip-10-135-0-67 ~]$ kubectl get pods nginx-kyaml-example -okyaml
error: unable to match a printer suitable for the output format "kyaml", allowed formats are: custom-columns,custom-columns-file,go-template,go-template-file,json,jsonpath,jsonpath-as-json,jsonpath-file,name,template,templatefile,wide,yaml

参考リスト