僕は Minecraft を遊んだことはないが最近知人からマイクラサーバを建ててほしいと頼まれたのでドキュメントを諸々読みながら GCE 上に建ててみた。
コマンド自体は Minecraft に限らず応用が効くと思うので将来のためにメモっておく。
最低限
CONTAINER_IMAGE="itzg/minecraft-server:java8"
INSTANCE_NAME="minecraft"
MACHINE_TYPE="e2-highcpu-2"
ZONE="asia-northeast1-a"
MEMORY="1500M"
DISK_AUTO_DELETE="no"
CONTAINER_ENV="\
EULA=TRUE,\
TZ=Asia/Tokyo,
MEMORY=$MEMORY\
"
gcloud compute instances create-with-container $INSTANCE_NAME \
--container-image $CONTAINER_IMAGE \
--machine-type $MACHINE_TYPE \
--zone $ZONE \
--container-env $CONTAINER_ENV \
--create-disk name=$INSTANCE_NAME-data,device-name=$INSTANCE_NAME-data,size=10GB,auto-delete=$DISK_AUTO_DELETE \
--container-mount-disk mount-path="/data",name=$INSTANCE_NAME-data \
--tags minecraft-server
gcloud compute firewall-rules create allow-minecraft \
--allow tcp:25565 --target-tags minecraft-server
(MACHINE_TYPE
、ZONE
、MEMORY
あたりは要件に応じて変えてください)
コマンドの意味は gcloud CLI リファレンス 1 を見れば全部書いてあるけれど順に解説していく。
create-with-container
まずサーバを建てるときに Docker イメージが公開されていたら嬉しいなと思って検索したら既に公開してくれている先人がいたので感謝しかないですね:
github.com
Tag に latest
を指定するとこの記事を書いている時点では Java 11 でサーバが起動するようだが個人的に latest
よりもバージョンは明示的に指定したいと思っているのと Java 15 は LTS ではないようなので java8
にした
(筆者は Minecraft にも Java にも詳しくないという事情もある)。
GCE では「Docker コンテナをデプロイして起動するように仮想マシン(VM)インスタンスまたはインスタンス テンプレートを構成でき」る 2 ので、これを使いましょう。
そのコマンドが
gcloud compute instances create-with-container INSTANCE_NAME \
--container-image CONTAINER_IMAGE
です。コマンドのリファレンスはこちら:
https://cloud.google.com/sdk/gcloud/reference/compute/instances/create-with-container
ちなみに各 VM インスタンスにデプロイできるコンテナは 1 つのみという制限 3 があり、
複数コンテナをデプロイしたい場合は Kubernetes (GKE) を使ってくださいということらしい。
さてこれでサーバは起動するのですが Minecraft はゲームなのでゲームデータという状態を持ち、その状態はコンテナ外のどこかに永続化したい。
上記の minecraft-server の README を読んでみるとホスト側のデータ保存用ディレクトリをコンテナの /data
ディレクトリにマウントすれば良いと書いてあり、
gcloud compute instances create-with-container
コマンドでは --create-disk
オプションを指定するとインスタンスの作成時と同時に永続ディスクを作成してインスタンスにアタッチすることができ、さらに
--container-mount-disk
オプションを一緒に指定することでその作成したディスクをコンテナの指定した path にマウントできる、のでそいつを使おうという寸法です。
ここで注意すべき点としては --container-mount-disk
でマウントするディスクはそのディスク名と device-name
(そのディスクの、OS が認識する名前(?)。詳しいことはよくわからない……)が同じでなければならない、ということです
(これらが異なるとマウントに失敗します)。
なので --create-disk
時に明示的に name
と device-name
に同じに名前を指定しています。
また auto-delete
はこのインスタンスが削除されたときに自動でこの永続ディスクも一緒に削除するかどうかを指定するフラグです。
これを no
に指定することで、誤ってインスタンスを削除してしまい今まで作ったワールドデータが全部吹っ飛んでしまう、というような事故を防ぎます。
デフォルト値は yes
なので、検証用に別のサーバを一時的に建てるというような場合は auto-delete
を指定する必要はないかもしれません。
--tags
は後述の firewall-rules
で説明します。
firewall-rules
無事マイクラサーバが建ってもクライアント側から接続できないと意味が無いので、マイクラ用のポートだけファイアウォールに穴を開けたいと思います。
さてガイドが存在して:
cloud.google.com
コンテナポートには、ホスト VM ポートへの 1 対 1 のマッピングがあります。たとえば、コンテナポート 80 はホスト VM ポート 80 にマップされます。Compute Engine ではポートの公開(-p)フラグをサポートしていないため、このフラグを指定しなくても、マッピングは機能します。
コンテナのポートを公開するには、ホスト VM インスタンスのポートへのアクセスを許可するようにファイアウォール ルールを構成します。コンテナの対応するポートには、ファイアウォールのルールに従って自動的にアクセスできるようになります。
具体的には create-with-container
時に --tags
オプションでインスタンスにタグを付け、firewall-rules create
でファイアウォールルールを作成し、そのルールを適用したい対象インスタンスのタグを --target-tags
オプションで指定すれば良いというわけですね。
https://cloud.google.com/sdk/gcloud/reference/compute/firewall-rules/create#--target-tags
Minecraft はデフォルトで 25565 番ポートを使用するようなのでそのポートのトラフィックを許可することにします。
これで無事マイクラサーバが順当に建ち、クライアントから接続して遊べるようになるでしょう。
--container-env
についてもう少し
Minecraft には op
権限を持つユーザという概念があるらしく、上述の minecraft-server Docker image では OPS
環境変数に Minecraft ユーザ名をカンマ区切りで指定することで op
権限を付与することができる 4 ので、 必要に応じて CONTAINER_ENV
に追加されたし。
また Minecraft 界隈ではサードパーティによる独自拡張である "mod" が多数公開されていて、複数の mods をクライアント・サーバに配置して遊ぶことがよく行われている(らしい)。
上述の minecraft-server Docker image では MODS
環境変数に jar ファイルの URL をカンマ区切りで指定するとコンテナ起動時に自動でその jar ファイルをダウンロードしてくれる 5 (便利ですね)。
ここで読者諸賢は --container-env=[KEY=VALUE, …,…]
という構文中で VALUE
としてナイーブにカンマを使うと KEY=VALUE
の組を分ける意味のカンマと衝突し構文エラーになることに気付くであろう。
実際 create-with-container
しようとすると以下のようにエラーが表示される:
ERROR: (gcloud.compute.instances.create-with-container) argument --container-env: Bad syntax for dict arg: [...]. Please see `gcloud topic flags-file` or `gcloud topic escaping` for information on providing list or dictionary flag values with special characters.
エラーメッセージが親切にも案内してくれているように gcloud topic escaping
を読んでみましょう:
https://cloud.google.com/sdk/gcloud/reference/topic/escaping
……なるほど!!!つまり --container-env=^DELIM^
と書くことで各 KEY=VALUE
同士の delemeter をカンマではなく DELIM
に変更することができるので、その上で VALUE
にカンマを含めることができるというわけですね。
DELIM
は :
とか -
のような一文字だけでなく ::
とか --
のような複数文字も許されています。MODS
に URL を指定することを考えると ::
あたりが良い選択肢ではないでしょうか。
具体例として今回僕は Buildcraft, Storage Drawers, Packing Tape という mod を入れることにしたので、 CONTAINER_ENV
は以下のようになりました:
CONTAINER_ENV="\
^::^\
EULA=TRUE::\
TZ=Asia/Tokyo::\
MEMORY=$MEMORY::\
TYPE=FORGE::\
MODS=\
https://edge.forgecdn.net/files/2502/739/buildcraft-7.1.23.jar,\
https://github.com/jaquadro/StorageDrawers/releases/download/sd-1.10.8/StorageDrawers-1.7.10-1.10.8.jar,\
https://github.com/gigaherz/PackingTape/releases/download/v0.3.5/Packing.Tape-0.3.5.jar::\
VERSION=1.7.10::\
OPS=pione30,foo_user,bar_user\
"
おわりに
具体例として Minecraft の話をしましたが Docker Hub に image が公開されていて環境変数の指定だけで設定を変えてスッと起動できる場合であればコマンド数本で手軽に GCE にインスタンスを建てられるんだな〜ということがわかったので良い収穫でした。
やはり Docker image を起点としてなるべく状態を持たないように起動できると検証用にサーバを建てたり壊したりするのが簡単かつ気軽にできて良いですね。