noellabo's tech blog

@noellaboの技術ブログ

WAL-GでオブジェクトストレージにPostgreSQLをバックアップしよう

Mastodon管理者のためのWAL-Gバックアップ

WAL-Gのススメ

Mastodonサーバ管理者(鯖缶)のみなさん、オブジェクトストレージ、使ってますか?
使っているなら、PostgreSQLのバックアップ、オブジェクトストレージにとるという手がありますよ。

ざっくり言うと、

  1. PostgreSQLの設定にarchive_mode=onarchive_command='wal-g wal-push'を追加し、自動で差分バックアップをとる
  2. cronで、毎日wal-g backup-pushで自動でフルバックアップをとる
  3. cronで、毎週wal-g delete retain 7で7回分だけ残して自動で残りを削除する

という感じです。簡単でしょ?

なお、WAL-Gはgoで書かれていて、バイナリ1個配置すれば動きます。

保管場所がオブジェクトストレージなので、

  • 安価で、容量の心配不要
  • 復元が簡単
  • 任意の時点に復元可能
  • 全自動
  • (暗号化)
  • (サーバの引っ越しが簡単)

というような利点があります。

便利そうでしょ? やってみる?

設定手順

とりあえずUbuntu、wasabi、PostgreSQL11で説明します。

オブジェクトストレージに保存場所を作る

  1. wasabi(S3やS3互換ストレージ)で、バックアップ保存用のバケットを作る

たとえば、i.ll.be.backというバケットをつくります。

  1. APIアクセスできるようにしたユーザーに読み書きできる権限を与える

こういうポリシーを作って(i-ll-be-back-fullaccessとか)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::i.ll.be.back"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::i.ll.be.back/*"
    }
  ]
}

Mastodonで使っているユーザーのPermissionsにこのポリシーを与えます。

バックアップオペレーターを作ってもいいと思います。
新規につくる場合、APIアクセスできるようにして、KEY_IDとACCESS_KEYをわかるようにしておいて下さい。

WAL-Gをとってきて配置する

  1. WAL-G is an archival restoration tool for Postgres.を見にいって、最新リリースのページから最新版のバイナリをもらってくる
  2. /usr/local/bin にでもおいておく
wget -O - https://github.com/wal-g/wal-g/releases/download/v0.2.9/wal-g.linux-amd64.tar.gz|tar xvzf -
sudo mv wal-g /usr/local/bin

設定を環境変数に保存してまとめて呼び出せるようにenvdirを入れておく

  1. daemontoolsに入ってるので入れる
sudo apt install daemontools

環境変数を設定する

  1. ディレクトリを作って、変数名のファイルを作って中身を書き込む
sudo mkdir -p /etc/wal-g.d/env
sudoedit /etc/wal-g.d/env/AWS_ACCESS_KEY_ID
sudoedit /etc/wal-g.d/env/AWS_SECRET_ACCESS_KEY
echo "https://s3.us-west-1.wasabisys.com" | sudo tee /etc/wal-g.d/env/AWS_ENDPOINT
echo "s3://i.ll.be.back/" | sudo tee /etc/wal-g.d/env/WALG_S3_PREFIX
echo "/var/run/postgresql" | sudo tee /etc/wal-g.d/env/PGHOST
echo "5432" | sudo tee /etc/wal-g.d/env/PGPORT
echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin" | sudo tee /etc/wal-g.d/env/PATH

wasabiのリージョンにあわせたENDPOINTと、バックアップ用のエンドポイントにあわせてs3://バケット名/のように設定すること。

  1. バックアップのリストを表示するbackup-listで No backups found になることを確認する。
sudo -u postgres envdir /etc/wal-g.d/env wal-g backup-list

postgres.confに設定する

データディレクトリのpostgresql.confを変更する。

データディレクトリはpg_lsclusterして確認。ついでにログの場所も確認しとく。

なお、私はconf.d/archive.confに書いて、postgresql.confでinclude_dir = 'conf.d'のコメントはずして有効にし、個別に読み込ませるのが好き。

archive_mode = on
archive_command = '/usr/bin/envdir /etc/wal-g.d/env /usr/local/bin/wal-g wal-push %p'
archive_timeout = 60
wal_level = replica

archive_timeoutで60秒に一度はWALをアーカイブするようにしている。 すでにレプリケーションを設定していれば、wal_levelの設定は不要。

バックアップする

とりあえず差分から

さっき設定したpostgresqlをrestartして、動いているかどうか、ログを監視する。

sudo pg_ctlcluster 11 main restart
sudo tail -f /var/log/postgresql/postgresql-11-main.log

次にフルバックアップ

