Salt で Kubernetes をもっと自動化しよう

@sadakunihiro と申します。初めての投稿になります。よろしくお願いします。

# Salt ってなに?

オープンソースで自動化ツールと言えば Ansible, Terraform, Chef あたりが有名だと思います。それらに比べると若干マイナー感は否めないですが Salt というオープンソースもあります。この記事ではあえてこのオープンソースに焦点を当ててその良さをなんとか伝えたいと思います。Salt は https://saltproject.io/ にてメンテされているオープンソースになります。

# なぜ Kubernetes に Salt なのか?

Saltではあるべき状態を定義するファイルとして State ファイルをYAML形式で記述します。Ansible での playbook に相当します。K8Sで多くのYAMLファイルを扱っているのに Salt で更にYAMLファイルを増やす必要があるのか、K8S自体自動化の要素があるのにさらにSaltで自動化する必要があるのか、と疑問に思うかも知れません。あえてSaltでK8Sを扱う利点は以下になるかと思います。

- 複数K8Sクラスタを選択的に一括で扱える
- K8Sだけでなく他のシステムも含めてオーケストレーションできる

# とりあえず Salt を触ってみよう

とりあえず触ってみましょう。Salt は通常 master と minion という2つのモジュールをそれぞれ別のOSへインストールします。master は1つのOSに、そして minion は1つ以上の操作対象システムにインストールします。(VyOS など minion がOSの一部として最初からインストールされているものもあります)

