SIer だけど技術やりたいブログ

Kubernetes コンテナ名を y にすると実行できなくて困った(YAML の Boolean の話)

k8s

環境

Kubernetes 1.15

]# kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T11:13:54Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T11:05:50Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}

困りごと

こんな yaml を用意して

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
  - name: x
    image: nginx

  - name: y
    image: redis

apply するとエラーになる。

]# kubectl apply -f pod.yaml
Error from server (BadRequest): error when creating "pod.yaml": Pod in version "v1" cannot be handled as a Pod: v1.Pod.Spec: v1.PodSpec.Containers: []v1.Container: v1.Container.Name: ReadString: expects " or n, but found t, error found in #10 byte of ...|","name":true}]}}
|..., bigger context ...|age":"nginx","name":"x"},{"image":"redis","name":true}]}}
|...

なんで?

y(文字列のつもりで書いた) が true(真偽値) になっていた。

kubectl apply -f pod.yaml --v=8 を実行して送信したリクエストを抜き出すと、その様子がわかる。

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "annotations": {
      "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"sample-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx\",\"name\":\"x\"},{\"image\":\"redis\",\"name\":true}]}}\n"
    },
    "name": "sample-pod",
    "namespace": "default"
  },
  "spec": {
    "containers": [
      {
        "image": "nginx",
        "name": "x"
      },
      {
        "image": "redis",
        "name": true <- これ
      }
    ]
  }
}

YAML 1.1 の仕様だと Boolean は y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF が許可されている。そのため y(文字列のつもりで書いた) が true(真偽値) に評価された。
参考 Boolean Language-Independent Type for YAML™ Version 1.1

回避策

シングルクオートで囲って明示的に文字列だと示せばよい。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
  - name: 'x'
    image: nginx

  - name: 'y'
    image: redis
]# kubectl apply -f pod.yaml
pod/sample-pod created

YAML の Boolean ハマるんですけど

YAML 1.2 の仕様だと Boolean は true/false だけに修正されている。
参考 YAML Ain’t Markup Language (YAML™) Version 1.2

そのため Kubernetes でも YAML 1.2 に準拠してほしいところ。しかし、当分は YAML 1.1 とお付き合いする必要がありそう。(『 kubectl / kubernetes not 100% compatible with YAML 1.2』 という Issue が 2016 年からオープンのままになっている。対応されない理由は、後方互換性がなくなることや、Kubernetes が利用している YAML パーサ(go-yaml) が YAML 1.1 と 1.2 のサポートを謳っているため。go-yaml の v3 からはデフォルトを YAML 1.2 にするらしい。)

最後に go-yaml でのやり取りを紹介して締めの言葉とする。

引用元 Boolean support inconsistent with the YAML 1.2 spec · Issue #214 · go-yaml/yaml · GitHub

Welcome to YAML…