Minecraft統合版サーバをAWSのサーバレス環境に移行(構築編)

2023/11/05

AWS Minecraft

t f B! P L

前回の記事からだいぶ期間が空いたけど・・・

Minecraft統合版サーバをAWS ECS環境に実装したときの話。

以前は概要編で、今回は構築編。

実際にAWSで操作する手順を書きます。


前回の話は↓


その0:必要なAWSリソース

構築の前に必要なAWSリソースを説明。

構成図を再掲。


必要なリソースは以下。順不同

  • Route53
  • CloudWatch
  • SNS
  • Lambda
  • ECS/Fargate
  • EFS
  • Backup
  • S3(オプション)
  • DataSync(オプション)

サーバの構成はECS/Fargate、永続ストレージにEFS、

あとはサーバ起動/停止にLambda、

起動トリガー用にRoute53、Cloudwatch、起動停止の通知にSNS。

S3とDatasyncはオプションなので必須じゃない。


その1:VPC作成

ECS/EFSを配置するためにVPCを作成する。

デフォルトVPCがあるのなら、それでもOK。

ここでは適当に以下のように。

CIDR:適当

パブリックサブネット:2つ

プライベートサブネット:2つ

NATゲートウェイ:無し


EFSもパブリックサブネットにおいてもいいのなら、プライベートサブネットは不要かな。

個人利用ならAZも1つでいいんじゃないかと。


その2:EFS作成

データを置くためのストレージ(EFS)を作成。

EFSにて「ファイルシステムの作成」をクリック。


名前:適当

ストレージクラスもここでは「標準」にしているけど、さらに低コストにするのなら「1ゾーン」でもいいかも。


他はそのままで「次へ」をクリック。


マウントターゲットをどのサブネットに置くかを指定。

ここではプライベートにしている。

あ、セキュリティグループを作成してないのなら、あとでNFSを許可するセキュリティグループに変更w


ファイルシステムポリシーはそのままで「次へ」をクリック。


確認して作成。


ファイルシステム作成。


続けてアクセスポイントを作成する。

「アクセスポイント」に移動して、「アクセスポイントを作成」をクリック。


ファイルシステムは先ほど作成したファイルシステム、

名前は適当、ルートディレクトリは「/minecraft」にする。

POSIXユーザーID・グループIDは「1000」を指定する。


次の所有者ユーザーID・グループIDも「1000」、

アクセス許可は「0755」を指定して「アクセスポイントを作成」をクリック。


アクセスポイント作成完了。


先ほどのファイルシステム作成でEFSのセキュリティグループをデフォルト(any/any)にしてしまったので、

新たにEFS用のセキュリティグループを作成。

VPCからセキュリティグループ作成画面に移り、以下のように作成。

タイプ:NFS(2049/tcp)

ソース:最低でもパブリックサブネットを含むように


作成したセキュリティグループに変更する。

EFSのファイルシステム画面に戻って、対象のファイルシステムを選択して、「詳細の表示」をクリック。


「ネットワーク」タブの「管理」をクリック。


セキュリティグループがデフォルトになっているのを・・・


作成したセキュリティグループに変更する。


最後に作成したアクセスポイントARNとファイルシステムIDを控える。

次のIAMポリシー作成に必要なため。


その3:Route53設定

DNSの設定。

まずはパブリックホストゾーンを作成する。


作成したゾーンのネームサーバをドメインのレジストラに登録する。


次に「クエリログの設定」をクリックする。


ロググループを新規作成する。


最後に作成したホストゾーンIDを控える。


その4:SNS設定

SNSの設定。

まずはSNSトピックを作成する。

名前は適当w


次にサブスクリプション(SNSの通知先)を作成する。

トピックARNは先ほど作成したSNSトピック。

プロトコルはEメールもしくはSMSかな。


その4:IAMポリシー、IAMロール設定

ECSタスクが実行するためのIAMポリシー、IAMロールを作成する。

まずはIAMポリシー。

ポリシー名:efs.rw.minecraft-data