インストールは bootstrap (https://repo.saltproject.io/#bootstrap) を使うと楽だと思います。今回は1台の Ubuntu 20.04 に master と minion インストールしたいと思います。以下のコマンドを実行します。

```shell:
$ curl -fsSL https://bootstrap.saltproject.io -o install_salt.sh
$ sudo sh install_salt.sh -P -M -x python3
    (出力省略)
*  INFO: Salt installed!
```

最後に「INFO: Salt installed!」という出力があれば成功です。つぎに設定ファイル /etc/salt/minion.d/master.conf を作成し以下の行を入力します。この変更で minion は localhost が master だと認識します。(minion 側の設定になります)

```/etc/salt/minion.d/master.conf
master: localhost
```
上記設定を反映させるために、以下コマンドで minion を再起動します。

```shell:
$ sudo systemctl restart salt-minion
```

ここからは master としての操作を行ないます。master と minion は鍵を使って暗号通信しています。その為まずは minion の鍵をアクセプトする必要があります。以下コマンドでまだアクセプトしていない minion の鍵があるか確認します。

```shell:
$ sudo salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
ubuntu.example.com
Rejected Keys:
```
ubuntu.example.com がまだアクセプトしていない minion の鍵だとわかります。`salt-key -A` コマンドで鍵をアクセプトします。

```shell:
$ sudo salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
ubuntu.example.com
Proceed? [n/Y] y
Key for minion ubuntu.example.com accepted.

$ sudo salt-key -L
Accepted Keys:
ubuntu.example.com
Denied Keys:
Unaccepted Keys:
Rejected Keys:
```

無事に鍵をアクセプトできました。以上で準備は完了です。お疲れさまでした。では動作確認しましょう。

```shell
# salt '*' test.ping
ubuntu.example.com:
    True
```
ちゃんと動いてますね。上記コマンドがどういう命令なのかちょっと説明します。

`salt` コマンドの最初の引数は対象となる minion を指定しています。`'*'` は全ての minion という意味になります。`'abc*'` と記述すると abc から始まる名前の minion が対象となります。また、grains という属性データを使って対象 minion を種類で指定することも可能です。 `-G 'os:Ubuntu'` と指定すると OS が Ubuntu の minion だけが対象になります。

次の引数 `test.ping` は実行モジュールとその function を指定しています。test.ping は minion が動作しているか確認する時によく使います。その他にどの様な実行モジュールがあるのかは https://docs.saltproject.io/en/latest/ref/modules/all/index.html を参照ください。

Salt はOSの各種属性データを自動で minion から master へ集める仕組みがあります。以下コマンドでどのようなデータを集めているのかわかります。

```shell:
$ sudo salt '*' grains.items
```

沢山出力されます。ある特定の属性データだけを出力するには `grains.item 属性名` で指定します。例えば全ての minion の IP アドレスを知りたい場合は以下のように `ipv4` を指定します。

```shell:
$ sudo salt '*' grains.item ipv4
ubuntu.example.com:
    ----------
    ipv4:
        - 127.0.0.1
        - 192.168.100.105
```
# Kubernetes を対象に加えよう

Salt で Kubernetes を扱うには Kubernetes Python Client が別途必要になります。以下の操作でインストールします。

```shell:
$ curl  https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ sudo python3 get-pip.py
$ sudo pip install --ignore-installed kubernetes
```

また、 /usr/lib/python3/dist-packages/salt/modules/kubernetesmod.py ファイルを以下のように変更します。

```diff:/usr/lib/python3/dist-packages/salt/modules/kubernetesmod.py
71,72c71,72
<         from kubernetes.client import V1beta1Deployment as AppsV1beta1Deployment
<         from kubernetes.client import V1beta1DeploymentSpec as AppsV1beta1DeploymentSpec
---
>         from kubernetes.client import V1Deployment as AppsV1beta1Deployment
>         from kubernetes.client import V1DeploymentSpec as AppsV1beta1DeploymentSpec
```

次に kubeconfig ファイルを用意ます。今回は /home/ubuntu/.kube/config とします。そして /etc/salt/minion.d/kubernetes.conf ファイルを作成し kubeconfig ファイルと context をそれぞれ以下のように指定します。

```/etc/salt/minion.d/kubernetes.conf
kubernetes.kubeconfig: '/home/ubuntu/.kube/config'
kubernetes.context: 'tkgs-cluster'
```
上記設定を反映させるために minion を再起動します。

```shell:
$ sudo systemctl restart salt-minion
```

では動作確認しましょう。

```
$ sudo salt '*' kubernetes.nodes
ubuntu.example.com:
    - tkgs-cluster-control-plane-f85m6
    - tkgs-cluster-tkg-cluster-nodeool-1-qgmpt-cf887845d-7pgm7
    - tkgs-cluster-tkg-cluster-nodeool-1-qgmpt-cf887845d-nd6lr

$ sudo salt '*' kubernetes.namespaces
ubuntu.example.com:
    - cert-manager
    - default
    - kube-node-lease
    - kube-public
    - kube-system
    - tanzu-system-ingress
    - tanzu-system-logging
    - tanzu-system-monitoring
    - tanzu-system-service-discovery
    - tkg-system
    - velero
    - velero-vsphere-plugin-backupdriver
    - vmware-system-auth
    - vmware-system-cloud-provider
    - vmware-system-csi
```

動いているようです。次は State ファイルを使って namespace を作ってみたいと思います。以下のファイルを作成します。

```yaml:/srv/salt/k8s/sample.sls
namespace-test:
  kubernetes.namespace_present:
    - name: sample-namespace
```

そして以下のコマンドで State ファイルを適用します。

```shell:
$ sudo salt '*' state.apply k8s.sample
```

再度 `sudo salt '*' kubernetes.namespaces` を実行すればで sample-namespace という名前の namespace を作成できたことがわかります。

# 最後に

Salt からKubernetes に対してもっと多くのことができますが今回は導入部分と少しの例を説明しました。
salt コマンドで使う kubernetes モジュール、Stateファイルで使う kubernetes モジュールのマニュアルはそれぞれ以下になります。

- https://docs.saltproject.io/en/latest/ref/modules/all/salt.modules.kubernetesmod.html#module-salt.modules.kubernetesmod
- https://docs.saltproject.io/en/latest/ref/states/all/salt.states.kubernetes.html#module-salt.states.kubernetes

また、以下の動画ではさらなる活用例を説明しています。参考になるかと思います。

https://www.youtube.com/watch?v=QPieidIEEcg