【GCP】Minecraft 1.17のサーバをGCEに建てる

# Minecraftサーバを構築

初投稿です
2021/6/9、Minecraft v1.17リリースに伴ってサーバを新しく構築する
多分全く参考にならないけど、自分用メモとして。

## なんと
GCP公式の「GCE上にMinecraftサーバを作る」ドキュメントが消えていた、、 
(※リンクは残ってるけどページがない、、) 
なので記憶を頼りに(ほとんどカンニングしながら)、アレンジを加えて一から自分で作成するぜ

## terraformでインスタンス起動

- スペック


|               項目 | 値        |
| :-----------------: | :-------------- |
| インスタンスタイプ | e2-standard-4   |
|OS|CentOS 8 Stream|
|           ディスク | pd-standard     |
|       ディスク容量 | 20GB            |
|         リージョン | asia-northeast1 |
| プリエンプティブル | オン(重要)      |

- プリエンプティブルインスタンスとは
  - 24時間で必ず停止
  - 突然停止するかもしれない
  - その代わりめっちゃ安い
  - e2-standard-4 : \$0.053/hくらい (普通は\$0.174/h)

```tf:main.tf
# VPCとサブネットは省略します

# GlobalIP
resource "google_compute_address" "mcs-ip" {
  name         = "mcs"
  description  = "external IP for mcs"
  network_tier = "STANDARD"
  region       = "asia-northeast1"
}

# Minecraft Game Server
resource "google_compute_instance" "minecraft-game-server" {
  machine_type = "e2-standard-4"
  name         = "mcs"
  project      = /*PROJECT_NAME*/
  tags         = ["minecraft-server"]
  zone         = "asia-northeast1-b"
  boot_disk {
    auto_delete = true
    device_name = "mcs"
    mode        = "READ_WRITE"
    initialize_params {
      image  = "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-stream-8-v20210512"
      labels = {}
      size   = 20
      type   = "pd-standard"
    }
  }

  network_interface {
    network    = google_compute_network.vpc.name
    network_ip = "10.0.0.3"
    subnetwork = google_compute_subnetwork.subnet.name
    access_config {
      nat_ip       = google_compute_address.mcs-ip.address
      network_tier = "STANDARD"
    }
  }

  service_account {
    email = "565378471472-compute@developer.gserviceaccount.com"
    scopes = [
      "https://www.googleapis.com/auth/cloud-platform",
    ]
  }

  #preemptible設定
  scheduling {
    preemptible       = true
    automatic_restart = false
  }
}

# allow 25565 for minecraft
resource "google_compute_firewall" "allow-mcp" {
  name    = "allow-mcp"
  network = google_compute_network.vpc.name
  allow {
    protocol = "tcp"
    ports    = ["25565"]
  }
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["minecraft-server"]
}
```

- apply する

```
$ terraform apply
```

## サーバ内作業

### とりあえず

```shell
# dnf -y update
```

### wgetを入れる

```
# dnf -y install wget
```

### サーバDL

```
# useradd minecraft
# sudo su - minecraft

公式サイトからURLコピーしてくる
$ wget https://launcher.mojang.com/v1/objects/0a269b5f2c5b93b1712d0f5dc43b6182b9ab254e/server.jar
```

### 初回起動(失敗!)

```
$ java -jar server.java nogui
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: net/minecraft/server/Main has been compiled by a more recent version of the Java Runtime (class file version 60.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:601)
エラー出た、、

$ java -jar server.jar --nogui
Error: LinkageError occurred while loading main class net.minecraft.server.Main
        java.lang.UnsupportedClassVersionError: net/minecraft/server/Main has been compiled by a more recent version of the Java Runtime (class file version 60.0), this version of the Java Runtime only recognizes class file versions up to 55.0
java-11-openjdkでもNG
NGか、、
```
1.8.0のOpenJDKはオワコンになってしまったようだ、、
    →v11.0.11にする
        →v11.0.11もオワコンになってしまったようだ
→あきらめてソースインストールする

### OpenJDKインストール