EFSのファイルシステムIDとアクセスポイントのARNをここで入力。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:ClientMount",
        "elasticfilesystem:ClientWrite",
        "elasticfilesystem:DescribeFileSystems"
      ],
      "Resource": "arn:aws:elasticfilesystem:ap-northeast-3:zzzzzzzzzzzz:file-system/fs-xxxxxxxx",
      "Condition": {
        "StringEquals": {
          "elasticfilesystem:AccessPointArn": "arn:aws:elasticfilesystem:ap-northeast-3:zzzzzzzzzzzz:access-point/fsap-xxxxxxxxxxxxxxxxx"
        }
      }
    }
  ]
}


ポリシー名:ecs.rw.minecraft-service

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ecs:*"],
      "Resource": [
        "arn:aws:ecs:ap-northeast-3:zzzzzzzzzzzz:service/minecraft/minecraft-server",
        "arn:aws:ecs:ap-northeast-3:zzzzzzzzzzzz:task/minecraft/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["ec2:DescribeNetworkInterfaces"],
      "Resource": ["*"]
    }
  ]
}


ポリシー名:route53.rw.yourdomainname

ここでは作成したRoute53のホストゾーンIDを記入。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:GetHostedZone",
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets"
      ],
      "Resource": "arn:aws:route53:::hostedzone/XXXXXXXXXXXXXXXXXXXXX"
    },
    {
      "Effect": "Allow",
      "Action": ["route53:ListHostedZones"],
      "Resource": "*"
    }
  ]
}


ポリシー名:sns.publish.minecraft-notifications

ここでは作成したSNSトピックのARNを記入。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:ap-northeast-3:zzzzzzzzzzzz:minecraft-notifications"
    }
  ]
}


次にIAMロールを作成する。

信頼されたエンティティは「Elastic Container Service Task」を選ぶ。


ポリシーは先ほど作成した4つを設定。

名前はなんでもいいけど、「ecs.task.minecraft-server」とした。


その5:ECSクラスター作成

次にコンテナを動かすための基盤、ECSクラスターを作る。

ECSより「今すぐ始める」をクリック。


「クラスターの作成」をクリック。


クラスター名:minecraft

VPC:その1で作成したVPC

サブネット:パブリックサブネット2つ


で、作成する。


作成完了。


その6:タスク設定

コンテナを動かす実行環境(タスク)の設定。

「タスク定義」をクリックし、「新しいタスク定義の作成」をクリックする。


タスク定義ファミリー:minecraft-server

コンテナ名:minecraft-server

イメージURI:itgz/minecraft-bedrock-server

コンテナポート:19132

プロトコル:UDP

キー:EULA 

値:TRUE


スペックは任意。俺の場合は余裕を持って以下にした。

OS/アーキテクチャ:Linux/X86_64

CPU:1vCPU

メモリ:6GB

タスクロール:ecs.task.minecraft-server

タスク実行ロール:ecsTaskExecutionRole


次にボリュームの設定。

ボリュームタイプ:EFS

ボリューム名:data

ファイルシステムID:EFSで作成したファイルシステム

ルートディレクトリ:/

アクセスポイントID:-(何も指定しない)

コンテナマウントポイント:/data


ログ収集は任意だけど、CloudWatchにしておくとコンテナのログが表示される。


同じ要領で監視用のコンテナを設定する。

コンテナ名:minecraft-ecsfargate-watchdog

イメージURI:doctorray/minecraft-ecsfargate-watchdog

環境変数:

 CLUSTER:minecraft(ECSクラスタ名)

 DNSZONE:XXXXXXXX(Route53のゾーンID)

 SERVERNAME:サーバのFQDN名(minecraft.hogehoge.comとか)

 SERVICE:minecraft-server(上記で設定したコンテナ名)

 SNSTOPIC:XXXXXX(SNSトピックのARN)


次に作成した定義にチェックを入れ、デプロイ→「サービスの作成」をクリックする。


既存のクラスター:minecraft

