はじめに
これまで、Minecraft Education Dedicated Serverを常時稼働で動かしていた。
バックアップも毎日取れるし。
ある日、連絡が来た。
「サーバーが古いから参加できません」
……はい?
調べてみると、原因はクライアントとDedicated Serverのバージョン不一致。
その結果、
| PF | Ver |
|---|---|
| Windowsユーザー | 26.32 |
| Macユーザー | 20.133 |
| Dedicated Server | 20.133 |
という状態が発生。
当然、Windowsだけ接続できない。
「サーバー古いです」
という報告が上がってきた。
これは困る。解散の危機じゃん。
これ、今後も絶対に発生するやつだ。
ということで、今回はMinecraft Education Dedicated Serverを更新しつつ、今後のアップデートを楽にするスクリプトも作ることにした。
まず結論。
サーバの更新スクリプトを作ったので、これでサーバをUpdateする。
スクリプトは後半に全文記載。
./update-minecraft.sh --dryrun1
で新バージョンをDLが問題なければ、
サーバを止めてから
./update-minecraft.sh
で更新。
その後、手動でサーバーを起動。
以上。
今回のアプデ、何が変わるの?
今回更新したのは Minecraft Education v1.26.32.0。
公式の変更内容はこちら。
かなり大きなアップデートだった。
ざっくり4つ。
1. Dedicated Serverが大幅強化
今回、サーバー運用的に一番気になるのがこれ。
cross-tenant multiplayerに対応。
違う学校とか組織の間でも、同じサーバーでマルチプレイができるようになった。
公式が想定しているユースケースも面白い。
- 別々の教室
- 学校・地区をまたいだ共同プロジェクト
- eスポーツ
など。
Minecraft EducationのDedicated Serverを、
学校A
│
│
├──── Dedicated Server ────┐
│ │
学校B │
│ │
└───────────────────────────┘
という形で利用しやすくなる。
複数の組織で合同でマイクラやるなら、神アプデかも。
2. Bedrock側の新機能が大量に入った
今回のMinecraft Educationは、Bedrock Edition側の大型アップデートを取り込んでいる。
Bedrock Edition 1.21.131 → 1.26.30の主要アップデート込み。
Name Tag
クラフト可能なName Tagが追加。
これまでより簡単に、
- Mobの名前付け
- NPCの管理
- チーム分け
- ストーリー設定
- 授業用ワールドの整理
などができる。
こういう細かい機能が、ワールド作るときに地味に効いてくる。
3. Tiny Takeover
Baby Mob関連の要素が追加された。
- Baby Mob
- Babyを生成するSpawn Egg
- Golden Dandelion
など。
マイクラの中で、生き物の成長とか生態系を観察する授業とかに使えそう。
4. Chaos Cubed / Sulfur
そして今回の目玉のひとつ。
Sulfur(硫黄)関連の新要素。
新しい環境として、
- Sulfur Caves
- Sulfur Springs
新しいブロック・素材として、
- Sulfur
- Cinnabar
さらに、
- Geyser
- Sulfur Spikes
- Sulfur Cube
などが追加されている。
これ、理科の実験とかに最高じゃん。
- 地球科学
- 化学
- 環境システム
といったテーマにMinecraftを使える。
また一段と、学校の教材っぽさが増した感じ。
サーバーを手動で上げるのはだるい
で、本題のサーバー更新。
Minecraft Educationの公式手順では、既存のサーバーを新しくする場合、
- 最新版サーバーをダウンロード
- 新しいディレクトリへ展開
- 古いサーバーを停止
- 必要なファイルを新サーバーへコピー
- 新しいサーバーを起動
という手順になっている。
公式の更新手順はこちら。
移行するものは、
edu_server_session.json
worlds/
server.properties
allowlist.json
permissions.json
さらに、自分で追加・変更したリソースパックやビヘイビアーパックなども移行。
起動後はコンソールの、
Version: 1.26.32.0
という表示でバージョンを確認。
以上をスクリプトで自動化する
サーバー停止を確認
↓
最新版ダウンロード
↓
展開
↓
worldsとか設定ファイルを全部自動コピー
↓
カスタムファイル確認
↓
古いサーバーをまるごと自動バックアップ
↓
新サーバーへガッと置き換え
少しだけ技術的なノウハウ紹介。
- あえて「サーバー起動・停止」は自動化しない
アプデの途中で勝手にサーバーが動き出したり、止めるのに失敗したままデータ上書きして壊れるのが一番怖いから。そこは人間の目で確認する。 - dryrun機能
いきなり本番環境が書き換わるのは怖いから、ダウンロードと展開チェックだけやるモードを作った。
使い方はこんな感じ。
まずはテスト。
./update-minecraft.sh --dryrun1
これを実行すると、最新版を勝手に取ってきて、一時フォルダで解凍して、中身が壊れてないかチェックするところまでやってくれる。
最新版をダウンロード
↓
ZIPを検証
↓
一時ディレクトリへ展開
↓
bedrock_serverを確認
↓
終了
既存のサーバーフォルダは一切触らないから安全。
テストがOKなら、本番サーバーを一旦自分で止めてから、通常アップデートを実行。
./update-minecraft.sh
これで、さっきのコピペ作業からバックアップまで一瞬で終わる。
プロセス確認
↓
最新版ダウンロード
↓
一時ディレクトリへ展開
↓
bedrock_server確認
↓
設定ファイル移行
↓
worlds移行
↓
カスタムファイル移行
↓
再度プロセス確認(念のため)
↓
バックアップ作成
↓
/opt/minecraftをガバッと更新
↓
終了
終わったら、いつもの手順でサーバーをポチッと起動するだけ。
まとめ
これで次から「サーバーが古くて入れませーん」って言われても、白目を剥かずに真顔でスクリプト叩くだけで解決できるようになった。自動化最高。
よーし、アプデも無事に終わったし、新要素の「Sulfur Caves(硫黄の洞窟)」とかいうやつをみんなで見に行くぞ!ってなって、ウキウキでサーバーを起動した。
サーバーログにもバッチリ Version: 1.26.32.0 の文字。完璧。
さあ、Windowsのやつら、入れなくて文句言ってたキッズたち、早く入ってこい!
……って待ってたんだけど、誰も入ってこない。
「入れないんですけど」ってまたチャットが来た。
え?なんで?サーバーは最新だよ?
Macは手動でUpdateしないとだめみたい。マイクラはWindowsがオススメでした・・・
付録 アプデ用スクリプト
アプデ用スクリプトは、長いので折りたたんで置いておく。
update-minecraft.sh
使うときは、スクリプト内の SERVER_DIR="/opt/minecraft" とかのパスを自分の環境に合わせて書き換えてね。
#!/bin/bash
set -euo pipefail
# ============================================================
# Minecraft Education Dedicated Server Update
#
# Usage:
#
# ./update-minecraft.sh --dryrun1
# ./update-minecraft.sh
#
# --dryrun1:
# 最新版をDLして一時ディレクトリへ展開
# /opt/minecraftは変更しない
#
# 通常モード:
# プロセス確認
# 最新版をDL
# 一時ディレクトリへ展開
# 設定・worldsを移行
# 現在のサーバーをバックアップ
# /opt/minecraftを新版へ置換
#
# IMPORTANT:
# Minecraftの停止・起動は行わない
# sudo/rootは使用しない
# ============================================================
SERVER_DIR="/opt/minecraft"
DOWNLOAD_URL="https://aka.ms/downloadmee-linuxserver"
PROCESS_NAME="bedrock_server_edu"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
WORK_DIR="/tmp/minecraft-update-${TIMESTAMP}"
NEW_DIR="${WORK_DIR}/minecraft"
ZIP_FILE="${WORK_DIR}/server.zip"
BACKUP_DIR="${HOME}/minecraft-backup-${TIMESTAMP}"
# ============================================================
# Functions
# ============================================================
error()
{
echo
echo "ERROR: $1"
echo
exit 1
}
cleanup()
{
if [ -d "$WORK_DIR" ]; then
echo
echo "作業ディレクトリ:"
echo " ${WORK_DIR}"
fi
}
trap cleanup EXIT
# ============================================================
# Argument
# ============================================================
MODE="${1:-normal}"
case "$MODE" in
--dryrun1)
DRYRUN1=true
;;
normal)
DRYRUN1=false
;;
*)
error "Unknown option: ${MODE}
使用方法:
$0
$0 --dryrun1"
;;
esac
# ============================================================
# Check commands
# ============================================================
for CMD in curl unzip rsync find pgrep ps stat mv mkdir chmod; do
if ! command -v "$CMD" >/dev/null 2>&1; then
error "${CMD} が見つかりません"
fi
done
# ============================================================
# Header
# ============================================================
echo "=============================================="
echo " Minecraft Education Dedicated Server"
echo "=============================================="
echo
echo "User:"
echo " $(whoami)"
echo
if [ "$DRYRUN1" = true ]; then
echo "Mode:"
echo " DRYRUN1"
else
echo "Mode:"
echo " UPDATE"
fi
echo
# ============================================================
# DRYRUN1
# ============================================================
if [ "$DRYRUN1" = true ]; then
echo "=============================================="
echo " DRYRUN1"
echo "=============================================="
echo
echo "実行内容:"
echo
echo " ✓ 最新版をダウンロード"
echo " ✓ ZIPを検証"
echo " ✓ 一時ディレクトリへ展開"
echo " ✓ bedrock_server確認"
echo
echo "実行しない処理:"
echo
echo " × Minecraft停止"
echo " × Minecraft起動"
echo " × /opt/minecraft変更"
echo " × worlds移行"
echo " × 設定移行"
echo " × バックアップ"
echo
mkdir -p "$NEW_DIR"
echo "[1/4] 最新版をダウンロード"
curl \
-fL \
--retry 3 \
--retry-delay 2 \
"$DOWNLOAD_URL" \
-o "$ZIP_FILE"
echo
echo "[2/4] ZIPを検証"
unzip -t "$ZIP_FILE" >/dev/null
echo " OK"
echo
echo "[3/4] ZIPを展開"
unzip -q "$ZIP_FILE" -d "$NEW_DIR"
echo
echo "[4/4] bedrock_serverを確認"
BEDROCK_SERVER=""
if [ -f "${NEW_DIR}/bedrock_server_edu" ]; then
BEDROCK_SERVER="${NEW_DIR}/bedrock_server_edu"
else
BEDROCK_SERVER=$(
find "$NEW_DIR" \
-type f \
-name "bedrock_server_edu" \
-print -quit
)
fi
if [ -z "$BEDROCK_SERVER" ]; then
error "bedrock_serverが見つかりません"
fi
#chmod +x "$BEDROCK_SERVER"
echo
echo "=============================================="
echo " DRYRUN1 completed"
echo "=============================================="
echo
echo "展開先:"
echo " ${NEW_DIR}"
echo
echo "bedrock_server:"
echo " ${BEDROCK_SERVER}"
echo
echo "既存の /opt/minecraft は変更していません。"
echo
exit 0
fi
# ============================================================
# Normal mode
# ============================================================
echo "=============================================="
echo " UPDATE"
echo "=============================================="
echo
# ============================================================
# Check /opt/minecraft
# ============================================================
echo "[1] 現在のサーバーを確認"
if [ ! -d "$SERVER_DIR" ]; then
error "${SERVER_DIR} が存在しません"
fi
if [ ! -f "${SERVER_DIR}/bedrock_server_edu" ]; then
error "${SERVER_DIR}/bedrock_server が見つかりません"
fi
# ============================================================
# Check write permission
# ============================================================
echo
echo "[2] 書き込み権限を確認"
if [ ! -w "$SERVER_DIR" ]; then
error "${SERVER_DIR} に書き込み権限がありません。
現在の権限:
$(ls -ld "$SERVER_DIR")
実行ユーザー:
$(whoami)"
fi
echo " OK"
# ============================================================
# Check Minecraft process
# ============================================================
echo
echo "[3] Minecraftプロセスを確認"
PIDS=$(pgrep -x "$PROCESS_NAME" || true)
if [ -n "$PIDS" ]; then
echo
echo "ERROR: Minecraft Serverが起動しています。"
echo
echo "PID:"
echo "$PIDS"
echo
echo "Process:"
ps -fp $PIDS
echo
echo "Minecraftを停止してから再実行してください。"
exit 1
fi
echo " OK: ${PROCESS_NAME} は停止しています"
# ============================================================
# Check owner
# ============================================================
echo
echo "[4] 所有者を確認"
SERVER_OWNER=$(stat -c '%U' "$SERVER_DIR")
SERVER_GROUP=$(stat -c '%G' "$SERVER_DIR")
echo
echo "Server:"
echo " ${SERVER_DIR}"
echo
echo "Owner:"
echo " ${SERVER_OWNER}:${SERVER_GROUP}"
# ============================================================
# Create work directory
# ============================================================
echo
echo "[5] 一時ディレクトリを作成"
mkdir -p "$NEW_DIR"
# ============================================================
# Download
# ============================================================
echo
echo "[6] 最新版をダウンロード"
curl \
-fL \
--retry 3 \
--retry-delay 2 \
"$DOWNLOAD_URL" \
-o "$ZIP_FILE"
# ============================================================
# Verify ZIP
# ============================================================
echo
echo "[7] ZIPを検証"
unzip -t "$ZIP_FILE" >/dev/null
echo " ZIP OK"
# ============================================================
# Extract
# ============================================================
echo
echo "[8] 最新版を展開"
unzip -q "$ZIP_FILE" -d "$NEW_DIR"
# ============================================================
# Find bedrock_server
# ============================================================
echo
echo "[9] bedrock_serverを確認"
BEDROCK_SERVER=""
if [ -f "${NEW_DIR}/bedrock_server_edu" ]; then
BEDROCK_SERVER="${NEW_DIR}/bedrock_server_edu"
else
BEDROCK_SERVER=$(
find "$NEW_DIR" \
-type f \
-name "bedrock_server_edu" \
-print -quit
)
fi
if [ -z "$BEDROCK_SERVER" ]; then
error "bedrock_serverが見つかりません"
fi
chmod +x "$BEDROCK_SERVER"
echo " ${BEDROCK_SERVER}"
# ============================================================
# Normalize extracted directory
# ============================================================
if [ "$BEDROCK_SERVER" != "${NEW_DIR}/bedrock_server_edu" ]; then
echo
echo "展開されたサブディレクトリを整理"
EXTRACT_ROOT=$(dirname "$BEDROCK_SERVER")
TEMP_ROOT="${WORK_DIR}/minecraft-root"
mkdir -p "$TEMP_ROOT"
rsync -a \
"${EXTRACT_ROOT}/" \
"${TEMP_ROOT}/"
rm -rf "$NEW_DIR"
mv "$TEMP_ROOT" "$NEW_DIR"
BEDROCK_SERVER="${NEW_DIR}/bedrock_server_edu"
chmod +x "$BEDROCK_SERVER"
fi
# ============================================================
# Copy official migration files
# ============================================================
echo
echo "[10] 設定を移行"
COPY_ITEMS=(
"edu_server_session.json"
"server.properties"
"allowlist.json"
"permissions.json"
)
for ITEM in "${COPY_ITEMS[@]}"; do
if [ -e "${SERVER_DIR}/${ITEM}" ]; then
echo " Copy: ${ITEM}"
rsync -a \
"${SERVER_DIR}/${ITEM}" \
"${NEW_DIR}/${ITEM}"
fi
done
# ============================================================
# Copy worlds
# ============================================================
if [ -d "${SERVER_DIR}/worlds" ]; then
echo
echo "[11] worldsを移行"
mkdir -p "${NEW_DIR}/worlds"
rsync -a \
"${SERVER_DIR}/worlds/" \
"${NEW_DIR}/worlds/"
else
echo
echo "[11] worldsなし"
fi
# ============================================================
# Copy custom files
# ============================================================
echo
echo "[12] カスタムファイルを移行"
for ITEM in "${SERVER_DIR}"/*; do
BASENAME=$(basename "$ITEM")
case "$BASENAME" in
bedrock_server)
continue
;;
server.properties)
continue
;;
allowlist.json)
continue
;;
permissions.json)
continue
;;
edu_server_session.json)
continue
;;
worlds)
continue
;;
logs)
continue
;;
esac
if [ -e "${NEW_DIR}/${BASENAME}" ]; then
echo " Keep new version: ${BASENAME}"
else
echo " Custom: ${BASENAME}"
rsync -a \
"$ITEM" \
"${NEW_DIR}/"
fi
done
# ============================================================
# Final process check
# ============================================================
echo
echo "[13] 更新直前のプロセス確認"
PIDS=$(pgrep -x "$PROCESS_NAME" || true)
if [ -n "$PIDS" ]; then
error "Minecraft Serverが起動しました。更新を中止します。"
fi
echo " OK"
# ============================================================
# Backup
# ============================================================
echo
echo "[14] 現在のサーバーをバックアップ"
mkdir -p "$BACKUP_DIR"
rsync -a \
"${SERVER_DIR}/" \
"${BACKUP_DIR}/"
echo
echo "Backup:"
echo " ${BACKUP_DIR}"
# ============================================================
# Replace
# ============================================================
echo
echo "[15] /opt/minecraftを更新"
OLD_DIR="${WORK_DIR}/minecraft-old"
mv "$SERVER_DIR" "$OLD_DIR"
mv "$NEW_DIR" "$SERVER_DIR"
# ============================================================
# Result
# ============================================================
echo
echo "=============================================="
echo " UPDATE completed"
echo "=============================================="
echo
echo "Server:"
echo " ${SERVER_DIR}"
echo
echo "Backup:"
echo " ${BACKUP_DIR}"
echo
echo "Old server:"
echo " ${OLD_DIR}"
echo
echo "Minecraft Serverは起動していません。"
echo "起動は外部から実施してください。"
echo