はじめに
Azure VM で発生するメンテナンス イベントの情報を取得し、メンテナンスに備えるための猶予を与える Azure Metadata Service をポーリングするスクリプトを、Python で作成してみました。
(polling のスペルミスに気付かないまま作ってしまった…)
2022/10/27 : ファイルの出力を yyyy/MM/dd/hh/mm の階層構造になるように修正しました
設定したスクリプトの動作テスト編を記事にしたのでよかったらこちらも参照ください。
目次
やりたいこと
Scheduled Event
Azure VM では、メンテナンスやハードウェア障害、ポータルからの操作などを様々なことをきっかけに、以下のようなイベントが起こりえます。
- freeze: VM の一時停止
- reboot: VM の再起動
- redeploy: ホストの移動
- preempt: スポット VM の削除
- terminate: VM の削除
Azure VM 内から叩ける API である Azure Metadata Service を使用することで、これらのイベントの予定をある程度事前に検知することができます。
それにより、必要に応じてアプリケーションが正常に中断するための準備処理を行うことや、イベントが発生したことを記録するためにイベント ログを残す、などの対処を行う時間的猶予を得ることができます。
それが Scheduled Event です。
Azure VM の中から以下のエンドポイントにリクエストを投げることで、レスポンスとして Scheduled Event の情報を返します。
http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01
どれくらい早く検知できるかはイベントの種類にもよりますが、Docs によれば一時停止メンテと再起動で、最大 15 分程度前には検知できます。
前置きが長くなりましたが、前述のとおり、このエンドポイントは Azure VM 内から API を叩く必要があります。
アプリケーションの重要度によるところもありますが、少しでも早くイベントを検知したいのであればポーリング頻度として 1 秒がお勧めされているため、今回は Python スクリプトで Scheduled Event を毎秒ポーリングしてみます。
実現イメージ
東日本リージョンに RHEL をデプロイし、必要なものをインストールして、Python スクリプトを動かします。
停止、起動してもスクリプトが止まらないよう、デーモン化させて動かすことにしました。
ログ ファイルは、マウントして使える Azure Files に出力しています。
環境構築
Azure Files マウント
デプロイしたのは RHEL 8.2 です。
SMB でマウントするため、cifs-utils をインストールします。
sudo yum update -y sudo yum install -y cifs-utils
ストレージ アカウントと、ファイル共有をデプロイ (容量はデフォルトの 5TiB)
ファイル共有の接続ボタンから、Linux 用の接続スクリプトをコピーして実行
マウント、fstab 設定までやってくれるので便利です。
"/mnt/マウント ポイント" にマウントされるので適当にファイルを作成して、ポータルから見えるかチェックしてもいいと思います。
Python 設定
インストール
今回は Python 3.8 をインストールしました。
sudo yum install -y python38
alternatives 設定
このままだと、"python" コマンドで動かず、"python3" とすると python3.6 が動いてしまうため、"python" で 3.8 を指すよう alternatives で変更してしまいます。
sudo alternatives --config python
変更前の確認
変更 & 変更後の確認
拡張機能インストール
今回のスクリプトで必要な request 拡張機能をインストールします。
sudo python -m pip install requests
root 使って入れない方がいい、と警告されたので sudo つけないで --user にするのがよいかも。
インストール後、script normalizer が PATH に入ってないと言われたので PATH に追加しときます。
export PATH=$PATH:/usr/local/bin
スクリプト設定
1 秒毎に Scheduled Event のエンドポイントを叩いて、結果を json ファイルとして Azure Files に出力しています。
毎秒実行については、こちらの記事を参考にしました。
スクリプト配置
作成したスクリプトはここにあるので、任意の場所にダウンロードします。
今回は home ディレクトリでやってしまいます。
curl -O https://raw.githubusercontent.com/kzk839/Polling_ScheduledEvent/main/Polling_ScheduledEvent.py
basepath 変数に Azure Files のマウントパスが書かれているため、変更しておきます。
(今回の場合は /mnt/scheduledevent/)
デーモン化して実行するので、システムに実行権限を付与します。
sudo chmod o+x Polling_ScheduledEvent.py
テスト
ここで一度、スクリプトを実行しておきます。
Scheduled Event のエンドポイントは初回のリクエストを投げた際に初めて有効化され、その際応答には 1, 2 分を要します。
デーモン化してから初めて実行すると待ち時間の間にエラーが出て、止まってしまったりするので、動作確認も兼ねてここで動かしておくのがいいと思います。
こんな感じで 1 秒ごとにファイルが出力されていれば OK
※2022/10/27 に、ファイルの出力を yyyy/MM/dd/hh/mm の階層構造になるように修正したため、現在は日時の変化に従いディレクトリが自動で追加されていきます。
例として、2022/10/27 18:24:35 のログだったら、 /2022/10/27/18/24/20221027-182435.json が出力されます。
ちなみに、Scheduled Event のエンドポイントを 24 時間叩かないと、無効化されます。(次叩いたときにまた 1 分くらい待たされる)
デーモン化
ログオフしたり、再起動したりしても実行し続けるよう、スクリプトをデーモン化します。
デーモン化については参考にした qiita 記事があったのですが、なくなってしまいました…
デーモン化するには、以下のファイルを作成します。
名前 (xxx.service) は任意です。
sudo vi /etc/systemd/system/polling_scheduledevent.service
中身はこれを書きます。
[Unit] Description = polling scheduled event daemon [Service] Type = simple Restart = on-failure ExecStart = Python3までの絶対パス スクリプトまでの絶対パス [Install] WantedBy = multi-user.target
今回だとこんな感じ
これで準備はできたので起動して、動作を確認します。
sudo systemctl start polling_scheduledevent sudo systemctl status polling_scheduledevent
ステータスを確認して、active (running) になれば OK です。
Files にバンバン出力されていると思います。
問題なければ最後に、自動起動を有効化します。
sudo systemctl enable polling_scheduledevent
これで実装は完了です!
終わりに
以上、Scheduled Event を毎秒ポーリングする Python スクリプトの実装でした。
このスクリプトではサボっていますが、ファイルが大量に出力されるので、日時に応じて出力フォルダを分けるとか、前回と内容が変化していなかったら出力しない、などした方が後から見やすいです。
サボらずディレクトリを作るよう更新しました。
今回実装しているのはイベント情報の出力だけなので、イベントへの対処をするのであれば、取得したイベントの種類に応じて更に処理を書き加えていく感じです。
最初は Windows でタスク スケジューラでやろうとしたんですがなかなかうまくいかず、デーモン化の記事を見つけて試したらあっさりできました…