3
3

More than 3 years have passed since last update.

PostgreSQL DockerコンテナのWALが壊れて起動できない状態をpg_resetwalで起動できるように

Posted at

PostgreSQLのDockerコンテナを起動していたローカルのマシンのバッテリーが切れて落ちてしまい、
電源を確保して、起動し直したところ、エラーを吐いて立ち上がらなくなってしまいました。

なお、コンテナのデータはホストマシンのディレクトリにマウントして永続化しての使用です。
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_resetxlogpg_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

コンテナが起動したら、ログ初期化コマンドを実行。
実行は、無事起動しました。

これはあくまでログの強制初期化なので、データの整合性が破損している可能性があります。
バックアップをとって、データを入れ直すなど整合性をチェックしたほうが良さそうです。

今回は手元の開発環境であり、最悪全部消えても良かったのですが、
復旧できるならということで、ここまでの対応としました。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3