minecraft/Minecraft\357\274\210Java,Vanilla\357\274\211\343\202\265\343\203\274\343\203\220\346\247\213\347\257\211\357\274\210Docker Compose + journald + restic\343\203\220\343\203\203\343\202\257\343\202\242\343\203\203\343\203\227\357\274\211.md
... ...
@@ -0,0 +1,240 @@
1
+このページは筆者の構築手順を元にgpt-5.2で生成しました。
2
+
3
+このページは、Ubuntu 24.04 上で **`itzg/minecraft-server`(Vanilla)** を Docker Compose で動かし、ログを **journald(journalctl)** に残しつつ、ワールドを **無停止で restic バックアップ**するための手順をまとめたものです。
4
+
5
+
6
+---
7
+
8
+## 0. プレースホルダ
9
+このWiki内の以下は、各自の環境に合わせて読み替えます。
10
+
11
+- `<COMPOSE_DIR>`:`docker-compose.yml` を置くディレクトリ
12
+ 例:`/home/<USER>/minecraft`
13
+- `<VOLUME_NAME>`:Minecraftデータが入っている Docker ボリュームの「実名」
14
+ 例:`minecraft_minecraft_volume`(環境により異なる)
15
+- `<RESTIC_REPO_DIR>`:resticリポジトリの保存先
16
+- `<RESTIC_PW_FILE>`:resticパスワードファイル
17
+
18
+---
19
+
20
+## 1. Docker Compose(Minecraft + journald)
21
+
22
+### 1.1 docker-compose.yml
23
+`<COMPOSE_DIR>/docker-compose.yml`
24
+
25
+```yaml
26
+services:
27
+ minecraft:
28
+ image: itzg/minecraft-server:latest
29
+ pull_policy: daily
30
+ ports:
31
+ - "25565:25565"
32
+ environment:
33
+ EULA: "TRUE"
34
+
35
+ # 2GB RAM マシン向けの目安(必要に応じて調整)
36
+ MEMORY: "1200M"
37
+
38
+ volumes:
39
+ - minecraft_volume:/data
40
+
41
+ # コンテナログをjournaldへ
42
+ logging:
43
+ driver: journald
44
+
45
+volumes:
46
+ minecraft_volume:
47
+```
48
+
49
+### 1.2 起動
50
+```bash
51
+$ cd <COMPOSE_DIR>
52
+$ sudo docker compose up -d
53
+```
54
+
55
+### 1.3 ログ確認
56
+Docker経由:
57
+```bash
58
+$ sudo docker compose logs -f
59
+```
60
+
61
+journald経由:
62
+```bash
63
+$ journalctl -f CONTAINER_IMAGE=itzg/minecraft-server:latest
64
+```
65
+
66
+---
67
+
68
+## 2. swap(Ubuntu 24.04)
69
+メモリが小さいマシンでは OOM 回避のため swap を用意します(例:2GB)。
70
+
71
+### 2.1 現状確認
72
+```bash
73
+$ free -h
74
+$ swapon --show
75
+```
76
+
77
+### 2.2 swapfile作成
78
+```bash
79
+$ sudo fallocate -l 2G /swapfile
80
+$ sudo chmod 600 /swapfile
81
+$ sudo mkswap /swapfile
82
+$ sudo swapon /swapfile
83
+```
84
+
85
+### 2.3 永続化(再起動後も有効)
86
+```bash
87
+$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
88
+```
89
+
90
+---
91
+
92
+## 3. restic(無停止バックアップ・1時間おき・保持30日)
93
+
94
+### 3.1 resticリポジトリとパスワードファイル
95
+
96
+```bash
97
+$ sudo install -d -m 0700 <RESTIC_REPO_DIR>
98
+$ sudo install -d -m 0700 $(dirname <RESTIC_PW_FILE>)
99
+$ sudo sh -c 'umask 077; printf "%s\n" "<CHOOSE_A_STRONG_PASSWORD>" > <RESTIC_PW_FILE>'
100
+```
101
+
102
+初回のみ `init`:
103
+```bash
104
+$ sudo docker run --rm \
105
+ -v <RESTIC_REPO_DIR>:/repo \
106
+ -v "$(dirname <RESTIC_PW_FILE>)":/pw:ro \
107
+ -e RESTIC_REPOSITORY=/repo \
108
+ -e RESTIC_PASSWORD_FILE=/pw/$(basename <RESTIC_PW_FILE>) \
109
+ restic/restic:latest init
110
+```
111
+
112
+---
113
+
114
+### 3.2 バックアップ対象ボリューム(実名)を確認(重要)
115
+Composeの named volume は、環境により「プロジェクト名付き」になることがあります。
116
+
117
+```bash
118
+$ cd <COMPOSE_DIR>
119
+$ cid=$(sudo docker compose ps -q minecraft)
120
+$ sudo docker inspect "$cid" --format '{{range .Mounts}}{{println .Name "->" .Destination}}{{end}}'
121
+```
122
+
123
+出力例:
124
+- `<VOLUME_NAME> -> /data`
125
+
126
+この `<VOLUME_NAME>` を次のスクリプトに設定します。
127
+
128
+---
129
+
130
+### 3.3 バックアップスクリプト
131
+`/usr/local/sbin/minecraft-restic-backup.sh`
132
+
133
+```bash
134
+#!/usr/bin/env bash
135
+set -euo pipefail
136
+
137
+COMPOSE_DIR="<COMPOSE_DIR>"
138
+SERVICE_NAME="minecraft"
139
+
140
+VOLUME_NAME="<VOLUME_NAME>"
141
+
142
+RESTIC_REPOSITORY="<RESTIC_REPO_DIR>"
143
+RESTIC_PASSWORD_FILE="<RESTIC_PW_FILE>"
144
+RESTIC_IMAGE="restic/restic:latest"
145
+TAG="minecraft"
146
+
147
+cd "$COMPOSE_DIR"
148
+
149
+# Minecraftに対して無停止で整合性を取る
150
+sudo docker compose exec -T "$SERVICE_NAME" rcon-cli save-off || true
151
+sudo docker compose exec -T "$SERVICE_NAME" rcon-cli save-all flush || true
152
+
153
+# バックアップ(volumeをread-onlyでマウント)
154
+sudo docker run --rm \
155
+ -v "${VOLUME_NAME}:/data:ro" \
156
+ -v "${RESTIC_REPOSITORY}:/repo" \
157
+ -v "$(dirname "$RESTIC_PASSWORD_FILE"):/pw:ro" \
158
+ -e RESTIC_REPOSITORY="/repo" \
159
+ -e RESTIC_PASSWORD_FILE="/pw/$(basename "$RESTIC_PASSWORD_FILE")" \
160
+ "$RESTIC_IMAGE" backup /data --tag "$TAG" --host "$TAG"
161
+
162
+# 保持:直近30日だけ残す(古いスナップショットを削除しprune)
163
+sudo docker run --rm \
164
+ -v "${RESTIC_REPOSITORY}:/repo" \
165
+ -v "$(dirname "$RESTIC_PASSWORD_FILE"):/pw:ro" \
166
+ -e RESTIC_REPOSITORY="/repo" \
167
+ -e RESTIC_PASSWORD_FILE="/pw/$(basename "$RESTIC_PASSWORD_FILE")" \
168
+ "$RESTIC_IMAGE" forget --tag "$TAG" --keep-within 30d --prune
169
+
170
+# 書き込み再開
171
+sudo docker compose exec -T "$SERVICE_NAME" rcon-cli save-on || true
172
+```
173
+
174
+実行権限:
175
+```bash
176
+$ sudo chmod +x /usr/local/sbin/minecraft-restic-backup.sh
177
+```
178
+
179
+---
180
+
181
+## 4. systemd timer(1時間おきで自動実行)
182
+
183
+### 4.1 systemd service
184
+`/etc/systemd/system/minecraft-restic-backup.service`
185
+
186
+```ini
187
+[Unit]
188
+Description=Minecraft restic backup (hourly, online)
189
+Wants=network-online.target
190
+After=network-online.target docker.service
191
+Requires=docker.service
192
+
193
+[Service]
194
+Type=oneshot
195
+ExecStart=/usr/local/sbin/minecraft-restic-backup.sh
196
+```
197
+
198
+### 4.2 systemd timer
199
+`/etc/systemd/system/minecraft-restic-backup.timer`
200
+
201
+```ini
202
+[Unit]
203
+Description=Run Minecraft restic backup every hour
204
+
205
+[Timer]
206
+OnCalendar=hourly
207
+Persistent=true
208
+RandomizedDelaySec=5m
209
+
210
+[Install]
211
+WantedBy=timers.target
212
+```
213
+
214
+有効化:
215
+```bash
216
+$ sudo systemctl daemon-reload
217
+$ sudo systemctl enable --now minecraft-restic-backup.timer
218
+```
219
+
220
+動作確認:
221
+```bash
222
+$ systemctl list-timers --all | grep minecraft-restic
223
+$ sudo systemctl start minecraft-restic-backup.service
224
+$ journalctl -u minecraft-restic-backup.service -f
225
+```
226
+
227
+---
228
+
229
+## 5. トラブルシュート
230
+
231
+### 5.1 バックアップが小さすぎる(`0 files`)/ 0B になる
232
+`/data` に実データが見えていない(ボリューム名違い)の可能性が高いです。
233
+
234
+```bash
235
+$ sudo docker compose exec -T minecraft ls -lah /data
236
+$ cid=$(sudo docker compose ps -q minecraft)
237
+$ sudo docker inspect "$cid" --format '{{range .Mounts}}{{println .Type .Name .Source "->" .Destination}}{{end}}'
238
+```
239
+
240
+`/data` に `world/` や `server.properties` が無い場合は、`<VOLUME_NAME>` の見直しを行います。