kubectl convertでyaml->json変換する

Kubernetesの操作をPowerShellで自動化する際、PowerShellが標準ライブラリでyamlフォーマットを現状扱えないため難儀する場面がある。提供されたyamlマニフェストにannotation追加したり、imageをちょっと変えたいといった場合だ。

jsonはPowerShell標準で扱えるんだけどな。。と思い出したが、kubectl -o jsonでjson出力できるんだからkubectlでどうにかならないのか、と思ったら有った。kubectlのプラグインという扱いであるがkubectl convertでローカルのyamlファイルをjsonに変換できる。

# kubectlとconvertプラグインをインストール

https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/#install-kubectl-convert-plugin

Windows 10のパワーシェルで以下を実行する。

```:PowerShellプロンプトで実行
> cmd /c curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/windows/amd64/kubectl.exe
> cmd /C curl -LO "https://dl.k8s.io/release/v1.22.0/bin/windows/amd64/kubectl-convert.exe"
> kubectl convert --help
(出力結果)
Convert config files between different API versions. Both YAML and JSON formats are accepted.
...
```

# Podのyamlをjson変換して、オブジェクトを操作してデプロイ

変換・オブジェクト操作前のpod.yamlは以下の通り。

```yaml:pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  containers:
  - name: httpd
    image: httpd
    ports:
    - name: http
      containerPort: 80
```

これを、「kubectl convert -o json」でjson変換すると以下のようになる。

```:PowerShellプロンプトで実行
> .\kubectl convert --local -o json -f pod.yaml
{
    "kind": "Pod",
    "apiVersion": "v1",
    "metadata": {
        "name": "httpd",
...
```


これに、PowerShellで以下の変更を加える。
・annotationsに「key1: value1」、「key2: value2」を追加する
・imageをhttpdからnginxに変更する
・portsに「hostPort: 80」を追加する

```PowerShell:PowerShellプロンプトで実行
> $pod = .\kubectl convert --local -o json -f pod.yaml | ConvertFrom-Json
> $pod.metadata | Add-Member -NotePropertyName annotations @{}
> $pod.metadata.annotations.add("key1","value1")
> $pod.metadata.annotations.add("key2","value2")
> $pod.spec.containers[0].image = "nginx"
> $pod.spec.containers[0].ports[0] | Add-Member -NotePropertyName "hostPort" 80
```

ちな、PowerShell V7からConvertFrom-JSONに-AsHashTableというパラメータが追加され、「| Add-Member ～」のところがもうちょっと簡単になる。

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json?view=powershell-7#example-4--convert-a-json-string-to-a-hash-table

Windows 10のPowerShellは、標準だと残念ながらバージョン5.1。

```PowerShell:PowerShellプロンプトで実行
> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.19041.1237
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.1237
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
```

閑話休題。
修正したPowerShellオブジェクトをJSONに変換してKubernetesクラスターにデプロイする。
-Depthを忘れると、データが途中でJSONじゃない何かになってエラーとなる。
sshコマンド経由でクラスタのkubectlに渡しても良い。

```PowerShell:PowerShellプロンプトで実行
> $pod | ConvertTo-Json -Depth 100 | ssh -i .\mykey.pem ubuntu@192.168.0.15 -- "kubectl apply -f -"
pod/httpd created
```

クラスターにデプロイされたPodは以下のようになる。

```:PowerShellプロンプトで実行
> ssh -i .\mykey.pem ubuntu@192.168.0.15 -- "kubectl get pod httpd -o yaml"
apiVersion: v1
kind: Pod
metadata:
  annotations:
    cni.projectcalico.org/containerID: f3d79004466d4932db6f17aca11e078536b7722ea12464b93a9ae8e652a354a3
    cni.projectcalico.org/podIP: 172.16.205.73/32
    cni.projectcalico.org/podIPs: 172.16.205.73/32
    key1: value1
    key2: value2
...
  creationTimestamp: "2021-11-04T12:57:21Z"
  labels:
    app: httpd
  name: httpd
  namespace: default
  resourceVersion: "17486"
  uid: c5c4b7ff-1ccb-44e9-9100-1cd4b1a953f3
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: httpd
    ports:
    - containerPort: 80
      hostPort: 80
      name: http
      protocol: TCP
...
```

curlにも応答する。

```:PowerShellプロンプトで実行
> cmd /c curl http://192.168.0.15
<!DOCTYPE html>
...
<title>Welcome to nginx!</title>
...
```