```
# cd /usr/local/src
# wget https://download.java.net/java/GA/jdk16.0.1/7147401fd7354114ac51ef3e1328291f/9/GPL/openjdk-16.0.1_linux-x64_bin.tar.gz
# tar xzvf openjdk-16.0.1_linux-x64_bin.tar.gz 
# mv jdk-16.0.1 /usr/local/jdk
# cd /usr/local/bin
# ln -s /usr/local/jdk/java java

$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment (build 16.0.1+9-24)
OpenJDK 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)
```

### 初回起動

```
$ java -jar server.jar --nogui
[11:10:14] [main/WARN]: Failed to load eula.txt
[11:10:14] [main/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
```
OK.

### End User Lisence Agreement に同意

```
$ sed -i -e 's/false/true/g' eula.txt
```

### サーバ実行

```
$ java -jar -Xms4G -Xmx6G server.jar nogui
```

### DNS登録

わざわざしなくてよいが、、

### 接続確認

ゲーム起動して接続してみる

## screen設定

### インストール

```
なんと dnf でインストールできなくなってるのでソースから、、
make , gcc ,ncurses あたりがいるみたいなのでdnfインストールしておく

# dnf -y install make ncurses-devel

ソースをDL
# cd /usr/local/src && wget http://ftp.gnu.org/gnu/screen/screen-4.8.0.tar.gz
解凍
# tar xzvf screen-4.8.0.tar.gz
# cd screen-4.8.0
コンパイル
# ./configure
# make
パス通し
# cd ../
# mv screen-4.8.0 /usr/local/screen
# ln -s /usr/local/screen/screen screen
```

### 確認

```
$ screen
GNU Screen version 4.08.00 (GNU) 05-Feb-20

Copyright (c) 2018-2020 Alexander Naumov, Amadeusz Slawinski
Copyright (c) 2015-2017 Juergen Weigert, Alexander Naumov, Amadeusz Slawinski
...

[Press Space or Return to end.]
```
Enter → Ctrl + D で抜ける

### screen上でサーバ起動確認

```
$ screen -S mcs java -Xms4G -Xmx4G -jar server.jar nogui
```
Ctrl + A → D で戻れる(覚えてたｗ)

## startup-script,shutdown-script関連

ここまででゲームは問題なくできるようになったので、  
自動起動、自動バックアップを入れる
ここは完全にカンニングさせていただきました。
参考:[GCP初心者がGCEでマイクラサーバを建ててみた話](https://qiita.com/rodotan/items/f5d7f76a1bc9b34ab717)

### 起動スクリプト

```sh
#!/bin/bash
(crontab -l | grep -v -F "/home/minecraft/backup.sh" ; echo "0 */1 * * * /home/minecraft/backup.sh")| crontab -
cd /home/minecraft
screen -d -m -S mcs java -Xms4G -Xmx6G -jar server.jar nogui
```

### バックアップスクリプト

```
# vi /home/minecraft/backup.sh
```

```sh:backup
#!/bin/bash
screen -r mcs -X stuff '/save-all\n/save-off\n'
/usr/bin/gsutil cp -R ${BASH_SOURCE%/*}/world gs://minecraft-backup-114514/$(date "+%Y%m%d-%H%M%S")-world
screen -r mcs -X stuff '/save-on\n'
```

- cronに登録

```
# crontab -e

1時間ごとにshを実行
0 */1 * * * /home/minecraft/backup.sh
```

# 感想

いろいろとソースインストールしないといけなくて、面倒くさかった
これはドキュメントが消えてしまうのもうなずける  

まぁscreenをdnfできなかったのはCentOS 8 Stream使ったからなんですが、、
OpenJDKのバージョン上げないといけないのは驚いた

ちなみにインスタンス起動をTerraformでやったのは完全にオ●ニーです
ぜったいコンソールポチポチのほうが速い

アレンジしたのは、

- 追加ディスクなし
- プリエンプティブル オン
- OpenJDK 16.0.1 , screen-4.8.0 をソースからインストール

したくらいですかね