PostgreSQLのDockerコンテナを起動していたローカルのマシンのバッテリーが切れて落ちてしまい、
電源を確保して、起動し直したところ、エラーを吐いて立ち上がらなくなってしまいました。
起動時にPanicログを出力する状態から、WALの復旧をした手順です。
Docker Composeの定義
コンテナのデータはホストマシンのディレクトリにマウントして永続化しての使用です。
docker-compose.yml
より定義部分。
services:
db:
image: postgres:12-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=foobar
volumes:
- ./dataDir:/var/lib/postgresql/data
起動時のログです。
db_1 |
db_1 | PostgreSQL Database directory appears to contain a database; Skipping initialization
db_1 |
db_1 | 2020-02-07 01:36:06.106 UTC [1] LOG: starting PostgreSQL 12.1 on x86_64-pc-linux-musl, compiled by gcc (Alpine 8.3.0) 8.3.0, 64-bit
db_1 | 2020-02-07 01:36:06.107 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
db_1 | 2020-02-07 01:36:06.107 UTC [1] LOG: listening on IPv6 address "::", port 5432
db_1 | 2020-02-07 01:36:06.270 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1 | 2020-02-07 01:36:06.434 UTC [21] LOG: database system was interrupted; last known up at 2020-02-07 01:19:57 UTC
db_1 | 2020-02-07 01:36:10.655 UTC [21] LOG: invalid record length at 1/94338ED0: wanted 24, got 0
db_1 | 2020-02-07 01:36:10.655 UTC [21] LOG: invalid primary checkpoint record
db_1 | 2020-02-07 01:36:10.655 UTC [21] PANIC: could not locate a valid checkpoint record
db_1 | 2020-02-07 01:36:10.656 UTC [1] LOG: startup process (PID 21) was terminated by signal 6: Aborted
db_1 | 2020-02-07 01:36:10.656 UTC [1] LOG: aborting startup due to startup process failure
db_1 | 2020-02-07 01:36:10.661 UTC [1] LOG: database system is shut down
.
.
.
db_1 | 2020-02-07 01:36:10.655 UTC [21] PANIC: could not locate a valid checkpoint record
このようなログを吐いて起動が停止してしまっていました。パニクってます。
調べてみると、WAL(Write ahead log)が損傷してしまったとのこと。
復旧コマンド
この状態からの復旧は pg_resetxlog
というコマンドを使用します。
pg_resetxlogは、先行書き込みログ(WAL)を消去し、さらにオプションでpg_controlファイル内に保存された制御情報の一部を初期化します。 この機能は、これらのファイルが破損した場合に必要になることがあります。 このような破損などが原因でサーバを起動できない場合の最後の手段としてのみ、この機能を使用してください。
なお、Postgres10
よりpg_resetxlog
はpg_resetwal
にリネームされていました。
バージョンによってコマンド名を変えてください。
docker run --rm -it -v $(pwd)/dataDir:/var/lib/postgres/data/ postgres:12 /bin/bash
データはホストマシン側でマウントしていたので、マウントします。
gosu postgres pg_resetwal -f /var/lib/postgres/data
コンテナが起動したら、ログ初期化コマンドを実行。実行後には無事起動しました。
これはあくまでログの強制初期化なので、データの整合性が破損している可能性があります。
バックアップをとって、データを入れ直すなど整合性をチェックしたほうが良さそうです。
今回は手元の開発環境であり、最悪全部消えても良かったのですが、復旧できるならということで、ここまでの対応としました。