MinetestサーバーのバックエンドをPostgreSQLにする
前にも書きましたが、minetestサーバーを地味に公開しています。管理できなくて止めました。
ぼちぼち安定した感じですが、minetestmapperというツールを使ってバックアップからマップを生成すると、いろんな場所が開拓されていてワールドがめちゃくちゃ広くなってました。(ワールドの地図画像。ファイルサイズがデカイです。)
このままだとヤバくなりそう…。ということで、minetestサーバーのバックエンドをsqlite3からPostgreSQLに移行するためのテストをメモしました。
参考資料ですが、スペイン語で書いてたブログ記事がとても役に立ちました。自分の記事は、この記事をDockerに置き換えただけです。
- 参考
- servidor minetest + postgreSQL en linux (I) | Todos hacemos TIC: https://diocesanos.es/blogs/equipotic/2021/03/01/servidor-minetest-postgresql-en-linux-i/
- SERVIDOR MINETEST + POSTGRESQL EN LINUX (II) | Todos hacemos TIC: https://diocesanos.es/blogs/equipotic/2021/03/11/servidor-minetest-postgresql-en-linux-ii/
- pandorabox.io/docker-compose.yml at master · pandorabox-io/pandorabox.io: https://github.com/pandorabox-io/pandorabox.io/blob/master/docker-compose.yml
- Database backends - Minetest Wiki: https://wiki.minetest.net/Database_backends
DockerでMinetestサーバーを動かすおさらい
以前「DockerでMinetestサーバーが動いた」という記事を書きました。
- DockerでMinetestサーバーが動いた | Days of speed: https://www.nofuture.tv/20211008
今回は、この記事のdocker-compose.yml
をベースにバックエンドをPostgreSQLに置き換えるので、一度もMinetestサーバーを設置したことが無い人は先にこちらを試して、動くことを確認してからPostgreSQLへ移行を試してください。
使用するファイルについて
docker-composeを使うのは変わりませんが、以前のファイル構造から少し変わってdb
とinitdb
フォルダとDockerfile
を追加しています。
./
├ conf/
│ └ minetest.conf
├ data/
│ └ .minetest/
├ db/ (今回追加)
│ └ (PostgreSQLのデータが置かれる)
├ initdb/ (今回追加)
│ └ init-user-db.sh
└ docker-compose.yml
dbは、PostgreSQLのデータベース保存のために用意しています。中身は空ですがマウントされてここにPostgreSQLのデータベースが保存されます。
initdbには、PostgreSQLにユーザーとデータベースを追加するスクリプトを置いています。PostgreSQLのDockerイメージの/docker-entrypoint-initdb.d/
フォルダに.sh
または.sql
拡張子のファイルがあると自動実行されます。(ドキュメントの「Initialization scripts」参照)。この場所をマウントしてユーザーとデータベースの追加を実行します。
docker-compose.yml
docker-compose.yml
ですが、PostgreSQLを追加するのでpostgres
を追加しています。それに伴ってminetest
も変更しています。最後のadminer
はPostgreSQLのデータベースを見るために追加してます。不要ならなくてもOKです。
version: "3"
services:
minetest:
container_name: minetest
image: registry.gitlab.com/minetest/minetest/server:5.5.0
volumes:
- "./conf/:/etc/minetest/"
- "./data/:/var/lib/minetest/"
ports:
- "30000:30000/udp"
depends_on:
postgres:
condition: service_healthy
links:
- postgres
postgres:
container_name: postgres
image: postgres
environment:
POSTGRES_PASSWORD: "admin"
POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
TZ: "Asia/Tokyo"
volumes:
- "./db/:/var/lib/postgresql/data/"
- "./initdb/:/docker-entrypoint-initdb.d/"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mtuser -d mtworld"]
interval: 10s
timeout: 5s
retries: 5
adminer:
container_name: adminer
image: adminer
ports:
- "8080:8080"
links:
- postgres
postgresのenvironment
ですが、POSTGRES_PASSWORD
はDockerイメージのドキュメントにもあるように必須なので設定しています。POSTGRES_INITDB_ARGS
は、データベースのデフォルト設定です。データベースのエンコーディングをUTF-8にするために入れてます。TZ
は、タイムゾーンです。
volumes
は、上で説明したデータベースを保存するdb
フォルダと設定スクリプトを置いてるinitdb
をマウントしています。
healthcheck
は、コンテナが起動したかをチェックしています。ここが今回一番悩んだ部分です。
コンテナを再起動したとき、postgres
コンテナが起動して接続OKになった後にminetest
コンテナを起動してほしいのですが、postgresコンテナの起動処理に時間がかかり、後から起動したminetestコンテナが先に起動していました。その結果、minetestコンテナは接続先が見つからず落ちることが、たびたび起こっていました。
最初、depends_on
で起動順序を指定しました。しかし、この設定は必要ですが、マシンの電源の入れる順番を設定するようなものなので問題は解決しません。
次にシャットダウンのメッセージを見るときちんと終了しないままシャットダウンされたように見えたので、stop_grace_period
で終了処理をきちんと終わらせるようにすればと思って設定しましたが、これも問題は解決しませんでした。
結局、起動処理の問題だから起動チェックをするようにすればいいと思って調べると公式ドキュメントに「Control startup and shutdown order in Compose | Docker Documentation」という、そのものズバリのものがありました。しかし、「version: "2"」と書いあって古いのでさらに調べると同じような疑問を持った人がいてzennで「DockerCompose を用いて起動順序を制御する」という文章を書いてました。
これでやっとhealthcheck
の設定がわかったので、さらに検索してこのドキュメントと公式ドキュメントを見て、やっと解決したのでした。長かった…。
ということで、pg_isready
を使って起動したかどうかチェックをしています。
minetest
のdepends_on
ですが、前述のようにpostgresが起動した後にminetestコンテナを起動させたいので追加してます。これはqiitaの「DockerのHEALTHCHECKの動きを理解する - Qiita」を参考にしました。
links
は、minetestコンテナからpostgresコンテナをを参照するために追加しています。
adminerは、データベースマネージャーです。PostgreSQLサーバーのデータベースを見るために追加しています。minetestサーバーに直接関係は無いのでなくても構いません。
Minetestサーバーに使うPostgreSQLユーザーとデータベース
PostgreSQLに追加するユーザーとデータベース名は以下にしています。
- ユーザー名: mtuser
- パスワード: mtpass
- データベース: mtworld
initdb/init-user-db.sh
initdb
フォルダに置いてある、このスクリプトはPostgreSQLのユーザーとデータベースを作成するスクリプトです。シェルスクリプトの内容は、minetest用のユーザーとデータベースを作って、ユーザーに全権限を付けてます。
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER mtuser WITH PASSWORD 'mtpass';
CREATE DATABASE mtworld WITH OWNER mtuser;
GRANT ALL PRIVILEGES ON DATABASE mtworld TO mtuser;
EOSQL
コンテナを起動する
docker-compose up
してコンテナを起動します。minetestサーバーは、まだsqlite3のままで動いています。
PostgreSQLにユーザーとデータベースが作成されているかチェックします。コマンドで確認していますが、adminerで確認しても構いません。 adminerでログインする場合の注意ですが、ログインするサーバーは、localhostではなくコンテナ名のpostgresを指定します。
$ docker exec -it postgres psql -U mtuser -d mtworld -c "\l"
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
mtworld | mtuser | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/mtuser +
| | | | | mtuser=CTc/mtuser
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)
ワールド設定ファイルworld.mtにPostgreSQLの設定を追加
データベースに問題がなければ、minetestコンテナを止めてminetestのworld.mtにPostgreSQLの接続設定を追加します。まずはコンテナを止めます。
docker-copose stop minetest
そしてMinetestデータのワールド設定ファイルdata/.minetest/worlds/(ワールド名)/world.mt
に以下のPostgreSQL接続の設定を追加します。この設定のhostですが、docker-compose.ymlのlinksで参照しているコンテナ名(ここではpostgres)を書きます。
pgsql_connection = host=postgres port=5432 user=mtuser password=mtpass dbname=mtworld
pgsql_auth_connection = host=postgres port=5432 user=mtuser password=mtpass dbname=mtworld
pgsql_player_connection = host=postgres port=5432 user=mtuser password=mtpass dbname=mtworld
データベースをマイグレーションする
設定を追記したらminetestコンテナを再び起動してデータベースをマイグレーションします。
docker-copose start minetest
起動したらminetestコンテナからデータベースのマイグレーションを実行します。
docker exec -it minetest minetestserver --migrate postgresql --map-dir /var/lib/minetest/.minetest/worlds/(ワールド名)/
docker exec -it minetest minetestserver --migrate-auth postgresql --map-dir /var/lib/minetest/.minetest/worlds/(ワールド名)/
docker exec -it minetest minetestserver --migrate-players postgresql --map-dir /var/lib/minetest/.minetest/worlds/(ワールド名)/
最初のワールドのマイグレーションはとても時間がかかるので気長に待ちます。認証とユーザーは、すぐに終わります。
終わったらマイグレーションできているか確認します。
data/.minetest/worlds/(ワールド名)/world.mt
を見ると、backend, auth_backend, player_backendがpostgresql
になっているはずです。sqlite3
のままの場合はマイグレーションされていません。
mod_storage_backend
は、PostgreSQLバックエンドが無いようでマイグレーションを実行するとエラーが出てマイグレーションできないので、これはsqlite3
のままでOKです。
mod_storage_backend = sqlite3
auth_backend = postgresql
player_backend = postgresql
backend = postgresql
データベースを確認します。テーブルが作成されていればOKです。こちらもadminerで確認しても構いません。
$ docker exec -it postgres psql -U mtuser -d mtworld -c "\dt"
List of relations
Schema | Name | Type | Owner
--------+------------------------+-------+--------
public | auth | table | mtuser
public | blocks | table | mtuser
public | player | table | mtuser
public | player_inventories | table | mtuser
public | player_inventory_items | table | mtuser
public | player_metadata | table | mtuser
public | user_privileges | table | mtuser
(7 rows)
問題がないようならデータベースのバックアップを取ります。
docker exec -it postgres pg_dump -U mtuser mtworld > mtworld.sql
バックアップを取ったら、docker-compose down
してdocker-compose up
しても、きちんと起動するか確認します。
docker-compose down
docker-compose up
minetest、postgresql両方のコンテナがきちんと起動したなら、minetestクライアントからサーバーにログインして動作を確認してください。それで問題なければ移行は成功です。
sqlite3に戻したい場合
何か問題があってマイグレーションできなかった場合ですが、sqlite3のデータベースは残っているのでworld.mt
のpostgresql
の記述を下のようにsqlite3
戻せば古いsqlite3データベースに戻せます。
mod_storage_backend = sqlite3
auth_backend = sqlite3
player_backend = sqlite3
backend = sqlite3
最後に
長かった。大丈夫だと思ってた設定がダメダメすぎて、このままお蔵入りかと思ったけど解決できてよかった。
PostgreSQLが使えるようになったので、次はテクスチャなどを配信するリモートメディアサーバーを置いて(これはすぐにできそう)、マップサーバーを設置すれば理想のサーバー環境ができるはず。あと少し。