11
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Organization

DiscordからMinecraftサーバーを立ち上げた話

はじめに

こんにちは。陰キャ大学生です。
陰キャ大学生の私は友達がオンライン上にしかいません。そのため、よくオンラインゲームをします。今回はそのお話です。

大学生の私は生協マンションに住んでいるため、サーバーを立ててもポート解放できず遊べません。そのため、普段はAWSのEC2でサーバーを立てています。

このサーバーをボイスチャットツールのDiscordから起動及び停止できるようにすれば大変便利です。

それでは前置きが長くなりましたがどうぞ。

EC2の準備

概要

image.png

  • 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コマンドによっての遠隔起動ができません。そのためそれを許可するためにそれぞれを同じセキュリティグループに入れてやる必要があります。

image.png

このIAM ロールの割り当て/置換を選択

image.png

新しいIAMロールを作成後、それぞれのインスタンスを同じIAMロールに追加して準備完了です。

結果

daw.png

image.png

無事に動きました。めでたしめでたし。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
11
Help us understand the problem. What are the problem?