Palworld Server を AWS Fargate Spot で安く運用する

AWS で Palworld Dedicated Server を Fargate で作成する手順です。
なるべく安く、手軽に運用できるようにしてみました。

# 概要
構成、必要なもの、手順、コストについて

### 構成概要
![aws_architecture.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3346823/8cf27220-3a82-81e5-8f3e-2cd6c4304c83.png)

### 必要なもの

- AWSアカウント
- 独自ドメイン
- 管理者としてアクセス出来るSlackアカウント

### 構築手順概要

1. Route53 のホストゾーンを作成
2. AWS Chatbot と Slack の連携設定
3. AWS にて環境を展開
4. Slack のコマンド設定

### サーバーの起動方法

1. Slack から起動コマンドを実行
2. 起動後 Slack からメッセージが届く
3. Palworld がプレイ可能になる
4. 誰も接続していなければ20分後に自動で終了

### コスト
大きめのコンピュートリソースを使用した場合、vCPU:4, Memory:16GB で月に20時間起動すると通常のFargateで月額1,000円くらいでしょうか。Fargate Spot だと更に安く運用できます。
参考：https://calculator.aws/#/estimate?id=d5fa8ecb8c40cbe23b35fb62eb6fb90f893f3f36

# 構築手順
作業は AWSマネジメントコンソール、Slack での設定になります。

## Route53
取得している独自ドメインのホストゾーンが１つ設定されていれば良いです。
素の状態だと、SOA, NSレコードの２つ存在しているかと思います。

## AWS Chatbot
AWS Chatbot にてすでに持っている Slack との連携をします。
参考：https://docs.aws.amazon.com/chatbot/latest/adminguide/slack-setup.html

## 環境を展開
AWSマネジメントコンソールから AWS CloudShell を開いて以下のコマンドを実行します。

### git clone

```
git clone https://github.com/coni524/palworld-ondemand.git
```

### .env ファイルを編集
デフォルトでは Fargate Spot を利用するようになっていますが、"USE_FARGATE_SPOT = false" にすれば通常のFargate でも起動出来ます。

```
cd palworld-ondemand/cdk/
cp -p .env.sample .env
vi .env
```

必要なフィールド

- **DOMAIN_NAME**: Route53 に設定したゾーンのドメイン
- **SLACK_WORKSPACE_ID** : AWS Chatbot の Workspace ID 
- **SLACK_CHANNEL_ID**: Slack の Channel ID
- **ADMIN_PASSWORD**: RCON のパスワード（接続中ユーザー数確認のため内部的に利用します）
- **SERVER_PASSWORD**: Palworld の Password
- **SERVER_REGION**: ap-northeast-1 など

.envの例

```
# Required
DOMAIN_NAME                   = example.net
SLACK_WORKSPACE_ID            = T07123456
SLACK_CHANNEL_ID              = C06J8123456
ADMIN_PASSWORD                = worldofpalrcon
SERVER_PASSWORD               = worldofpal
SERVER_REGION                 = ap-northeast-1
```

### ビルド＆デプロイ
AWS CloudShell での実行で遅いため数分かかります。

```
# palworld-ondemand/cdk/ にいる状態で
npm run build && npm run deploy
```

### Slack のエイリアスコマンドの登録
Slack からの起動を簡略化するためにコマンドエイリアスを設定します。

AWS Chatbot と連携するためにチャンネルに @aws を招待します。

```
/invite @aws
```

AWSマネジメントコンソールの us-east-1 にて "〜LauncherLambda〜" という名前の Lambda 名を "--function-name" に指定します。"--region" は "us-east-1" で固定です。

```
@aws alias create palworld lambda invoke --function-name ＜Functionname＞ --region us-east-1 --payload {}
```

### Palworld の起動
Slack から以下のコマンドを実行します。
コマンド実行後、確認のメッセージが届きますので、"[Run] command" ボタンを押します。

```
@aws run palworld
```

### Palworld Server へ接続
数分後、起動が完了すればSlackにメッセージが届けば、Palworldクライアントから接続可能です。
palworld.example.net:8211 などの指定で接続出来ます。

# 停止方法
接続数が 0 の状態が20分続くと自動で Fargate はシャットダウンされます。
EFS にデータは保存しているので、次回起動時もワールド情報は維持されています。

手動で停止する場合は、AWSマネジメントコンソールからECSサービスの Desired Count を 0 にしてください。

# 環境の削除方法
cdk destroy で削除できない場合は、us-east-1, ap-northeast-1(SERVER_REGIONで指定したリージョン) の 対応する Cloudformation を手動で削除します。

# その他

### Fargate Spot について
Fargate Spot で起動した場合、不意のシャットダウンはあります。
ワールドデータは EFS にデータ保存されていますが、通常の Fargate で起動すれば不意のシャットダウンは通常ありません。

### 停止する仕組みについて
自動で停止仕組みは、Palworld コンテナのサイドカーとして起動している監視用コンテナから、RCON を利用してユーザー数をチェックする方法で実装しています。ただ、万が一、起動し続ける可能性もありますので、Billing アラートの設定などもしておくことをおすすめします。

### 元にしている CDK からの主な変更箇所

1. 起動方法の変更
元々参考にしている AWS CDK の環境では、Route53 にクエリがあると自動で Fargate を起動する仕組みでしたが、Aレコードへのアクセスは全世界の誰でも可能で、実際に、意図しない起動があったため無効にし、Slack からのみ起動できるように変更しています。

2. SNS Email -> Slack への変更
起動時に AWS SNS からメールが届くようになっていた部分は Slack へ送るように変更しています。
Slack 側の設定をできるだけ行いたくなかったため、Lambda からではなく、AWS Chatbot からの連携にしています。

3. 接続ユーザー数確認方法の変更
Minecraft は TCP 接続のため、netstat で拾うことはできるようですが、Palworld は UDP を利用するためできませんでした。そのため、同時に起動する監視用コンテナにて、RCON を実行して接続中のユーザー数を取得しています。

# git
以下のプロジェクトで公開しています。
ドキュメントは完全ではないので更新を続けて参ります。
https://github.com/coni524/palworld-ondemand

# 参考
以下のプロジェクトのコンテナイメージやCDKを利用させて頂きました。
AWS上のシステムはほぼ doctorray117/minecraft-ondemand のプロジェクトを利用しており、Minecraft 向けの設定を Palworld 向けに変更しています。

AWS CDK: https://github.com/doctorray117/minecraft-ondemand
Palworld Container Image: https://github.com/thijsvanloef/palworld-server-docker

# 追記

### AWS当月料通知について
当月のAWS料金を通知する仕組みを追加しました。デフォルトで6時間毎に Slack へ通知されます。
AWS Cost Explorer の更新は 24時間後になるため、頻繁なチェックはあまり意味がありません。
https://docs.aws.amazon.com/ja_jp/cost-management/latest/userguide/ce-what-is.html

### Fargate の ARM64 対応について
ここまで来たら意地でも安くしてみようということで、以下のような設定に変更しました。
この変更により、通常の Fargate 起動でも X86_64 と比べ 20% のコストオフで起動できます。
.env を変更して、"USE_FARGATE_SPOT" のパラメーターを変更して起動しても、引き続き同じ状態のワールドデータで起動出来ることを確認しています。

- Fargate SPOT 起動の場合 Fargate(X86_64) で起動
- Fargate（通常）起動の場合 Fargate(ARM64) で起動