GCP上のMinecraft統合版サーバーをdiscordのBotから起動する

GCP上のMinecraft統合版サーバーをdiscordのBotから起動する

この記事では、Google Cloud Platfrom上に設置したMinecraft統合版サーバーを、discordのコマンドから操作する方法を解説します。

この記事で分かること

  • GCP無料枠インスタンスの立て方
  • discord Botの導入
  • コマンドによるインスタンスの起動・停止

参考にしたサイト

この記事の全体の思想は以下の記事から来ています。大変役立ち、よくまとまっているのでお勧めです。

構成図

GCP無料インスタンスを立てる

Google Cloud PlatformにはAlways freeというキャンペーンがあり、無料で使えるインスタンスがあります。現時点では何年でも無料ですので、このサーバーにdiscrodを監視するBotを置き、コマンドが送信されたらプリエンプティブのMinecraftサーバーを起動します。

それでは、この無料インスタンスを作っていきましょう。
無料インスタンスの制限は以下の通り。

項目 詳細
マシンタイプ f1-micro(vCPU×1,0.6GB RAM)
ディスクサイズ 30 GB
OS 無料OS(DebianやUbuntu等)
リージョン アメリカ

この条件内であれば、月744時間、つまり常に無料です。
では、このインスタンスを作っていきましょう。

  1. 前回作成したMinecraftサーバーのあるプロジェクトに移動

  2. Compute Engine>VMインスタンス からインスタンスを作成を選択

  3. 下記画像のようにリージョンとマシンタイプを設定する

    この画像ではus-west1にしています。西海岸の方が日本に近いため、遅延が少ないはずです。私は既に他の無料インスタンスをus-centralで作ってdiscordサーバーとして運用していますが問題ありません。

    画面右に下記のようなメッセージが出れば無料枠となります。

  4. ブートディスクをUbuntu 18.04 LTS Minimalにし、サイズを30GBにします。

  5. 作成でインスタンスを作成します

以上で、無料枠インスタンスの作成は完了です。

試しにSSHでログインしてみましょう。前回の記事と同様、VMインスタンスのSSHボタンをクリックして入ります。

このような画面が出現すれば成功です。

discord Botを導入する

では、discord Botをこのサーバーに設定しましょう。
まずは、簡単なコマンド返しを実装します。

  1. Pythonで実用Discord Bot(discordpy解説)を参考に、操作したいdiscordグループのアクセストークンを取得し、「Botプログラムの作成と起動」に沿って実行する

非常にまとまっているので、そのまま沿って行けば実装できると思います。

Botを起動後、自分のdiscordサーバーで/nekoコマンドを試してみましょう。

このpythonスクリプトで重要な所は、以下の場所です。

@client.event async def on_message(message): # メッセージ送信者がBotだった場合は無視する if message.author.bot: return # 「/neko」と発言したら「にゃーん」が返る処理 if message.content == '/neko': await message.channel.send('にゃーん')

このif message.content == '/hogehoge'を積み重ねれば、様々なコマンドに対する応答を実装できます。
GCPのインスタンスはgloudというコマンドから操作できるので、起動する関数をserver_start()、停止する関数をserver_stop()と仮定すると、

if message.content == '/server start':
    server_start()
if message.content == '/server stop':
    server_stop()

のように記述すればOKなわけです。

これらを実行するpythonファイルを作っていきましょう。

discordからサーバーを起動する

pythonファイルを作る前に、メインのマイクラ鯖を操作する権限を持つアカウントの作成が必要となります。

