Container Linux Config Transpiler を使うときには -strict オプションを付けておくと良さそう

[Container Linux Config Transpiler（ct）](https://github.com/coreos/container-linux-config-transpiler/) を利用する際の Tips となります。ct を利用して Ignition Config を生成したことがある方向けの記事なので、Ignition 自体の説明は割愛しています。

# TL;DR

- `-strict` オプションは Warning 発生時に ct をエラー終了させるオプション
- パラメータの typo で意図せぬ Ignition Config（空ファイルを置くだけなど）が生成されてしまうので、余計な Ignition Config の生成を避けたり、Ignition Config をバージョン管理せずにデプロイの度に動的生成する運用をされていたり、ct の wrapper script を利用していて Container Linux Config の間違いに終了ステータスベースで気付きたい方々は `-strict` オプションをつけると幸せになれそう
- [コピペですぐに使えるオプション付き ct テンプレート](#コピペですぐに使えるオプション付き-ct-テンプレート) も紹介しているので参考までにどうぞ

# `-strict` オプションの意味

### Warning 発生時に ct をエラー終了させるオプション

`Fail if any warnings are encountered.` の通りで、Container Linux Config から Ignition Config への変換時に Warning が発生したら、エラー終了させるオプションです。通常は Warning はあくまで Warning なので、他にエラーが発生しなければ正常終了する仕様となっています。

```bash
$ ct --version
ct v0.9.0

$ ct --help
Usage of ct:
  -files-dir string
        Directory to read local files from.
  -help
        Print help and exit.
  -in-file string
        Path to the container linux config. Standard input unless specified otherwise.
  -out-file string
        Path to the resulting Ignition config. Standard output unless specified otherwise.
  -platform string
        Platform to target. Accepted values: [azure digitalocean ec2 gce packet openstack-metadata vagrant-virtualbox cloudstack-configdrive custom].
  -pretty
        Indent the resulting Ignition config.
  -strict
        Fail if any warnings are encountered.
  -version
        Print the version and exit.
```

# ct 実行時にエラー終了となる例

いくつかピックアップして紹介します。

### 1. パラメータに渡す値の型が違う

```yaml:sample.yaml
storage:
  files:
    - path: [] # /opt/bin/kubectl などの string な値で必要がある
      filesystem: root
      mode: 0755
      contents:
        remote:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl
```

`path` に渡す値の型が異なるのでエラー終了となる。
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/config/types/files.go#L56

```bash
$ ct -in-file sample.yaml
error: yaml: unmarshal errors:
  line 3: cannot unmarshal !!seq into string
Failed to parse config

$ echo $?
1
```

### 2. パラメータに渡す値が有効なものでない

```yaml:sample.yaml
storage:
  files:
    - path: /opt/bin/kubectl
      filesystem: root
      mode: 12345 # 0755 などのパーミッションとして有効な数値を入れる必要がある
      contents:
        remote:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl
```

`mode` に渡す値がパーミッションとして有効な数値でないのでエラー終了となる。
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/vendor/github.com/coreos/ignition/config/v2_2/types/mode.go#L21-L26
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/vendor/github.com/coreos/ignition/config/shared/errors/errors.go#L57

```bash
$ ct -in-file sample.yaml
error at line 5, column 13
illegal file mode

$ echo $?
1
```

上記の条件でエラー終了することで、Container Linux に対して宣言した処理を実行するときに OS レベルで問題が起きるのを未然に防ぐことができるのは本当に良いですね。

# ct 実行時に Warning が出力される例

いくつかピックアップして紹介します。

### 1. パラメータの typo

```yaml:sample.yaml
storage:
  files:
    - path: /opt/bin/kubectl
      filesystem: root
      mode: 0755
      typo_contents: # contents を typo_contents と typo
        remote:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl
```

`contents` であるべきところを `typo_contents` と打ち間違えたので Warning が出力された。
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/vendor/github.com/coreos/ignition/config/validate/validate.go#L213

Container Linux Config としてが誤っていないので、Ignition Config への変換処理がなされて正常終了となるが、出力された Ignition Config を見てみると `/opt/bin/kubectl` に空ファイルを作成する中途半端なものになってしまっている。

```bash
$ ct -in-file sample.yaml
warning at line 6, column 7
Config has unrecognized key: typo_contents
{"ignition":{"config":{},"security":{"tls":{}},"timeouts":{},"version":"2.2.0"},"networkd":{},"passwd":{},"storage":{"files":[{"filesystem":"root","path":"/opt/bin/kubectl","contents":{"source":"data:,","verification":{}},"mode":493}]},"systemd":{}}

$ echo $?
0
```

### 2. ファイル作成時にパーミッションの指定忘れ

```yaml:sample.yaml
# mode でのパーミッション指定なし
storage:
  files:
    - path: /opt/bin/kubectl
      filesystem: root
      contents:
        remote:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl
```

パーミッションの指定がないのでデフォルト値 `0644` を使う旨の Warning が出力された。
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/config/types/files.go#L96-L101
https://github.com/coreos/container-linux-config-transpiler/blob/v0.9.0/config/types/files.go#L38

```bash
$ ct -in-file sample.yaml
warning at line 3, column 7
mode unspecified for file, defaulting to 0644
{"ignition":{"config":{},"security":{"tls":{}},"timeouts":{},"version":"2.2.0"},"networkd":{},"passwd":{},"storage":{"files":[{"filesystem":"root","path":"/opt/bin/kubectl","contents":{"source":"https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl","verification":{}},"mode":420}]},"systemd":{}}

$ echo $?
0
```

## `-strict` オプションを付与して Warning 発生時にエラー終了するか確認

```yaml:sample.yaml
storage:
  files:
    - path: /opt/bin/kubectl
      filesystem: root
      mode: 0755
      typo_contents: # contents を typo_contents と typo
        remote:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.13.2/bin/linux/amd64/kubectl
```

`-strict` オプションを付与することで、先程までは Warning が発生しても正常終了してたのが、エラー終了してくれるようになった。中途半端な Ignition Config の作成も実行されることはないので安心。

```bash
$ ct -strict -in-file sample.yaml
warning at line 6, column 7
Config has unrecognized key: typo_contents
Failed to parse config

$ echo $?
1
```

# コピペですぐに使えるオプション付き ct テンプレート

自分は、以下のディレクトリ構成とオプション付与で ct を実行しています。
ct で用意されているオプションは全て付与する形をとっているので、参考になればと思います。

```bash
# Container Linux Config を作成
$ tree .
.
├── cl-config
│   ├── files
│   │   └── yyy.config
│   └── xxx.yaml
└── ignition-config

# -platform は適用したいプラットホームによって要調整
# 以下は Vagrant を利用する際のサンプル
$ ct -pretty -strict \
    -platform vagrant-virtualbox \
    -files-dir cl-config/files \
    -in-file cl-config/xxx.yaml \
    -out-file ignition-config/xxx.json

# Ignition Config は動的生成
$ tree .
.
├── cl-config
│   ├── files
│   │   └── yyy.config
│   └── xxx.yaml
└── ignition-config
    └── xxx.json
```

# さいごに

公式ドキュメントにもあったとおり、Container Linux Config Transpiler（ct） は Container Linux で問題が起きないことが保証される Ignition Config を生成するということを再認識しました。

ただ、パラメータの typo で意図せぬ Ignition Config（空ファイルを置くだけなど）が生成されてしまうので、余計な Ignition Config の生成を避けたり、Ignition Config をバージョン管理せずにデプロイの度に動的生成する運用をされていたり、ct の wrapper script を利用していて Container Linux Config の間違いに終了ステータスベースで気付きたい方々は `-strict` オプションをつけると幸せになるかもしれません。