Heroku Postgresのバックアップ手法
Heroku Postgresのバックアップを行うには以下の方法があります。
- 物理バックアップ
- 論理バックアップ
物理バックアップの制限
「物理バックアップ」の機能は「Standard」以上のプランの場合のみ利用可能なようなので、今回は「論理バックアップ」にフォーカスして説明していきます。
![]() |
「Heroku Postgres」の「Durability」の画面にて |
![]() |
「Heroku Postgres のデータの安全性と継続的保護」より抜粋 |
論理バックアップの制限
Heroku Postgres には 「Heroku PGBackups」というバックアップ機能が提供されており、バックアップを定期実行する場合も簡単に設定可能です。
- Heroku PGBackups(英語)
- Heroku PGBackups(日本語)
ただし、「Heroku PGBackups」には「データベースのサイズが20GBまで」という制限があるようです。
今回、「Heroku PGBackups」の利用をやめて自前実装に切り替える理由はこれです。
「Heroku PGBackups」の機能を利用して定期バックアップを行っていたつもりが、実はバックアップに失敗していましたといったことがないように注意しましょう。
![]() |
「Heroku Postgres の論理バックアップ」より抜粋 |
![]() |
「Heroku PGBackups」より抜粋 |
Heroku PGBackupsの仕組み
自前実装を始める前に、Heroku PGBackupsの仕組みについて理解していきます。
「Heroku PGBackups を使用した小さなデータベースでの論理バックアップの取得」で説明されているとおり、 heroku pg:backups
の実体は pg_dump
と pg_restore
です。
heroku pg:backups
でバックアップのIDを取得し、どこに保存されているかを確認すると、Amazon S3に保存されていることがわかります。
$ heroku pg:backups --app アプリケーション名
=== Backups
Id Created at Status Size Database
──── ───────────────────────── ─────────────────────────────────── ────── ────────
b001 2025-03-01 23:22:23 +0000 Completed 2025-03-01 23:22:25 +0000 1.93KB DATABASE
=== Restores
No restores found. Use heroku pg:backups:restore to restore a backup
=== Copies
No copies found. Use heroku pg:copy to copy a database to another
$ heroku pg:backups:url b001 --app アプリケーション名
https://xxxxx.s3.amazonaws.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/2025-03-01T23%3A22%3A23Z/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxxxxxxxxxxxx%2F20250302%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250302T001750Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Heroku Postgresの定期バックアップを自前実装するための仕様
Heroku PGBackupsの仕組みを踏まえて、以下のような仕様で実装を行っていきます。
- バックアップ処理はシェルスクリプト(bash)で実装する。
- PostgreSQLのバックアップコマンドである
pg_dump
を利用する。 -
pg_dump
で出力されたダンプファイルをgzip
コマンドで圧縮する。 - gzip圧縮したファイルファイルをAmazon S3にアップロードする。
- Heroku Schedulerを利用してバックアップ処理を定期実行する。
事前準備
- Amazon S3の操作が可能なIAMアカウントを準備します。
- 「Heroku buildpack for the AWS CLI」の手順に従って、ビルドパックを追加します。
- この手順内でHerokuのConfig VarsにS3を操作可能なIAMアカウントの「
AWS_ACCESS_KEY_ID
」、「AWS_SECRET_ACCESS_KEY
」、「AWS_DEFAULT_REGION
」を追加します。
- この手順内でHerokuのConfig VarsにS3を操作可能なIAMアカウントの「
- HerokuのConfig VarsにS3のバケット名を「
AWS_S3_BUCKET
」として追加します。 - HerokuのConfig Varsの登録状況を確認します。
- Heroku SchedulerをAdd-onsとして追加します。
バックアップスクリプトを実装
- 処理の流れ
- Config Varsで登録済みの各環境変数の必須入力チェックを行う。
-
pg_dump
コマンドでダンプファイルを出力する。- 「より大規模なデータベースでの論理バックアップの取得」では、オプションに「
-F c
」が指定されていますが、圧縮についてはgzip
コマンドを利用するので、プレーンテキストとするために「-F p
」を指定しました。 - 「
-F c
」を利用すると、ダンプファイルの中身をテキストエディタで開いて確認するといったことができなくなるため、今回は「-F p
」を採用しました。
- 「より大規模なデータベースでの論理バックアップの取得」では、オプションに「
- 出力されたダンプファイルを
gzip
コマンドで圧縮する。 - gzip圧縮されたファイルをAWS CLI(
aws s3 cp
)でAmazon S3にアップロードする。 - 本番環境の場合であれば、成功・失敗時のSlackなどへの通知処理については実装しておいた方がよいですが、今回は処理を簡素化するために実装内容から割愛しています。
$ cat pgbackup.sh
#!/bin/bash
set -eu
set -o pipefail
# 環境変数の必須入力チェック
if [ -z "${DATABASE_URL:-}" ]; then
exit 1
fi
if [ -z "${AWS_S3_BUCKET:-}" ]; then
exit 1
fi
if [ -z "${AWS_ACCESS_KEY_ID:-}" ]; then
exit 1
fi
if [ -z "${AWS_SECRET_ACCESS_KEY:-}" ]; then
exit 1
fi
if [ -z "${AWS_DEFAULT_REGION:-}" ]; then
exit 1
fi
BACKUP_FILE_NAME="dump_$(TZ=Asia/Tokyo date +%Y%m%d_%H%M%S).sql.gz"
BACKUP_FILE_PATH="/tmp/${BACKUP_FILE_NAME}"
# データベースのダンプ処理
if ! pg_dump -F p --no-acl --no-owner --quote-all-identifiers "${DATABASE_URL}" | gzip > "${BACKUP_FILE_PATH}"; then
exit 1
fi
# AWS_S3_BUCKETの末尾に「/」が含まれる場合は「%/」により削除する
S3_BUCKET_PATH="${AWS_S3_BUCKET%/}/${BACKUP_FILE_NAME}"
# S3へのアップロード処理
if ! aws s3 cp "${BACKUP_FILE_PATH}" "${S3_BUCKET_PATH}"; then
exit 1
fi
exit 0
バックアップスクリプトを反映
$ git add pgbackup.sh
$ git commit -m "add pgbackup script"
$ git push heroku main
バックアップスクリプトを手動実行して動作確認
利用している「Heroku-24 Stack」は「Ubuntu 24.04」をベースにしているため、「 sh pgbackup.sh
」と実行するとdashが実行されるはずなので、明示的に「 bash pgbackup.sh
」として実行しています。
$ heroku run bash pgbackup.sh
Running bash pgbackup.sh on ⬢ アプリケーション名... up, run.9667
upload: ../tmp/dump_20250302_104213.sql.gz to s3://バケット名/dump_20250302_104213.sql.gz
shebangに #!/bin/bash
と記述しているので、「 sh pgbackup.sh
」と実行しても実際には問題ないかもしれませんが、実行権限を付与して以下のように実行することも可能です。
$ chmod +x pgbackup.sh
$ heroku run ./pgbackup.sh
Running ./pgbackup.sh on ⬢ アプリケーション名... up, run.7937
upload: ../tmp/dump_20250302_105126.sql.gz to s3://バケット名/dump_20250302_105126.sql.gz
Amazon S3にアップロードされていることを確認
上記の手動実行により、2つのファイルがアップロードされています。
Heroku Schedulerによる定期実行の設定
Heroku Schedulerの画面で「Create Job」をクリックします。
Job Editorの画面で以下のように昼の12時(JST)に実行されるように設定します。
Jobの登録に成功すると以下のように一覧画面に表示されます。
Heroku Schedulerにより定期実行されていることを確認
指定していた「昼の12時(JST)」になると定期処理が実行され、S3にファイルがアップロードされています。
Heroku SchedulerのJob一覧画面には次回の実行タイミングが更新され「翌日の昼の12時(JST)」が表示されています。
以上がHeroku PGBackupsから自前実装による論理バックアップへの切り替え作業になります。
バックアップ実行時の通知処理の実装やS3のライフサイクル設定などについては割愛しましたが、ひとまずこれで定期バックアップ自体は実現可能かと思いますので、Heroku Postgresのサイズが20GB以上になりそうな場合は参考にしてみてください。