やりたいこと
「Google Cloud Platform(以下GCP)」の「Google Compute Engine(以下GCE)」を用いてMinecraftサーバーを構築したい。常時起動していてはお金がかかって大変なので、遊ぶときだけ起動したいが、自分以外の人が遊ぶときでも起動できるようにはしておきたい。そこで、Discordのチャットにコマンドを打ち込むことで、そのときだけMinecraftサーバーを起動できるようにしたい。
経緯
今まで自分のPC上にサーバーを構築して、ポート開放一時的にしたりとかしてマイクラのマルチプレイをしていた。けれども、これではぼくがPCを起動しっぱなしにしなければならないし、他の人が自発的に遊べないのでクラウドとかにサーバーがほしいとおもった。
あとセキュリティ的怖さも・・・・・・ね。
サークルの方ではWeb管理係なるものになったようだし、サーバー関係のお勉強も兼ねて構築してみることにした。
クラウドサービスの中でGCPを選んだ理由としては、GCPが初回一年は約3万円分ほど無料で使えるのと、小さな仮想マシンであれば一年目以降も無料で使えるようだったので、有料分はマイクラ鯖用、無料分はDiscordのコマンドbot用に使えそうだということで試すことにした。(あと既存のアカウントで使えたというのもある)
前提
Googleアカウントを持っていて、GCPが利用できる状態になっている(クレカ登録とかが済んでいる)こと。GCEのインスタンス作成まではできる状態であること。
Minecraftサーバーの構築
こちらは自分のパソコンでサーバーを立てていたのとほぼ同じ手順でやっていたのでさほど問題なく構築できた。
基本的には
の通りにやっていく感じ。
インスタンスの作成
マイクラサーバーは無料分のスペックの低いインスタンスだとうまく動かすのは難しいようなので、「n1-standard-1」を選択。
OSは個人的趣向でCentOS7。まあお好きなLinux使えばいいんじゃないでしょうか。追加ディスクはやってないのでデフォの10GBのみ。
あとでファイアウォールでポートの設定をするためにネットワーキングタグの設定も忘れずに(あとでもできるけど)。
静的IPアドレスの設定
IPアドレス変わりまくるとめんどうですよねって話。 GCPコンソールの左上からメニューを開いて、「ネットワーキング」→「VPCネットワーク」→「外部IPアドレス」で、「静的アドレスを予約」をクリック。適当な名前を設定したらインスタンスと同じリージョンを選択して、接続先に先程作成したインスタンスを設定しましょう。
サーバー本体の設定
インスタンスを作成したら起動します。必要なものをインストールしていきましょう。 SSHで接続する。GCPのコンソールからでOK。「SSH」をクリッククリック。
# スーパーアカウントにする $ sudo su - # yumのアップデート $ yum update # 必要なものをそれぞれインストールする # Javaのインストール。JREあればOK。yum serach javaとかすれば出てくるはずなので自分にあうものをインストール。default-jreとか?とりあえずここではJDK $ yum install java-1.8.0-openjdk # バックグラウンドで動かしてほしいのでscreen $ yum install screen # 新しくディレクトリを作ってそこにサーバーをダウンロード $ cd /home $ mkdir minecraft $ cd minecraft $ curl -OL マイクラサーバーのURL # 初回起動からeula.txtの書き換え $ java -Xms1G -Xmx3G -d64 -jar server.jar nogui $ vi eula.txt # 変数eulaの値をfalseからtrueに。
これでOK。サーバーのURLは
Minecraft Server Download | Minecraft
で確認してやりましょう。
ファイアウォールの設定
Minecraftはデフォルトだとポート25565を使うので許可しておかないといけない(変更したければserver.propertiesを書き換え)。
「ネットワーキング」→「VPCネットワーク」→「ファイアウォールルール」を開き、「ファイアウォールルールを作成」する。ターゲットタグのところに、先程インスタンスに設定したネットワーキングタグを設定しておけばよい。ソースIPの範囲は0.0.0.0/0
、許可するのはtcp:25565
。これで作成すればOK。
インスタンスの起動、終了時に自動でMinecraftサーバーの起動、終了を行う
インスタンスの設定で、カスタムメタデータのところを編集すればOK。
startup-script
というキーで値を
cd /home/minecraft screen -d -m -S mcs java -Xms1G -Xmx3G -d64 -jar server.jar nogui
というものを作成する。これで起動時にサーバーの起動もしてくれる。
次にshutdown-script
というキーで
screen -r -X stuff '/stop\n'
を追加しておくことで、シャットダウン時にサーバーも正常に終了してくれるようになる。
バックアップ関係
今回ぼくの作ったサーバーでは、こまめにサーバーを起動したり終了したりするように設定しているので、shutdown-scriptのほうでバックアップのスクリプトを追記することでバックアップを行っている。これは各自好きなようにするとよいだろう。crontabとか使うところも多いのではないだろうか。
サーバー起動botの作成
次に、Discordのチャットを見てサーバーを起動するbotを作成した。使うのはPython3とGoogle API。 参考にしたのはここ。
ここのbot.py
を使わせてもらいました。
インスタンスの作成
こちらはDiscordを監視してコマンドが入力されるのを待っているだけなのでGCP無料分を使えばOK。「f1-micro」を使いましょう。リージョンとかも無料分のやつをよく確認して設定。OSも好みのやつを。ここではCentOS7。
APIのアクセスは、デフォルトアカウントでいいので完全アクセス権を許可しておく(このbotのみ動かすならcompute engine 許可されていればいいけれどまあ他の操作するbotも作るなら適宜変更)。ファイアウォールはHTTPトラフィックを使うので許可しておきましょう。
Botサーバーの設定
先ほどと同じように必要なものをインストールしていく。
$ sudo su - $ yum update # Python3の確認。 $ pyhton3 -V $ yum search python3.7 $ yum install python3.7 # 出てきたものをみて適宜変える。 # discord.pyを導入する $ python3.5 -m pip install -U discord.py # google APIを使うためのパッケージも導入 $ python3.5 -m pip install --upgrade google-api-python-client
Google Cloud SDKのインストール
ほとんど参考にした記事通りにやればいいのでほとんど割愛。ここではCentOS7を使っているのでwget
の代わりにcurl -OL
を使うことに注意。
また、gcloud init
では、GCEインスタンスを使っているのでデフォルトアカウントを選択(たぶん対話型設定で[1]を選択すればよいはず。)でOK。外部のコンピュータからgcloudを使う場合は面倒な手順(認証作業)があるようだけど、同プロジェクト内だし楽みたい。「warning」と出るかもしれないけど特に問題はない。auth認証も特にいらない。
Discord Botの作成
DiscordのBOTを作るには登録してこないといけない模様(当然)。おとなしくやります。
$ vi ~/.bash_profile $ export BOT_TOKEN='取得したトークン'
として登録しておくと、上記サイトの「bot.py」が使えるようになります。
botの起動
実際にbot.pyを動かしてみます。まずはサイトのやつをコピペさせてもらって(@thincellerさんに圧倒的感謝)、任意のフォルダに配置。そしたら、
nohup python3.5 bot.py&
で起動したままにできます。
2020/12/22 追記
2年たってこれを見直してみるといくつか問題があったので追記
問題1: pythonが動かない
discord.py
がアップデートされていて上記コードだと動かない!!新しくなったdiscord.py
用にコードを修正しました。コチラ↓
#!/usr/bin/env python3 import asyncio from time import sleep from googleapiclient import discovery import discord client = discord.Client() BOT_TOKEN = YOUR_TOKEN # Instance information PROJECT = 'YOUR_PROJECT' ZONE = 'YOUR_INSTANCE_ZONE' INSTANCE = 'YOUR_IUNSTANCE_NAME' # Build and nitialize google api compute = discovery.build('compute', 'v1') @client.event async def on_ready(): print('Logged in as') print(client.user.name) print(client.user.id) print('------') @client.event async def on_message(message): if message.content.startswith('/minecraft'): # ex.) message.content: '/minecraft start' => command: 'start' command = message.content.split(' ')[1] channel = message.channel if command == 'start': m = await channel.send('Server starting up...') start_server(PROJECT, ZONE, INSTANCE) await m.edit(content='Success! Server started up.') sleep(10) await m.delete() elif command == 'stop': m = await channel.send('Server stopping...') stop_server(PROJECT, ZONE, INSTANCE) await m.edit(content='Success! Server stopped.') sleep(10) await m.delete() elif command == 'status': status = get_server_status(PROJECT, ZONE, INSTANCE) if status == 'RUNNING': m = await channel.send('Server is running! Please enjoy Minecraft!') sleep(10) await m.delete() elif status in {'STOPPING', 'STOPPED'}: m = await channel.send('Server is stopped. If you play Minecraft, please chat in this channel, `/minecraft start`.') sleep(10) await m.delete() else: m = await channel.send('Server is not running. Please wait for a while, and chat in this channel, `/minecraft start`.') sleep(10) await m.delete() elif command == 'help': m = ''' ```Usage: /minecraft [start][stop][status] start Start up minecraft server stop Stop minecraft server status Show minecraft server status(running or stopped)``` '''.strip() await channel.send(m) def start_server(project, zone, instance): compute.instances().start(project=project, zone=zone, instance=instance).execute() def stop_server(project, zone, instance): compute.instances().stop(project=project, zone=zone, instance=instance).execute() def get_server_status(project, zone, instance): res = compute.instances().get(project=project, zone=zone, instance=instance).execute() return res['status'] client.run(BOT_TOKEN)
コレで動きました。
問題2: Pythonでエラーが出た時止まってしまう。
nohup
だとエラーがでると実行が止まって動かなくなってしまう。ってことでサービス化した。
/etc/systemd/system/mc-discord-bot.service
[Unit] Description = Discord bot deamon [Service] User = username ExecStart = /path/to/bot.py Restart = always Type = simple [Install] WantedBy = multi-user.target
bot.py
の権限、chmod
しておきましょうね
あとは起動
#!/bin/bash $ sudo systemctl reload $ sudo systemctl enable mc-discord-bot.service $ sudo systemctl start mc-discord-bot.service
できるようになったこと
GCP上に立てた有料インスタンスのMinecraftサーバーは、使ってないときはシャットダウンした状態。誰かが遊びたいときにDiscord上のテキストチャンネルで「/minecraft start」とすれば起動できるようになった。逆に、「/minecraft stop」とすればシャットダウンしてくれる。これで有料インスタンスを必要なときだけ起動できるようになったので、お金が節約できるようになった。よかった!