Featured image of post Firefish データベースアップグレード記録

Firefish データベースアップグレード記録

データベースのアップグレードは結構面倒ですね。

私の Firefish インスタンスは昨年の11月に構築されましたが、使用しているデータベースのバージョンは当然最新ではありません。具体的には、5年前のPostgresに基づいたPGroonga 12という古いバージョンです。将来の互換性やセキュリティの問題を避けるため、またパフォーマンスを向上させるために、今日はこのデータベースをアップグレードする必要があります。

PostgreSQL 12は2019年にリリースされました

Dockerで稼働しているデータベースをアップグレードするのは、他のDockerコンテナをアップグレードするのとは大きく異なります。新しいイメージをプルするだけでは終わりません。Postgresはほぼ毎回メジャーバージョンでBreaking Changesがあり、旧バージョンと新バージョンで生成される永続化ファイルは互換性がありません。新しいイメージを直接プルして実行すると、データベースは起動しません。そのため、データを移行するための手段を講じる必要があります。

Postgresには公式のアップグレードツールpg_upgrade1がありますが、今回は使用しません。私のデータベースは1年以上稼働しており、しかも5年前の古いバージョンを使用しているため、このツールを使って問題が発生しないか確信が持てません。この移行では、SQLをエクスポートしてから新しいバージョンにインポートするという大まかな手順を取ります。

アップグレード前のデプロイ状況

以下はアップグレード前に知っておくべき設定情報です:

項目設定
インスタンスのデプロイ方法Docker Compose
データベースコンテナ名firefish_db
アップグレード前のデータベースコンテナイメージgroonga/pgroonga:3.1.9-alpine-12-slim
データベースユーザーexample-firefish-user
データベース名firefish

Docker Composeのデータベース部分は以下の通りです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
db:
    restart: unless-stopped
    image: groonga/pgroonga:3.1.9-alpine-12-slim
    container_name: firefish_db
    networks:
      - calcnet
    env_file:
      - .config/docker.env
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready --user="${POSTGRES_USER}" --dbname="${POSTGRES_DB}"
      interval: 5s
      timeout: 5s
      retries: 5

現在のデータベースのエクスポート

データベースをアップグレードする前に、まずFirefishのオーケストレーションを停止します:

1
docker compose down

データベースコンテナを単独で起動し、現在のデータベースをSQLとしてエクスポートします:

1
2
docker compose up -d db
docker exec -it firefish_db pg_dumpall -U example-firefish-user > backup.sql

Firefishのデータベースは比較的大きいため、エクスポートプロセスにはかなりの時間がかかる可能性があります。例えば、私の個人インスタンスでは10分以上かかりました。

エクスポートファイルの処理

おそらく新しいバージョンのPostgresの認証方法が変更されたため、以前エクスポートしたbackup.sqlファイルを新しいデータベースに直接インポートすると、新しいデータベースの認証スキームが変更され、その後Firefishがデータベースに接続する際に認証に失敗します。この問題を避けるためには、現在のbackup.sqlファイルを処理し、firefishデータベースの部分のみを抽出し、すべてのデータを直接インポートしないようにする必要があります。2

1
2
3
#!/bin/bash
[ $# -lt 2 ] && { echo "Usage: $0 <postgresql dump> <dbname>"; exit 1; }
sed  "/connect.*$2/,\$!d" $1 | sed "/PostgreSQL database dump complete/,\$d"

上記の内容でシェルスクリプトを作成し、script.shとして保存して、現在のbackup.sqlを処理します:

1
2
3
nvim script.sh  # またはお好みのエディタ
chmod +x script.sh
./script.sh backup.sql firefish >> upgrade.sql

すべてが順調に進めば、現在のディレクトリにupgrade.sqlという名前のファイルが作成されます。これを開いて、正しくエクスポートされたか確認してください。

新しいデータベースに既存データをインポート

docker-compose.ymlを修正します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
db:
    restart: unless-stopped
    image: groonga/pgroonga:3.2.2-alpine-16-slim  # 最新のコンテナ
    container_name: firefish_db
    networks:
      - calcnet
    env_file:
      - .config/docker.env
    volumes:
      - ./database:/var/lib/postgresql/data # この行の変更に注意
    healthcheck:
      test: pg_isready --user="${POSTGRES_USER}" --dbname="${POSTGRES_DB}"
      interval: 5s
      timeout: 5s
      retries: 5

データベースディレクトリのマッピング設定が./db:/var/lib/postgresql/dataから./database:/var/lib/postgresql/dataに変更されていることに注意してください。これは、新しいデータベースに新しいスタートを与えつつ、古い永続化データを保存するためです。問題が発生しても、古いデータベースにいつでも戻すことができます。

新しいコンテナをプルして起動します:

1
2
docker compose pull
docker compose up db -d

upgrade.sqlを新しいデータベースにインポートします:

1
cat upgrade.sql | docker exec -i firefish_db psql -U example-firefish-user -d firefish

データベースのサイズに応じて、インポートプロセスも長時間かかる可能性があります。

仕上げ作業

インポートが完了したら、全体のオーケストレーションを起動します:

1
2
docker compose stop db
docker compose up

インポート後の最初の起動では、-dパラメータを使用しないことをお勧めします。パラメータなしで起動し、起動プロセスに問題がないことを確認した後、-dパラメータで再起動してください。

最後に、新しく起動したFirefishインスタンスにログインし、データが損失していないか確認します。問題がなければ、作業完了です🎉


  1. 公式ドキュメント:https://www.postgresql.org/docs/current/pgupgrade.html ↩︎

  2. 参考:https://thomasbandt.com/postgres-docker-major-version-upgrade ↩︎

Licensed under CC BY-NC-SA 4.0
Hugo で構築されています。
テーマ StackJimmy によって設計されています。