はじめに
こんにちは。陰キャ大学生です。
陰キャ大学生の私は友達がオンライン上にしかいません。そのため、よくオンラインゲームをします。今回はそのお話です。
大学生の私は生協マンションに住んでいるため、サーバーを立ててもポート解放できず遊べません。そのため、普段はAWSのEC2でサーバーを立てています。
このサーバーをボイスチャットツールのDiscordから起動及び停止できるようにすれば大変便利です。
それでは前置きが長くなりましたがどうぞ。
EC2の準備
概要
- discord-bot EC2 t2.microインスタンス
- game-server EC2 t2.largeインスタンス
システムの概略はこのような感じです。ここでのポイントは
- discordのレスポンス用とサーバー用に2つのインスタンスを用意
- それぞれのインスタンスはアカウント内セキュリティグループで管理
2つのインスタンスを用意する理由
お金がないからです。minecraftのサーバーを動かすには最低でも__t2.large__の性能(メモリ8GB)が必要になります。しかしDiscordのbotは常にアクティブにする必要があり、より高価な__t2.large__を常時起動するわけにはいかないからです。
インスタンスの設定
EC2のインスタンスの起動方法は多くの方が説明してくださっているので割愛します。
discord-bot
インスタンスタイプ:t2.micro
インバウンドルール:無編集でOK(SSHの22ポートのみ)
コンソール:AWSコマンドが使えること
discordのBOTはdiscord.pyを使用します。
どうしてPythonなのかというと、私が好きだからです。。
game-server
インスタンスタイプ:t2.large
インバウンドルール:TCP25565ポートを追加(Minecraft用)
実装
discordのbotアカウントの作成
こちらを参考に作成してください。
アクセストークンを控えておきます。
discord-botの作成
__discord-botインスタンス__で作業します。
SSH接続したターミナルで以下を実行します。
python3 -m pip install -U discord.py
メインのソースコードを記述します。今回は$start minecraft
と入力されたらサーバーを起動、$stop minecraft
と入力されたらサーバーを停止するようにします。
import discord
import subprocess
import paramiko
import time
# 自分のBotのアクセストークンに置き換えてください
TOKEN = 'your access token'
# game-serverのインスタンスidを指定してください
INSTANCEID = 'your instance id'
# 接続に必要なオブジェクトを生成
client = discord.Client()
# ***************************
# *** 処理関数
# ***************************
class DiscordBOT:
def __init__(self, client):
self.SSHClient = None
async def main(self, discord_event):
get_text = discord_event.content
send_text = ""
if "$start minecraft" in get_text:
# インスタンスの起動
subprocess.call("aws ec2 start-instances --instance-ids {}".format(INSTANCEID), shell=True)
time.sleep(3)
# インスタンスが起動するまで待機
subprocess.call("aws ec2 wait instance-running --instance-ids {}".format(INSTANCEID), shell=True)
time.sleep(3)
# インスタンスのIPアドレスを取得
proc = subprocess.run(["aws ec2 describe-instances --instance-ids {} --query 'Reservations[*].Instances[*].PublicIpAddress' --output text".format(INSTANCEID)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
ip_add = proc.stdout.decode("utf-8")
ip_add = ip_add.replace(".", "-").replace("\n", "")
self.server_ip = ip_add
time.sleep(3)
# SSH接続クライアント作成
self.SSHClient = paramiko.SSHClient()
self.SSHClient.set_missing_host_key_policy(paramiko.WarningPolicy())
self.SSHClient.connect('ec2-{}.compute-1.amazonaws.com'.format(ip_add), username='root', password='')
time.sleep(2)
# SSHでminecraftサーバー起動
stdin, stdout, stderr = self.SSHClient.exec_command("java -Xmx4096M -Xms4096M -jar server.jar nogui")
for x in stdout:
print(x)
for x in stderr:
print(x)
time.sleep(2)
# 接続用のIPアドレスをdiscordに送信
send_text = "インスタンスの起動とminecraftサーバーへの接続に成功しました。\n サーバー起動後は {} で接続できます".format(ip_add.replace("-", "."))
elif "$stop minecraft" in get_text:
# サーバーの停止
self.SSHClient.connect('ec2-{}.compute-1.amazonaws.com'.format(ip_add), username='root', password='')
time.sleep(2)
stdin, stdout, stderr = self.SSHClient.exec_command("stop")
self.SSHClient.close()
# インスタンスの停止
subprocess.call("aws ec2 stop-instances --instance-ids {}".format(INSTANCEID), shell=True)
send_text = "サーバーの停止が完了しました。"
if send_text:
await discord_event.channel.send(send_text)
discordbot = DiscordBOT(client)
@client.event
async def on_ready():
print('ログインしました')
# on get message
@client.event
async def on_message(message):
if message.author.bot:
return
await discordbot.main(message)
# Botの起動とDiscordサーバーへの接続
client.run(TOKEN)
これをEC2上で実行すれば完成です。
nohup python3 main.py &
game-serverの設定
javaをインストールする必要があります。
こちらを参考にしてください。
さらにはrootユーザーのホームディレクトリにminecraftのサーバースクリプト(server.jar)を保存しておきます。
また、SSH接続を公開鍵認証を用いて行いますのでそちらの設定を行います。
こちらもすでに記事がありますので紹介させていただきます。
EC2インスタンス間でSSHパスワードなしでログインする方法
セキュリティグループの設定
いまのままでは、awsコマンドによっての遠隔起動ができません。そのためそれを許可するためにそれぞれを同じセキュリティグループに入れてやる必要があります。
この__IAM ロールの割り当て/置換__を選択
新しいIAMロールを作成後、それぞれのインスタンスを同じIAMロールに追加して準備完了です。
結果
無事に動きました。めでたしめでたし。