インスタンスの起動・停止権限を持つユーザーを作る

  1. GCP>プロダクト>IAMと管理>役割 を選択

  2. 「役割を作成」を選択

  3. 適当なタイトル(minecraft-admin等)をつけ、権限を追加を選択

  4. 権限に以下の4つを追加する

    • compute.instances.start
    • compute.instances.sto
    • compute.instances.get
    • compute.zoneOperations.get

    追加するときは検索欄に入れると便利です。見つかったらチェックを入れて追加しましょう。

  5. 作成をクリック
    これでサーバーの起動・停止権限がある役割が作成できました。
    次は、この役割を与えられるユーザーを作ります。

  6. IAMと管理>サービスアカウント へ移動

  7. サービスアカウントを作成を選択

  8. サービスアカウント名に「minecraft-admin」等の名前を付け、作成

  9. 先程作成した役割を付与する。(私の場合は役割の名前をMineAdminにしたので、これを選択)

  10. キーの作成(オプション)からキーを作成する。この時、JSON形式にすること。

    これでサービスアカウントの作成は完了です。

JSONファイルはすぐに使います。

サーバーの秘密鍵をダウンロード・登録する

  1. discord用のサーバー(無料インスタンス)にSSHでつなぐ
  2. 右上の
  3. 以下のコマンドを実行する
gcloud auth activate-service-account --key-file xxxxxxxxxxxx.json

※xxxxxx.jsonの部分は、先程アップロードしたjsonファイル名にしてください。

これで、このサーバーからminecraftサーバーを起動・停止できるようになりました。

コマンドに反応するpythonスクリプトを書く

以下の通りのpythonファイルを、discord用鯖の適当な場所に置きましょう。冒頭のすべて大文字になっている変数はご自分の環境に合わせて変更してください。GCP_PROJECT_NAMEはプロジェクト選択ウィンドウのIDのところに記載されています。

IDがHOGE1221であれば、GCP_PROJECT_NAME="HOGE1221"とします。

#references: https://qiita.com/1ntegrale9/items/9d570ef8175cf178468f, https://qiita.com/neight0903/items/b243c730bd09d3562654
# インストールした discord.py を読み込む
import discord
import subprocess
# 自分のBotのアクセストークンに置き換えてください
TOKEN = 'THi5IsDuMMyaCCesSTOK3nQ4.Cl2FMQ.ThIsi5DUMMyAcc3s5ToKen7kKWs'
# サービスアカウントID
SERVICE_ACCOUNT_ID=hogehoge@hogehoge.iam.gserviceaccount.com
# プロジェクト名
GCP_PROJECT_NAME=hogehoge
# マイクラサーバーインスタンスの名前
MINECRAFT_INSTANCE_NAME=hogehoge
#MINECRAFT_INSTANCE_NAME=minecraft-server
# マイクラサーバーインスタンスのゾーン
MINECRAFT_INSTANCE_ZONE=hogehoge
#MINECRAFT_INSTANCE_ZONE=asia-northeast1-b
# 接続に必要なオブジェクトを生成
client = discord.Client()


#サーバー起動処理
def server_start():
    command = f'/snap/bin/gcloud --account={SERVICE_ACCOUNT_ID} compute instances start {MINECRAFT_INSTANCE_NAME} --project {GCP_PROJECT_NAME} --zone {MINECRAFT_INSTANCE_ZONE}'
    subprocess.call(command.split())
    return
#サーバー停止処理
def server_stop():
    command = f'/snap/bin/gcloud --account={SERVICE_ACCOUNT_ID} compute instances stop {MINECRAFT_INSTANCE_NAME} --project {GCP_PROJECT_NAME} --zone {MINECRAFT_INSTANCE_ZONE}'
    subprocess.call(command.split())
    return
# 起動時に動作する処理
@client.event
async def on_ready():
    # 起動したらターミナルにログイン通知が表示される
    print('ログインしました')

# メッセージ受信時に動作する処理
@client.event
async def on_message(message):
    # メッセージ送信者がBotだった場合は無視する
    if message.author.bot:
        return
    # 「/neko」と発言したら「にゃーん」が返る処理
    if message.content == '/neko':
        await message.channel.send('にゃーん')

    if message.content == '/server start':
        server_start()
        await message.channel.send('starting server...')
    
    if message.content == '/server stop':
        server_stop()
        await message.channel.send('stopping server...')
