はじめに
Azure の仮想マシンを使って、 Minecraft (Spigot) マルチサーバを立ち上げて運用しています。
参加メンバーは全員会社勤めなので、平日の日中はサーバを停止して、「平日の夜・土日の終日」の間だけ自動でサーバが立ち上がるようにしています。
今回は、サーバの開始・起動スケジュールを IFTTT の DateTime トリガーと連動するため Azure Automation を使い、更に 仮想マシンの起動と終了に連動する Minecraft サーバ を構築しました。
最終的にはサーバの起動通知を Discord に送るようにしてメンバーが確認できるようにしています。
この記事では、以下の手順で解説しています(基礎知識的な部分は省略しています)。
- 仮想マシンの構築
- VM の起動と終了に連動した Minecraft サーバを構築します
- Azure Automation で Webhook を作成する
- VM の起動と終了を行い、Discord に Webhook で通知する Runbook を構築します
- IFTTT で Webhook のトリガーを作成する
仮想マシンの構築
今回作成した VM は以下のようなスペックでした。
- SKU: Standard D2s v3 (2 vcpu 数、8 GiB メモリ)
- Region: 東日本
- Image: Ubuntu Server 18.04 LTS
D2s v3 で ¥9,166/月
ですが、平日は 6h 程しか稼働しないため大体 300h/月 となり、月額のおよそ 1/2 程度で運用しています(価格だけ見たらやっぱりちょっと高い気もする)。
Spigot サーバの構築
今回は Docker を使って構築しました。
nimmis/docker-spigot を Clone して docker-compose.yml
の値を変更するだけで終わりです。
$ sudo mkdir -p /minecraft
$ sudo chown -R mcserver:mcserver /minecraft
$ git clone --depth=1 https://github.com/nimmis/docker-spigot /minecraft
version: "2"
services:
spigot-main:
container_name: "spigot-main"
build: "."
ports:
- 80:8123
- 25565:25565
environment:
- MC_MAXMEM=8g
- MC_MINMEM=1g
- SPIGOT_AUTORESTART=yes
- SPIGOT_VER=1.14.4
- SPIGOT_UID=1000
volumes:
- "./server:/minecraft"
restart: "always"
これで docker-compose up
すれば spigot.jar
のビルドが走り、以降はサーバが自動で立ち上がるようになっています。
終了時スクリプト
仮想マシンが停止しようとする時に、Minecraft サーバのワールドデータを /save-all
した上で終了する必要がありますが、今回利用したイメージは、コンテナが Stop する際にそのあたりを自動でやってくれています。
なので終了時スクリプトを書いてシャットダウン時にコンテナを停止するようにします。
終了時スクリプトの作成
$ sudo vim /etc/init.d/stop-mcserver.sh
$ sudo chmod a+x /etc/init.d/stop-mcserver.sh
$ sudo ln -s /etc/init.d/stop-mcserver.sh /etc/rc6.d/K99stop-mcserver
#!/bin/bash
cd /minecraft
/usr/local/bin/docker-compose stop
また、 restart: "always"
なので次回起動時に自動的にコンテナが立ち上がって Minecraft サーバが復帰するため、これで自動起動・終了の仕組みが完成します!!!
しなかった
原因が未だに分からないんですが、Azure の仮想マシンが再起動した後に何故かコンテナが自動で立ち上がりません。
ですが、SSH して docker ps
などを叩くと 微妙なラグの後にコンテナが起動 したため、おそらく Docker daemon のプロセスが正しく起動していないのではと考えられます。
起動時スクリプト
なので、起動時に Docker API を叩く無害なコマンドを実行させることで無理やり Docker daemon を起動させています。
これで、仮想マシンが再起動した後もコンテナが自動で立ち上がるようになりました。
起動時スクリプト
$ crontab -e
crontab の中身:
# m h dom mon dow command
@reboot /usr/bin/docker --version > dev/null 2>&1
Azure Automation で仮想マシンを起動・終了させる
Azure Automation の Runbook でこれらの内容を実装します。
- サーバを起動させる
- サーバを停止させる
- 起動・停止したら Discord の Webhook で通知する
- Automation 開始トリガーを Incoming Webhook にする
サーバを起動・停止させる
これは、 Runbook ギャラリーの人気上位にある 2つのスクリプトをインポートすれば終わりです。
ですが、インポートしてきた Runbook は Azure の仕様変更に合わせて更新されておらず、正しく起動・停止できたのにも関わらず Automation ジョブが Error で終わるようになっています。
原因は Notify VM Started/Stopped ノードの実行条件式が古いためで、これを現在の ActivityOutput のプロパティに合わせることで解決します(あと Notify Failed To Start/Stop ノードあたりのエラー内容の取得方法も古かったため直しました)。
Discord の Webhook で通知する
※ Webhook は作成済みです
以下のような感じでそれぞれの出力メッセージを IDictionary -> JSON に変換して、その内容を Webhook で Discord に通知しています。
Format message
Write-Output
ノードを使い、Discord の Webhook の仕様に合わせてコンテンツを作成。
@{
content = $_
}
ConvertTo-Json
Format message からアクティビティの出力を受け取る
Notify to webhook
Invoke-WebRequest
ノードを使い、ConvertTo-Json のアクティビティの出力を POST
で送信。
Content-Type に application/json; charset=utf-8
を指定しないと日本語が文字化けする。
あと UseBasicParsing
フラグも True
にしないとジョブが正しく終わらなかった(はず)。
開始トリガーの Incoming-Webhook を作成する
それぞれの Runbook で Webhook を作成して動くかどうか確認する。
$ curl -X POST -H "Content-Type: application/json" https://WEBHOOK
このように通知されて仮想マシンが起動・終了すれば OK(Runbook 上のメッセージを日本語に変えています)。
それぞれの Webhook URL を控えておきます。
IFTTT のトリガーを作成する
IFTTT の DateTime トリガーから Every day of the week at を選択します。
曜日と時間が選択出来るので、例えば 平日の19時に実行するようなトリガー を作成します。
次に実行するアクションで Webhook を選択し、先程の Webhook URL を設定します。
これを複数個作成し、1週間分の起動・停止スケジュールを作成すれば完成です。
ちなみに
Azure Automation 自体にもスケジュール実行機能が備わっていますが、正直使い勝手が良くないのと スマートフォン上から編集しづらいので IFTTT 経由でスケジュールを編集出来る方がより簡単です。
完全に蛇足ですが仮に祝日判定などの機能追加をする場合も、Runbook 上で構築するよりも Discord の Bot を別途ホストして独自でスケジューリングを実装するのが良いと思います。