Afternoon Log

日々のことや、技術的な備忘録を吐き出していくつもり

マイクラサーバ構築とdiscordへのログイン通知

こんにちはこんばんは、おはようございます。

3月4月と更新が空いてしまっています。
愚かな……。
そしてGW最終日です。まぁ、有給を+2取っているので僕はもう少し続くんですが。

閑話休題


このGWにマイクラをやってみました。
AWSでサーバを立てて、通知をdiscordに飛ばすってことをやったので、
それを少々記事として残しておこうと思います。

サーバ構築

まずはAWS EC2でサーバ用インスタンスを用意します。
ググれば構築の仕方は沢山ありました。
ただ、まぁ、あまり複雑なことまで書いてなかったので
イクラ用にVPCやInternet Gateway、サブネットの用意とかGUIでポチポチするのが意外と手間でした。
サブドメインにElastic IP を割り当てて、ホスト名解決できるようにしました。
一応3,4人同時にできるようにスペックは以下の様に設定しましたが、恐らく少々過剰かもしれません。

項目
インスタンスタイプ t2.medium
CPU 2 core
RAM 4GB
ボリューム 20GB

インスタンスを用意したら、サーバへSSHして環境構築を進めます。

# AWSから秘密鍵をダウンロードして、配置&権限を正します
$ mv ./Downloads/秘密鍵 ~/.ssh/
$ chmod 600 ~/.ssh/秘密鍵

$ ssh ssh ec2-user@ホスト名 -i ~/.ssh/秘密鍵

# JDKのインストール
$ yum search openjdk
$ sudo yum install java-1.8.0-openjdk
$ java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-b08)
OpenJDK 64-Bit Server VM (build 25.282-b08, mixed mode)

# 無くても良いけど、実行ユーザー作成
## 因みに、後ほどこれめんどいなってなってます。
$ sudo adduser minecraft
$ sudo su minecraft
$ cd

# マイクラ準備
$ mkdir minecraft
$ cd minecraft
$ wget https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar
$ echo '#!/bin/sh

java -Xmx1024M -Xms1024M -jar server.jar nogui' > start.sh
$ chmod +x start.sh

ググると、screenを利用しているパターンが沢山ありますが
バックグラウンド実行のためだけだったらデーモンプロセス化で良いかなって思って入れてません。
(勿論利用する恩恵はあるとは思うのだけど、一旦そこまで考えていないので……)

デーモンプロセス化するために次のファイルを用意します。
serviceファイルに関しては全然詳しくないので、粗があったらご指摘頂きたいです。

/etc/systemd/system/multi-user.target.wants/minecraft.service

[Unit]
Description=Minecraft Server
After=network-online.target

[Service]
Type=simple
ExecStart=/bin/sh start.sh
WorkingDirectory=/home/minecraft/minecraft
Restart=always
User=minecraft
Group=minecraft

[Install]
WantedBy=multi-user.target

UserやGroupは先ほど作成したユーザーを指定しています。
また、ExecStart は今回通知を仕込むためのスクリプトを用意したので起動はシェルスクリプトを介する形にしています。
この実行ユーザーはsudoできないので、一旦ログアウトして起動できるか確かめて見ます。

# minecraft ユーザーからログアウト
$ exit

# 起動
$ sudo systemctl start minecraft.service
# status確認
$ sudo systemctl status minecraft.service

# 因みにサービス停止はこれ
$ sudo systemctl stop minecraft.service

無事に起動出来たら、eula.txtがserver.jarと同一ディレクトリに作成されていると思うので、
eula=trueに変更します。
サービス停止をしてから、再度startするとマイクラサーバが起動するはずです。
もしダメだったら、色々と頑張ります。手順から抜け落ちていたらごめんなさい。

discord通知

次にお試しでログイン通知をdiscordへ流して見ます。
スクリプトはNode.jsを利用して作成します。

# nodejsをインストール
$ sudo yum install https://rpm.nodesource.com/pub_12.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm
$ sudo yum install nodejs
$ node --version
v12.22.1

# minecraftへ切り替え
$ sudo su minecraft
$ cd

# 任意(NPMライブラリを利用したい場合)
## 今回はHTTPリクエストにaxiosを利用するのと、bot化もしたかったのでinitしました
$ npm init

ここからガリガリと通知するためのコードを書いていきます。
まずは、環境変数から設定値を取得します。
config.js

'use strict';

const WEBHOOK_URL = process.env.WEBHOOK_URL ? process.env.WEBHOOK_URL : '';
exports.WEBHOOK_URL = WEBHOOK_URL;

// const TOKEN = process.env.TOKEN ? process.env.TOKEN : '';
// exports.TOKEN = TOKEN;

// const BOT_NAME = process.env.BOT_NAME ? process.env.BOT_NAME : 'sample-bot';
// exports.BOT_NAME = BOT_NAME;

// const CHANNEL = process.env.CHANNEL ? process.env.CHANNEL : '';
// exports.CHANNEL = CHANNEL;

webhookだけならURLだけなので別ファイルに分ける必要は薄いですが、
癖もありますし、botのためのもの(コメントアウトしてます)も書いているので分けています。

次にメインとなるロジックを用意します。
discord-logger.js

'use strict';

process.stdin.resume();
process.stdin.setEncoding('utf8');

const { WEBHOOK_URL } = require('./config');

const axios = require('axios');
// const Discord = require('discord.js');
// const client = new Discord.Client();

// ログインユーザー
// const activeUser = new Set();

// 標準入力監視
process.stdin.on('data', async (input) => {
  let postMessage = '';
  let color = 'FFFFFF'

  if (input.includes('joined the game')) {
    postMessage = `${input.split(' ')[3]} が入室しました. :wink:`;
    color = '37b24d';
    // activeUser.add(input.split(' ')[3]);
  } else if (input.includes('lost connection: Disconnected')) {
    postMessage = `${input.split(' ')[3]} が退室しました. :wave:`;
    color = 'f4aa41';
    // activeUser.delete(input.split(' ')[3]);
  } else {
    return;
  }
  await axios.post(WEBHOOK_URL, {
    username: 'micra-log',
    embeds: [
      {
        title: postMessage,
        color: parseInt(color, 16)
      }
    ]
  });
});

javaコマンドで起動したマイクラサーバの標準出力をパイプでこのスクリプトに流してやる想定です。
なので process.stdinを利用して、都度入力受け取った際に処理を走らせます。
入退出の判定は、単純に文字列を見ています。
ただこのままだと、稀に名前[IPアドレス]が出力されたので、もう少し処理があったら良いでしょう。
そして、discordに送る時は引用を利用してメッセージを送っています。
こうすると色を付けられて分かりやすいかなと思いました。
コメントアウトしている箇所は、botのために書いたところです。

実際にログイン、ログアウトするとこんな感じの表示になります。

f:id:mura_elma:20210505185229j:plain

最後に、先に用意したstart.shを次の様にパイプにて渡すように書き換えます。
あ、discordのチャンネル設定からWEBHOOKのURLを発行しておくのを忘れずに。

#!/bin/sh

java -Xmx1024M -Xms1024M -jar server.jar nogui | WEBHOOK_URL=WEBHOOKのURL node discord-logger.js

これで標準入力から文字列判定して、接続/切断時にdiscordへ投稿できるようになりました。


※ 注意点として、マイクラの標準出力をそのままdiscordへ投げるのはやめましょう。
大量にHTTPリクエストを送ることはDoS攻撃にもなり得るので、想定したものだけ投稿する形にしましょう。



ところで、
イクラやってると度々クライアント落ちるんですが、落ちすぎじゃないですか?
僕のPCスペックのせい……?