# Botの起動とDiscordサーバーへの接続
client.run(TOKEN)

コマンドの実行

python3 discord_minecraft.py

ログインしましたと表示されれば成功です。

コマンドのバックグラウンド実行

nohup python3 discord_minecraft.py &

nohupという機能を使い、バックグランド実行である&オプションをつけて実行しています。こうすればsshからログアウトしてもdiscordBotが動き続けます。

ここで、トークンを指定したdiscordグループで/server startと打ってみましょう。返答があり、gcpのダッシュボードでminecraft鯖の起動が確認できれば実装成功です!

サーバーの自動起動

以上の設定をすれば、minecraftサーバーが入っているインスタンスの起動がdiscordからできます。
しかし、インスタンスが起動してもminecraftサーバーは起動しません。インスタンス起動時にminecraftサーバーも自動起動する必要があります。

systemdファイルの作成

ubuntuにはsystemdと呼ばれるシステム起動機能が備わっています。ここに登録しておけば、起動時に指定したスクリプトを実行できます

  1. minecraft鯖用インスタンスを起動してsshで接続
  2. vi /etc/systemd/system/minecraft.service と入力し、ファイル編集画面にする
  3. iを押して文字挿入モードにする
  4. 以下のソースコードをコピーして、Ctrl + Vで貼り付ける
    [Unit]
    Description=minecraft bedrock server service
    After=network.target
    [Service]
    User=root
    Group=root
    WorkingDirectory=MINECRAFTSERVERDIRECTORY
    ExecStart=/usr/bin/screen -DmS bds MINECRAFTSERVERDIRECTORY/bedrock_server
    ExecStop=/usr/bin/screen -r bds -X stuff $"say SERVER SHUTTING DOWN IN 15 SECONDS...\n"
    ExecStop=/bin/sleep 15
    ExecStop=/usr/bin/screen -r bds -X stuff $"save-all\n"
    ExecStop=/usr/bin/screen -r bds -X stuff $"stop\n"
    Restart=no
    
    [Install]
    WantedBy=multi-user.target
    

    MINECRAFTSERVERDIRECTORYには自分のインストールしたminecraftサーバーのパスを入れましょう。例えばユーザー名hogeのホームディレクトリ内のminecraftというフォルダに入れた場合は/home/hoge/minecraftを入れます。

  5. sudo service minecraft startで、systemdのサービスとしてminecraftを実行。
  6. sudo suで管理者になってから、screen -r bdsでminecraft鯖のコンソールに入れたら成功。

以上の設定で、インスタンス起動時に自動的にminecraftサーバーが起動するようになります!

まとめ

以上がdiscordBotからminecraft鯖を起動する方法でした。統合版はスマホからもプレイできるため、例えば電車内からdiscord経由で鯖を起動してログインするという遊び方もできます。

再度今回の流れをまとめますと、

  1. discord用の常時起動無料鯖を建てる
  2. discordBot用のアクセストークンを取得
  3. discordBotのpythonファイルを書き実行
  4. minecraft鯖に戻り、systemdを登録
  5. discordから/server start/server stopで遠隔起動できるようになる!

といった感じでした。何か不明点やエラーなどがございましたらお気軽にtwitterかコメント欄でお知らせください。

2件のコメント

  1. bot起動コマンドを実行したのですが以下の文章が出てきてしまい起動が出来ません。

    Traceback (most recent call last):
    File “minecraft-bot10.py”, line 3, in
    import discord
    ModuleNotFoundError: No module named ‘discord’

    記事の通りに作成したり自分なりに調べしたりして何度も試したのですが起動できませんでした。
    どうすればよいのでしょうか?

    1. コメントありがとうございます。

      エラーには「discordという名前のライブラリが見つからない」と書いてあります。
      本記事で紹介しているdiscord導入記事(https://qiita.com/1ntegrale9/items/9d570ef8175cf178468f)をご覧いただき、インストールしてください。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です