コンピューティングオプション:キャパシティープロバイダー戦略

キャパシティープロバイダー:FARGATE_SPOT

を選ぶ。


サービス名:minecraft-server

必要なタスク:0

を選ぶ。


VPC:作成したVPC

サブネット:パブリック

セキュリティグループ:19132/UDPを許可

パブリックIP:オン


これでサービスが作成された。


まだこの状態ではコンテナ(=タスク)は起動していない。


その7:Lambda作成

タスクを起動するためのLambda関数を作成する。

この関数はRoute53からイベントをトリガーにしてCloudWatchが起動する関数でもあるから、

バージニア北部リージョンで作成すること。

コードは以下の通り。

import boto3

REGION = 'ap-northeast-3'
CLUSTER = 'minecraft'
SERVICE = 'minecraft-server'

def lambda_handler(event, context):
    """Updates the desired count for a service."""

    ecs = boto3.client('ecs', region_name=REGION)
    response = ecs.describe_services(
        cluster=CLUSTER,
        services=[SERVICE],
    )

    desired = response["services"][0]["desiredCount"]

    if desired == 0:
        ecs.update_service(
            cluster=CLUSTER,
            service=SERVICE,
            desiredCount=1,
        )
        print("Updated desiredCount to 1")
    else:
        print("desiredCount already at 1")


リージョンとクラスタ名とサービス名を指定するだけ。

ちなみに"if desired == 0"と"desiredCount=1"の数字をそれぞれ逆にすると

サーバを停止する関数になる。


API Gatewayを挟むなり、関数URLを作成して関数化するなりすれば、APIで起動停止ができるようになる。


その8:CloudWatch設定

先ほど作成したLambda関数を実行するためのトリガーを作成する。

つまり、Route53のクエリログが出力されたら、Lambdaを実行するようにする。

バージニア北部のCloudWatchに移動して、Route53のクエリログをチェックする。

アクションから「サブスクリプションフィルター」→「Lambdaサブスクリプションフィルターを作成」をクリックする。


Lambda関数:先ほど作成したLambda関数

サブスクリプションフィルターのパターン:"<サーバのFQDN名>"

サブスクリプションフィルター名:任意


作成後、Lambda関数に戻り、トリガーに「CloudWatch Logs」が追加されていればOK。


その9:動作確認

以上で一通りの設定は完了。

Lambdaを実行するなり、サーバのFQDNにcurl等でアクセスを行ってみる。

すると、ECSサービスのタスクが"実行中"になる。


タスクを確認すると、実行中となっていることがわかる。


ログを確認すると、コンテナが起動していることがわかる。


パブリックIPも割り当てられている。


このパブリックIPはタスクが起動するたびにコロコロ変わるので、

Route53にゾーン登録できるドメインを持っていなければ、ここで逐次IPアドレスを確認する必要がある。


あとはMinecraftのクライアントから接続すればOK。


おまけ:いくらかかった?

10月はこんな感じ。約$6ということで900円くらい。

おそらく数時間程度しか使っていないと思う。

EFSのマウント確認にEC2を立てたりしたので、余計なコストも混じっているかもしれないw


x86ベースになっているのか、OCIのコンテナ環境よりも遥かに快適になった。

起動停止スクリプトをLambdaの関数URLに設定して、

iPhoneのショートカットからcurlするようにすれば

起動に時間がかかるものの普通に遊べるレベル。


AWSクレジットがいくらを登録しているので、多少費用が発生しても問題無し。

今のところは大きな課金も発生しておらず安定して動かしている。


この仕組みを考えた人天才だわ〜。

検索

Blog Archive

Popular Posts

About Me

自分の写真
性別:男
年齢:ついに40over
趣味:Snowboard、パソコン、iPhone、子育て

仕事:ユー子の社内SEとしてサーバ、NW等のインフラ全般をやってます

日々生活していく中で思ったことなどをつらつらと書いていきます。

どうぞよろしく!

ブログランキング

ブログランキング・にほんブログ村へ

QooQ