Kubernetesで障害発生するとNT-Dが発動しユニコーンガンダムのサイコフレームが発光するシステムの開発

# モチベーション

自宅のKubernetsの運用を行っていると、障害が発生してもついつい後回しにしてしまいがちです。
これにより、家庭内の情シス部門としては、ユーザ(家族)からクレームを受けることがしばしばあり、家庭の平穏を脅かすものでした。

そこで、障害が発生しても直ぐに気がつけ、さらにテンションを上げるものが欲しくなりました。
真っ先に思い出したのが、いにしえ(?)のデータセンターのパトランプです。
障害発生時に設置されたパトランプが光り出しスタッフに緊張感が走ったものでした。

しかし、パトランプは残念ながら持ち合わせていないため、光らせてテンションの上がるものを家の中を物色すると、積みプラされた「RX-0ユニコーンガンダム」を発見してしまいました。
この積みプラされていたユニコーンガンダム、幸いなことにLEDが組み込まれた光る奴でした。
発見した瞬間、障害発生でNT-Dが発動しデストロイモードとなるユニコーンガンダムの姿が脳裏に浮かび上がり、3秒で即決し作成に取り掛かりました。

なお、完成したシステムのデモ動画は[こちら](https://youtu.be/0-yCTHrpOm0)です

# 構成概要

構成図を以下に示します。
はんだこてなど使った電子工作はゼロで作成しています。

![arch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229880/32070499-98af-549c-6a0e-e0150d370f77.png)

(3)(4)以外は脊髄反射でアーキテクチャが決まりましたが(3)(4)は正直悩みました。
悩んだポイントは後ほど解説します。

# 使用機器

今回使用した機器は以下です。

【ハードウェア】

- [RG 1/144 ガンダムベース限定 RX-0 ユニコーンガンダム(デストロイモード) Ver.TWC(LIGHTING MODEL)](https://www.gundam-base.net/products/details.php?detail=2834)
- [LANMUダミー電池 単4形](https://www.amazon.co.jp/dp/B09HGQKQMG?ref_=cm_sw_r_cp_ud_dp_NGAEQ9BSB9Q7GAA9KZJC)
- [Merossスマート電源タップ MSS425FJP](https://www.amazon.co.jp/dp/B07Q9S2629?_encoding=UTF8&psc=1&ref_=cm_sw_r_cp_ud_dp_6SKBWH40BGFVHRM7D2JD)

【ソフトウェア】
- [Kubernetes](https://kubernetes.io) (Raspberry Piで構築)
	- [Prometheus](https://prometheus.io)
	- [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/)
- [Slack](https://slack.com/)

:memo: 本ドキュメントではKubernetes、Prometheus, Alertmanager, Slackのセットアップについては省略します。
Tipsとしては、詳しく説明しませんが、Alertmanagerの設定(config.yaml)の設定で`send_resolved: true`を設定しておくと、NT-Dモードを停止させる契機を得ることができます。

【開発言語】
- Python
- Docker (コンテナイメージのビルドで利用)

# ハードウェア構築

- (Step1) ガンプラのユニコーンをひたすら作成
- (Step2) 電源の準備

まず、ここで悩み始めました。 
ユニコーンガンダムは光ると言っても単4電池を入れるタイプです。
電池はいざという時に切れていることがあるので直接コンセントにつなぎたいという思いがあり、どうしようか悩みました。
電子工作するかーと脳裏に浮かんだのですが、ふと過去家の中の電飾で利用していたダミー電池を思い出しました。
手持ちのダミー電池が運良く単4電池だったため、試しにユニコーンガンダムの電池ボックスへ入れてみたところ問題なく動作しました。

![battery.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229880/32fd2832-7070-9013-d803-728d479fc2a6.png)

上記の写真にあるように、ダミー電池からのケーブルはフラットケーブルのため、問題なくケースも閉じることができました。

- (Step3) スイッチのON/OFFの制御設計

次に悩んだポイントはスイッチのON/OFFの制御をどのようにして行うのかです。
下の写真にあるように、このユニコーンガンダムの発光は、スイッチのON/OFFによって行われます。

![switch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229880/27e4ce77-34bc-5e4a-eacd-8c4797c46163.png)

ただし、ダミー電池を使うと決めていたので、ユニコーンガンダムのスイッチは常にONにしておき、USB給電をON/OFFすれば発光できます。
そのため、どうやってUSB給電のON/OFFを行うかを悩みました。
思い浮かんだ案は以下の2つです。

- (案1) Raspberry PiのUSBに接続し給電。Raspberry PiでUSBのON/OFFを制御。
- (案2) スマート電源タップに繋ぎ、USBのON/OFFを制御。

この2つの案は、どちらでも良かったのですが少し悩んだ結果、(案1)では以下の懸念点があり不採用とし(案2)を採用しました。

[懸念点]

- Raspberry Piの電源が不足するリスクあり
- Raspberry PiのUSBポートは全ポート単位で電源のON/OFF制御となる
- Raspberry Piをユニコーンガンダム向けに用意するのか?
  - Kubernetesで利用しているRaspberry Piを利用する手もあるが、ユニコーンガンダムを接続しているRaspberry Piのノードに限定してBotを稼働させないといけなくなる (Kubernetes上のPodスケジューリングの柔軟性を損なう)
  - ユニコーンガンダムが発光することで、Raspberry Piの電源が不足し、二次障害を発生し得るリスクあり
  - ユニコーンガンダム用にRaspberry Piを用意する場合、リモートでRaspberry PiのUSBのON/OFFを制御するAPIサーバを作る必要あり

以上でハードウェアの構築が完了です。

# ソフトウェア構築

次は、Slackに通知されたアラートを受け動作するSlack Botを開発します。
Slack BotはWebSocketを使い開発します。

- (Step1) Slack Appを登録
  
[slack api](https://api.slack.com/apps) にアクセスしSlack Appを新規に作成します。
Slack Appの登録は[「Slack ソケットモードの最も簡単な始め方」](https://qiita.com/seratch/items/1a460c08c3e245b56441)が参考になります。
今回はグローバルショートカットは不要ですので設定は不要です。
Appの名前は迷わず「ハロ」に設定しました。

- (Step2) Slack Bot(ハロ)の開発

ここで1つ悩みが発生しました。
スマート電源タップMerossでは制御を行うためのAPIが公式から公開されていませんでした。
仕方ないので[「Merossのスマートプラグとスマート電球をハックして間接照明をリモコン操作できるようにした話」](https://zenn.dev/ttskch/articles/95cfa30390241c)の記事を参考に、スマートフォンのMerossのクラアントアプリからパケットをダンプし解析して試してみました。
動きはしましたが、残念ながらこの方法だとリクエストのJSONデータ内の鍵となる`messageId`, `sign`に有効期限があるようで、しばらくすると期限切れを起こし値の更新が必要になってしまいました。

そこで、個人で開発されている[Meross IoT library](https://github.com/albertogeniola/MerossIot)が公開されているのを見つけ、これを利用する方針としました。

開発したSlack Bot(ハロ)のソースコードは[ysakashita/haro/manifests/haro.py](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py)で公開しました。
興味があれば読んでみてください。
簡単に流れを説明すると以下です。
やっていることはシンプルです。

1. [Slackからmessageのイベントを受信](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L53)
1. [Alertmanagerからのメッセージかどうかをチェック](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L69)
1. [メッセージがアラート発生の場合はntd(1)を呼び出し](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L78)
1. [MesossのClientを作成](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L29)
1. [Merossのデバイスを検出](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L34-L35)
1. [MerossのデバイスのチャンネルへON命令を送信](https://github.com/ysakashita/haro/blob/0.1/manifests/haro.py#L39)

ソースコードの説明は以上です。

- (Step3) ハロのデプロイ

Kubernetes上にハロをデプロイします。

デプロイ方法は[ysakashita/haro/README.md](https://github.com/ysakashita/haro/blob/0.1/README.md)を参照してください。

Pythonでハロを開発しコード量も100ステップ以下のため、kustomizeのconfigMapGeneratorを使いデプロイしています。
この方法だと、スクリプト言語でConfigMapに格納できるぐらいのコード量であれば、ソースを変更するたびにコンテナイメージを作成しなくても良いので楽です。

自宅で軽く開発などをする場合には、よく利用する方法です。

以上で完成です。

# 感想

Kubernetesで障害発生するとNT-Dが発動し、ユニコーンガンダムのサイコフレームが発光するシステムの解説でした。
全体的に作りはシンプルなため、Slack Botを介して何かを制御する本やり方は、他にも応用が効くかと思います。
実際に作ってみて(1)電源の準備、(2)スイッチのON/OFF制御設計、(3)スマート電源タップのAPIの3点ほど頭を悩ましましたが、いずれもそこそこ納得する形で実装できたかと思います。

あと、本題とは関係ないところでも実は悩みました。アニメのユニコーンガンダムでは、NT-Dを発動するのはユニコーン自身であり「ハロ」を使っていないのです。
そのため、Slack Bot名を「ハロ」or「ユニコーンガンダム」にするかで悩みましたが、特に理由はなく感覚でBotは「ハロ」かなーということで決まりました。

ちなみに、このシステムで一番時間がかかったのは、ユニコーンガンダムの組み立てです。

(おまけ)
NT-Dの表向きな正式名称は「ニュータイプ・ドライブ」ですが、実体は「ニュータイプ・デストロイヤー」です。NT-Dが発動したユニコーンガンダムはデストロイモードに変形しサイコフレームが発光します。
アナハイム社のエンジニア曰く「なぜ発光するのかわからないのです」だそうです。