zaki work log

作業ログやら生活ログやらなんやら

[Docker] PostgreSQLコンテナのボリューム未指定時の場合のデータサルベージとバックアップ・リストア

postgresコンテナのデータを永続化するにはボリューム指定するのが定石だけど、うっかりしてコンテナ再作成後にデータが消えていた場合のサルベージ方法について。
ちなみにアプリの都合でpostgres:12を使ってるけど、2024年にサポート終了してるのね。本文中はver17の情報にリンク。

なお、DBは専門じゃないので「そんなんよりこんな方法があるよ」とかあればぜひ教えてください。

データのサルベージ

まずpostgresコンテナは /var/lib/postgresql/dataVOLUME 指定してあるため、とりあえずコンテナデプロイ時にボリューム指定していなくてもデータが暗黙的にボリューム保存される。
よって、コンテナデプロイ時にうっかりしてボリューム未指定であっても、/var/lib/docker/volumes 以下を頑張って漁ればコンテナ削除後でも(ボリュームを消していなければ)データのサルベージは可能。
探し方としては ls /var/lib/docker/volumes/*/*/pg* などを実行して地道にやるしかないかな?

サルベージしたデータでバインドマウント

/var/lib/docker/volumes から掘り起こしたDBのデータをどこか適当な場所へコピーし、コンテナから /var/lib/postgresql/data で参照できるような定義でpostgresをデプロイする。

compose.yamlのある場所から見て ./volume/data 以下にデータがある構成なら以下のとおり。

        volumes:
            - $PWD/volume/data:/var/lib/postgresql/data

これで先ずはバインドマウントした状態でDBがデプロイされる。
ちなみにファイルのownerはコンテナ起動時にあるべき状態に再セットされるため、あまり気にしないで良い(っぽい)

DBバックアップ

www.postgresql.jp

バインドマウントしたDB領域で無事に起動したら、このデータを pg_dumpall でバックアップする。
その際、ホストOSからdocker execで実行、結果をファイルへリダイレクトすればホストOS上にバックアップデータが生成される。

$ docker compose exec db pg_dumpall -U r-board > dumpfile.sql
$ ls
compose.yaml  dumpfile.sql  volume

データを吸い出せたら、一度コンテナを停止(削除)する。

ボリュームマウントで起動

ボリュームマウントする定義に変更してDBコンテナをデプロイ。 composeの場合は(アプリの初回起動時に初期データ構築等が行われるなら)DBのみをデプロイ。

services:
    db:
        image: postgres:12

        environment:
            POSTGRES_USER: r-board
            POSTGRES_PASSWORD: パスワード

        [snip]

        volumes:
            - pg_data:/var/lib/postgresql/data

volumes:
    pg_data:
docker compose up -d db

もちろん新規ボリュームになるため、(ユーザー名指定による最低限の初期状態の生成データを除いて)中身は空。

$ docker compose exec db bash
root@c395a389f69c:/# psql -U r-board
psql (12.22 (Debian 12.22-1.pgdg120+1))
Type "help" for help.

r-board# \dt
Did not find any relations.

バックアップデータをリストア

pg_dumpall で取得したデータを psql コマンドで流し込む。

cat dumpfile.sql | docker compose exec -T db psql -U ユーザー名

これでデータが復元される。(データによってはコンテナ起動時に作られるためalready existsになると思うが基本問題ない)

$ docker compose exec db bash
root@c395a389f69c:/# psql -U r-board
psql (12.22 (Debian 12.22-1.pgdg120+1))
Type "help" for help.

r-board=# \dt
             List of relations
 Schema |      Name       | Type  |  Owner  
--------+-----------------+-------+---------
 public | app_user        | table | r-board
 public | board           | table | r-board
 public | board_access    | table | r-board
 public | board_api_token | table | r-board
 public | board_event     | table | r-board
 public | pgmigrations    | table | r-board
 public | user_board      | table | r-board
(7 rows)

r-board=# 

アプリケーション(というかDB以外)のコンテナをデプロイ

数が少なければ個別にデプロイする…でもいいが、composeを使っていればdocker compose up -dすれば未起動のコンテナはすべて起動する。
これで、ボリューム領域にリストアされたデータでDBが使用可能状態になる。

環境

$ docker --version
Docker version 28.3.3, build 980b856
$ docker compose exec db psql --version
psql (PostgreSQL) 12.22 (Debian 12.22-1.pgdg120+1)

システム的には以下のアプリで使用しているデータベース

zaki-hmkc.hatenablog.com