GitHubActionsでkubernetesマニフェストのバリデーションチェック

## 背景
とある先日。
kubernetesマニフェストを用意してCIも通ったしマージ！あとはデプロイを待つだけ！と思って待っている時にデプロイパイプラインの中でマニフェストに不備があるよ的なエラーを吐いて止まっている...

マニフェストのバリデーションチェックをしていなかったので、デプロイするときになって初めてapplyできないマニフェストであることに気づくことがしばしば。時間返して...と悲しい気持ちになるので、PullRequestを作ったときに自動でそこまでチェックできるようにしたい。

## やりたいこと
- kustomizeを使っているので、kustomize buildの結果に対してバリデーションチェックをしたい
- 最近はGithubActionsを使うことが多いので、GitHubActionで実装したい

## バリデーションチェックツールは何を使うか
[kubeval](https://github.com/instrumenta/kubeval)は聞いたことがあったのですが、21/3以降あまり動きが見受けられず。

調べていると[kubeconform](https://github.com/yannh/kubeconform)というのがあり、こちらはスキーマも最新の1.23まで対応していそうだったのでkubeconformを使ってみることにしました。

## まずは手元で実験する
homebrewでインストール可能です。詳細は[README](https://github.com/yannh/kubeconform#installation)を参照ください。

実験に使うサンプルのマニフェストは以下のように準備しています。

```
$ tree
.
├── README.md
└── kubernetes
    ├── base
    │   ├── busybox-deployment.yml
    │   ├── kustomization.yml
    │   └── nginx-deployment.yml
    └── overlays
        └── test
            ├── busybox-deployment.yml
            ├── kustomization.yml
            └── nginx-deployment.yml
```

### Q.エラーになった時対象はわかるのか

kustomize buildを実行すると結果は以下のように１つのファイルで出力されます。

```
$ kustomize build kubernetes/overlays/test/
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: busybox
  name: busybox-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
      - env:
        - name: COLLOR
          value: YELLOW
        image: busybox:latest
        name: busybox
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - env:
        - name: COLLOR
          value: GREEN
        image: nginx:latest
        name: nginx
        ports:
        - containerPort: 80

```

そのため、不備があるのはどのマニフェストなのか？が判別できる情報がないと実行しても修正箇所を見つけるのが大変...となってしまいそうです。

意図的にspec.template.spec.containersのnameをいじってkubeconformを実行すると、`kind: Deployment`とDeploymentのname情報が出力されていました。

```
$ kustomize build kubernetes/overlays/test/ | kubeconform -summary
stdin - Deployment nginx-deployment is invalid: For field spec.template.spec.containers.0: name is required
Summary: 2 resources found parsing stdin - Valid: 1, Invalid: 1, Errors: 0, Skipped: 0

```

### Q.スペルミスでスキーマに存在しない記述があった場合に検知されるのか

spec.template.spec.containersで指定するimageをmageに変えてバリデーションを実行してみます。なお、この状態で生成されるマニフェストはkubectl applyしようとすると失敗する内容です。

```
$ kustomize build kubernetes/overlays/test/ | kubectl apply -f meerged-manifest.yml
deployment.apps/busybox-deployment unchanged
error: error validating "meerged-manifest.yml": error validating data: ValidationError(Deployment.spec.template.spec.containers[0]): unknown field "mage" in io.k8s.api.core.v1.Container; if you choose to ignore these errors, turn validation off with --validate=false
```

そのまま実行すると全てValidになっていました。

```
$ kustomize build kubernetes/overlays/test/ | kubeconform -summary
Summary: 2 resources found parsing stdin - Valid: 2, Invalid: 0, Errors: 0, Skipped: 0
```

よくよくkubeconform -hでhelpを見ると、`-strict`というオプションが。

```
-strict
        disallow additional properties not in schema
```

`-strict`オプションを付けて実行してみると無事Invalidになっていました。

```
$ kustomize build kubernetes/overlays/test/ | kubeconform -summary -strict
stdin - Deployment nginx-deployment is invalid: For field spec.template.spec.containers.0: Additional property mage is not allowed
Summary: 2 resources found parsing stdin - Valid: 1, Invalid: 1, Errors: 0, Skipped: 0
```

## Github Actionsにする

kustomize buildした結果に対してバリデーションを実行したいので、まずはkustomizeのアクションで結果の出力を指定します。

kustomizeのアクションはこちらを利用しています。
https://github.com/karancode/kustomize-github-action

```yaml
name: validate-kubernetes-manifest

on:
  pull_request:
    types: [opened, synchronize]
  push:
    branches:
      - "main"

jobs:
  cluster:
    name: Validate Kubernetes Manifest
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: 'Kustomize Build'
        uses: karancode/kustomize-github-action@master
        with:
          kustomize_build_dir: 'kubernetes/overlays/test'
          kustomize_comment: true
          kustomize_output_file: "merged-manifest.yml" #ここを指定
          kustomize_build_options: ""
          enable_alpha_plugins: false
        env:
          GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_ACCESS_TOKEN }}

```

ここに続けてkubeconformのステップを追加していきます。

```yaml
      - name: login to Github Packages
        run:  echo "${{ github.token }}" | docker login https://ghcr.io -u ${GITHUB_ACTOR} --password-stdin
      - uses: docker://ghcr.io/yannh/kubeconform:master
        with:
          entrypoint: '/kubeconform'
          args: "-summary -strict merged-manifest.yml"
```

実行されたアクションの結果を見ると、以下のようにちゃんと結果が出力されていました。

```
Summary: 2 resources found in 1 file - Valid: 2, Invalid: 0, Errors: 0, Skipped: 0
```


## 終わりに
まだ手探り状態なので、使いながら少しずつベストな形に改良していきたいと思います！

## おまけ
kubeconformとは別に[datree](https://www.datree.io/)というツールも気になっていたのですが、こちらはkindやnameといった情報が表示されず、エラー箇所がわかりませんでした。

```sh
$ datree test meerged-manifest.yml 
>>  File: /Users/akane.saigo/go/src/github.com/akanenone/practice-kubernetes/meerged-manifest.yml

[V] YAML validation
[X] Kubernetes schema validation

❌  k8s schema validation error: For field spec.template.spec.containers.0: Additional property mage is not allowed

[?] Policy check didn't run for this file

(Summary)
- Passing YAML validation: 1/1
- Passing Kubernetes (1.18.0) schema validation: 0/1
- Passing policy check: 0/1

+-------------------------------------+----------------------------------------------------------+
| Enabled rules in policy “Default” | 8                                                        |
| Configs tested against policy       | 0                                                        |
| Total rules evaluated               | 0                                                        |
| Total rules failed                  | 0                                                        |
| Total rules passed                  | 0                                                        |
| See all rules in policy             | https://datreeのURLリンク |
```

とはいえ、cpuやメモリがちゃんと設定されているかをチェックしたりとできることは多く有用そうではあるので、また時間がある時に再度試してみたいと思います。