Helmチャートで無効なパラメータをチェックする

はじめに
------------

Helmチャートは便利ですが、次のような経験はありませんか？

- 文字列を指定すべきパラメータが数値になっていて、デプロイに失敗する
- 必須パラメータを指定していなくて、デプロイに失敗する
- パラメータ名を間違えてデプロイして、設定が変わっていないと首をかしげる

Helm v3では、実はチャート側に、指定するパラメータの[スキーマを配置](https://helm.sh/docs/topics/charts/#schema-files
)できます。
スキーマでは必須パラメータを定義したり、パラメータのタイプを指定したり、定義外のパラメータを受け付けなくしたりできます。
（なので、もちろん管理しているチャート、自製のチャートでしか使えない手法ではありますが、）
スキーマに違反していると `helm install` や `helm template` コマンドなどがエラーとなるため、デプロイ前に気づくことができます！
本記事ではスキーマの書き方の一部を紹介します。

必須パラメータの定義
-------------

次のように `required` を設定しておくと、`name` `version` パラメータが指定されていないとエラーになります。

```json:values.schema.json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "name": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "replicas": {
      "type": "number"
    }
  },
  "required": [
    "name",
    "version"
  ],
  "title": "Values",
  "type": "object"
}
```

`name` や `version` パラメータが指定されていないと、`helm template` の実行時にエラーが以下のように出力されます。

```text
$ helm template ./my-charts/required-parameter > /dev/null
Error: values don't meet the specifications of the schema(s) in the following chart(s):
my-chart-name:
- (root): name is required
- (root): version is required
```

`name` と `version` パラメータをちゃんと指定すると、`helm template` の実行時にエラーは出力されなくなります。

```text
$ helm template ./my-charts/required-parameter --set=name=name --set=version=version > /dev/null

```

パラメータのタイプの定義
-------------

次のように `type` などのプロパティを設定しておくと、`name` 文字列が32文字を超えていたり、`hostname` 文字列が正規表現(DNSホスト名のつもり)にマッチしなかったり、 `terminationGracePeriodSeconds` パラメータが数値でなかったり、`replicas` の数値が0から10の間になかったりするとエラーになります。

```json:values.schema.json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "name": {
      "type": "string",
      "maxLength": 32
    },
    "hostname": {
      "type": "string",
      "pattern": "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$"
    },
    "terminationGracePeriodSeconds": {
      "type": "number"
    },
    "replicas": {
      "type": "number",
      "minimum": 0,
      "maximum": 10
    }
  },
  "title": "Values",
  "type": "object"
}
```

※DNSレコード名の正規表現は [regex - Regular expression to match DNS hostname or IP Address?](https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address) を参考にしました。

パラメータが条件を満たしていないと、`helm template` の実行時にエラーが以下のように出力されます。

```text
$ helm template ./my-charts/type --set=name=abcdefghijklmnopqrstuvwxyz0123456789 --set=hostname=-1-test --set='terminationGracePeriodSeconds="30"' --set=replicas=11 > /dev/null
Error: values don't meet the specifications of the schema(s) in the following chart(s):
my-chart-name:
- name: String length must be less than or equal to 32
- hostname: Does not match pattern '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
- terminationGracePeriodSeconds: Invalid type. Expected: number, given: string
- replicas: Must be less than or equal to 10/1
```

パラメータが条件を満たしていると、`helm template` の実行時にエラーは出力されなくなります。

```text
$ helm template ./my-charts/type --set=name=abcdefghijklmnopqrstuvwxyz --se
t=hostname=1-test --set=terminationGracePeriodSeconds=30 --set=replicas=10 > /dev/null

```

他にもいろいろな定義の仕方があるので、公式のドキュメント [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) を参照するとよさそうです。

定義外パラメータを受け付けない定義
-----------------

次のように `additionalProperties: false` を設定しておくと、`name` `version` **以外** のパラメータが余分に指定されているとエラーになります。

```json:values.schema.json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "name": {
      "type": "string"
    },
    "version": {
      "type": "string"
    }
  },
  "title": "Values",
  "type": "object",
  "additionalProperties": false
}
```

typoに気づけるようになるのが、大きな利点だと思います。

`name` や `version` 以外のパラメータが余分に指定されていると、`helm template` の実行時にエラーが以下のように出力されます。

```text
$ helm template ./my-charts/additional-properties --set=namae=test --version=v1.0.0 > /dev/null
Error: values don't meet the specifications of the schema(s) in the following chart(s):
my-chart-name:
- (root): Additional property namae is not allowed
```

※非常にわかりにくいですが、 `name` を `namae` にtypoしています。

（今回の場合typoを直して）`name` や `version` 以外の余分なパラメータがなくなると、`helm template` の実行時にエラーは出力されなくなります。

```text
$ helm template ./my-charts/additional-properties --set=name=test --version=v1.0.0 > /dev/null

```

おわりに
--------------

本記事ではHelmチャートのスキーマを定義して、無効なパラメータをチェックする方法を紹介しました。
Helmチャートを書くときは、CIなどでパラメータの誤りに気付くことができるように、スキーマを定義しておくとよさそうです！