sudo -iu postgres envdir /etc/wal-g.d/env wal-g backup-push /var/lib/postgresql/11/main

cronで定期実行を仕込む

毎日フルバックアップ、毎週7つだけ残して古いのを削除、という設定。このへんは任意に。

sudo crontab -u postgres -e
@daily /usr/bin/envdir /etc/wal-g.d/env /usr/local/bin/wal-g backup-push /var/lib/postgresql/11/main
@weekly /usr/bin/envdir /etc/wal-g.d/env /usr/local/bin/wal-g delete retain 7 --confirm

リストアする

リストアしても副作用はないので、バックアップをとりはじめたら、とりあえず一回やってみることをお薦めする。

どこか別のUbuntu環境に復元してみる。
いざという時の復旧手順そのものなので、ちゃんと記録しておいたり、準備しておいたりした方がいいよ。

envdirとか環境変数とかWAL-Gとか準備する

さっきと手順は同じ。

wget -O - https://github.com/wal-g/wal-g/releases/download/v0.2.9/wal-g.linux-amd64.tar.gz|tar xvzf -
sudo mv wal-g /usr/local/bin

sudo apt install daemontools

sudo mkdir -p /etc/wal-g.d/env
sudoedit /etc/wal-g.d/env/AWS_ACCESS_KEY_ID
sudoedit /etc/wal-g.d/env/AWS_SECRET_ACCESS_KEY
echo "https://s3.us-west-1.wasabisys.com" | sudo tee /etc/wal-g.d/env/AWS_ENDPOINT
echo "s3://i.ll.be.back/" | sudo tee /etc/wal-g.d/env/WALG_S3_PREFIX
echo "/var/run/postgresql" | sudo tee /etc/wal-g.d/env/PGHOST
echo "5432" | sudo tee /etc/wal-g.d/env/PGPORT
echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin" | sudo tee /etc/wal-g.d/env/PATH

復元先のクラスタを作って、データディレクトリを空にしとく

sudo pg_createcluster 11 test
sudo sh -c "rm -rf /var/lib/postgres/11/test/*"

最新のフルバックアップを復元

sudo -u postgres envdir /etc/wal-g.d/env wal-g backup-fetch /var/lib/postgresql/11/test/ LATEST

最新の差分を復元

データディレクトリにrecovery.confを作成して

cat <<_EOS_ | sudo -u postgres tee /var/lib/postgresql/11/test/recovery.conf
restore_command = '/usr/bin/envdir /etc/wal-g.d/env /usr/local/bin/wal-g wal-fetch "%f" "%p"'
_EOS_

で、動かす。

sudo pg_ctlcluster 11 test start

必要な差分を適用し、recovery.confがrecovery.doneにリネームされて、書き込み可能な状態になる(リストア完了)

任意の時点に復元する

フルバックアップのリストを表示して、last_modifiedから対象のバックアップのnameをピックアップ

sudo -u postgres envdir /etc/wal-g.d/env wal-g backup-list

LATESTの代わりにnameを指定

sudo -u postgres envdir /etc/wal-g.d/env wal-g backup-fetch /var/lib/postgresql/11/test/ base_000000020000000000000042

recovery.confに日時を指定

cat <<_EOS_ | sudo -u postgres tee /var/lib/postgresql/11/test/recovery.conf
restore_command = '/usr/bin/envdir /etc/wal-g.d/env /usr/local/bin/wal-g wal-fetch "%f" "%p"'
recovery_target_time = '2019-03-04 17:20:00'
_EOS_

という流れです。

サーバ引っ越しの際は?

下準備

  1. 引っ越し先にフルバックアップをbackup-fetchする
  2. recovery.confを作成(wal-fetch)
  3. /etc/postgresql/11/main の設定ファイル類を持ってくる
  4. postgresql.conf の設定内容を、新旧比較して反映する
    このとき、元サーバであらかじめ conf.d/ に設定を分離していれば、postgresql.confそのものをいじらずに済む
  5. pg_hba.conf は接続セキュリティ設定なので、IPアドレスなどの変更を含めて反映し、よく見直しておく
  6. (その他のファイルも、使っていたものがあれば反映する)

本番

  1. 元のデータベースを停止
  2. 引っ越し先のデータベースを開始

という流れになります。

本番前に、一度testクラスタを作って練習しておきましょう。 練習が済んだら、pg_dropcluster 11 test --stopなどでバッサリ削除します。

暗号化は?

説明が長くなるので割愛します :-)

wal-gのgithubを見て、環境変数で、WALG_S3_SSEとかWALG_S3_SSE_KMS_IDとか、WALG_PGP_KEYWALG_PGP_KEY_PATHなどを指定してください。仕組みがわかっていれば簡単です。

参考資料