PostgreSQL の Backup / Restore ツールとして heroku で開発されたとされる WAL-E がある。 フィジカル(物理)バックアップと WAL のアーカイブを S3 互換のオブジェクトストレージや Azure BLOB Storage や Google Cloud Storage へ保存でき、そこからのリストアもできる便利ツールです。 AWS で EC2 上の PostgreSQL のバックアップ/リストアを WAL-E で行ってみます。OS は Ubuntu 14.04 (Trusty) を使います。
S3 側の準備
バックアップ先となる S3 の Bucket を用意します。既存のものでもかまいません。 Bucket 内の指定のディレクトリ(Path)配下に保存します。 IAM のポリシーを作成
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets"
],
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
}
]
}
EC2 のインスタンス Role を使わない場合は AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY を取得します。 この後の例はインスタンス Role を使っているため –aws-instance-profile オプションを指定してありますが、クレデンシャルを使う場合はこれを削る必要があります。
wal-e のインストール
wal-e は Python で書かれており pip でインストールできます まずは apt で必要なパッケージをインストールします
sudo apt-get update
sudo apt-get install lzop pv python-pip python-dev daemontools -y
daemontools に含まれる envdir コマンドで AWS のクレデンシャルを環境変数として読み込んでコマンドを実行するようにします lzop はファイルの圧縮に使われます pv は disk i/o のレート制限に使われます(バックアップ処理の負荷で影響がでないように) requests と six が古いので更新して wal-e をインストールします
sudo pip install -U requests
sudo pip install -U six
sudo pip install wal-e
$ wal-e -h
usage: wal-e [-h] [-k AWS_ACCESS_KEY_ID | --aws-instance-profile]
[-a WABS_ACCOUNT_NAME] [--s3-prefix S3_PREFIX]
[--wabs-prefix WABS_PREFIX] [--gpg-key-id GPG_KEY_ID] [--terse]
{version,backup-fetch,backup-list,backup-push,wal-push,wal-fetch,wal-prefetch,delete}
...
WAL-E is a program to assist in performing PostgreSQL continuous
archiving on S3 or Windows Azure Blob Service (WABS): it handles pushing
and fetching of WAL segments and base backups of the PostgreSQL data directory.
optional arguments:
-h, --help show this help message and exit
-k AWS_ACCESS_KEY_ID, --aws-access-key-id AWS_ACCESS_KEY_ID
public AWS access key. Can also be defined in an
environment variable. If both are defined, the one
defined in the programs arguments takes precedence.
--aws-instance-profile
Use the IAM Instance Profile associated with this
instance to authenticate with the S3 API.
-a WABS_ACCOUNT_NAME, --wabs-account-name WABS_ACCOUNT_NAME
Account name of Windows Azure Blob Service account.
Can also be defined in an environmentvariable. If both
are defined, the one definedin the programs arguments
takes precedence.
--s3-prefix S3_PREFIX
S3 prefix to run all commands against. Can also be
defined via environment variable WALE_S3_PREFIX.
--wabs-prefix WABS_PREFIX
Storage prefix to run all commands against. Can also
be defined via environment variable WALE_WABS_PREFIX.
--gpg-key-id GPG_KEY_ID
GPG key ID to encrypt to. (Also needed when
decrypting.) Can also be defined via environment
variable WALE_GPG_KEY_ID
--terse Only log messages as or more severe than a warning.
subcommands:
{version,backup-fetch,backup-list,backup-push,wal-push,wal-fetch,wal-prefetch,delete}
version print the wal-e version
backup-fetch fetch a hot backup from S3 or WABS
backup-list list backups in S3 or WABS
backup-push pushing a fresh hot backup to S3 or WABS
wal-push push a WAL file to S3 or WABS
wal-fetch fetch a WAL file from S3 or WABS
wal-prefetch Prefetch WAL
delete operators to destroy specified data in S3 or WABS
PostgreSQL のインストール
sudo apt-get install postgresql-9.3 -y
Ubuntu の場合、データベースの設定ファイルは /etc/postgresql/9.3/main/ 配下に、データは /var/lib/postgresql/9.3/main/ 配下に設置されます アーカイブモードの設定を行います
sudoedit /etc/postgresql/9.3/main/postgresql.conf
wal_level = archive # hot_standby でも可
archive_mode = on
archive_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile wal-push %p'
archive_timeout = 60 # WAL ファイルがいっぱいにならなくてもこの秒数が経過すればログスイッチしてアーカイブする
反映には再起動が必要ですがそれは envdir 設定の後で
envdir 用設定
場所に決まりはありませんが /etc/wal-e.d/env/ ディレクトリを作成し、そこに設定したい環境変数名のファイルを作成し値を入れます
sudo mkdir -p /etc/wal-e.d/env
sudoedit /etc/wal-e.d/env/AWS_ACCESS_KEY_ID # インスタンス Role を使う場合は不要
sudoedit /etc/wal-e.d/env/AWS_SECRET_ACCESS_KEY # インスタンス Role を使う場合は不要
sudoedit /etc/wal-e.d/env/AWS_REGION # 東京なので ap-northeast-1
sudoedit /etc/wal-e.d/env/WALE_S3_PREFIX # s3://YOUR_BUCKET_NAME/SUBDIR
sudo chown -R root:postgres /etc/wal-e.d
sudo chmod -R o-rwx /etc/wal-e.d
バックアップの実行
sudo service postgresql restart
archive_command が正常に実行されるかどうかログ (/var/log/postgresql/postgresql-9.3-main.log) を確認します
wal_e.main INFO MSG: starting WAL-E
DETAIL: The subcommand is "wal-push".
STRUCTURED: time=2016-09-01T14:39:52.182896-00 pid=23763
wal_e.worker.upload INFO MSG: begin archiving a file
DETAIL: Uploading "pg_xlog/000000010000000000000002" to "s3://YOUR_BUCKET_NAME/SUBDIR/wal_005/000000010000000000000002.lzo".
STRUCTURED: time=2016-09-01T14:39:52.234031-00 pid=23763 action=push-wal key=s3://YOUR_BUCKET_NAME/SUBDIR/wal_005/000000010000000000000002.lzo prefix=SUBDIR/ seg=000000010000000000000002 state=begin
wal_e.worker.upload INFO MSG: completed archiving to a file
DETAIL: Archiving to "s3://YOUR_BUCKET_NAME/SUBDIR/wal_005/000000010000000000000002.lzo" complete at 609.625KiB/s.
STRUCTURED: time=2016-09-01T14:39:52.462079-00 pid=23763 action=push-wal key=s3://YOUR_BUCKET_NAME/SUBDIR/wal_005/000000010000000000000002.lzo prefix=SUBDIR/ rate=609.625 seg=000000010000000000000002 state=complete
sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-push /var/lib/postgresql/9.3/main
これでデータベース全体のバックアップが行われます
$ sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-push /var/lib/postgresql/9.3/main
wal_e.main INFO MSG: starting WAL-E
DETAIL: The subcommand is "backup-push".
STRUCTURED: time=2016-09-01T14:39:51.941209-00 pid=23737
wal_e.operator.backup INFO MSG: start upload postgres version metadata
DETAIL: Uploading to s3://YOUR_BUCKET_NAME/SUBDIR/basebackups_005/base_000000010000000000000003_00000040/extended_version.txt.
STRUCTURED: time=2016-09-01T14:39:52.237635-00 pid=23737
wal_e.operator.backup INFO MSG: postgres version metadata upload complete
STRUCTURED: time=2016-09-01T14:39:52.368084-00 pid=23737
wal_e.worker.upload INFO MSG: beginning volume compression
DETAIL: Building volume 0.
STRUCTURED: time=2016-09-01T14:39:52.399796-00 pid=23737
wal_e.worker.upload INFO MSG: begin uploading a base backup volume
DETAIL: Uploading to "s3://YOUR_BUCKET_NAME/SUBDIR/basebackups_005/base_000000010000000000000003_00000040/tar_partitions/part_00000000.tar.lzo".
STRUCTURED: time=2016-09-01T14:39:52.720335-00 pid=23737
wal_e.worker.upload INFO MSG: finish uploading a base backup volume
DETAIL: Uploading to "s3://YOUR_BUCKET_NAME/SUBDIR/basebackups_005/base_000000010000000000000003_00000040/tar_partitions/part_00000000.tar.lzo" complete at 8799.85KiB/s.
STRUCTURED: time=2016-09-01T14:39:53.112379-00 pid=23737
NOTICE: pg_stop_backup complete, all required WAL segments have been archived
backup-list サブコマンドでベースバックアップのリストが確認できまう
$ sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-list
wal_e.main INFO MSG: starting WAL-E
DETAIL: The subcommand is "backup-list".
STRUCTURED: time=2016-09-01T14:50:11.054832-00 pid=24023
name last_modified expanded_size_bytes wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop
base_000000010000000000000003_00000040 2016-09-01T14:39:55.000Z 000000010000000000000003 00000040
base_000000010000000000000007_00000040 2016-09-01T14:49:02.000Z 000000010000000000000007 00000040
base_000000010000000000000009_00000040 2016-09-01T14:49:27.000Z 000000010000000000000009 00000040
--detail
をつけるともう少し情報が増えますが、それぞれについて S3 にアクセスすることになるので大量にある時間がかかります
$ sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-list --detail
wal_e.main INFO MSG: starting WAL-E
DETAIL: The subcommand is "backup-list".
STRUCTURED: time=2016-09-01T14:51:08.766735-00 pid=24049
name last_modified expanded_size_bytes wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop
base_000000010000000000000003_00000040 2016-09-01T14:39:55.000Z 19603869 000000010000000000000003 00000040 000000010000000000000003 00000184
base_000000010000000000000007_00000040 2016-09-01T14:49:02.000Z 26102357 000000010000000000000007 00000040 000000010000000000000007 00000184
base_000000010000000000000009_00000040 2016-09-01T14:49:27.000Z 26110549 000000010000000000000009 00000040 000000010000000000000009 00000184
リストアする
PostgreSQL を停止してデータディレクトリを空っぽにする
sudo service postgresql stop
sudo rm -fr /var/lib/postgresql/9.3/main
sudo install -o postgres -g postgres -m 0700 -d /var/lib/postgresql/9.3/main
backup-fetch サブコマンドでベースバックアップを取得する
$ sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-fetch /var/lib/postgresql/9.3/main LATEST
wal_e.main INFO MSG: starting WAL-E
DETAIL: The subcommand is "backup-fetch".
STRUCTURED: time=2016-09-01T15:01:12.084425-00 pid=24131
wal_e.worker.s3.s3_worker INFO MSG: beginning partition download
DETAIL: The partition being downloaded is part_00000000.tar.lzo.
HINT: The absolute S3 key is waletest2/basebackups_005/base_000000010000000000000009_00000040/tar_partitions/part_00000000.tar.lzo.
STRUCTURED: time=2016-09-01T15:01:12.439743-00 pid=24131
recovery.conf を作成する restore_command に wal-fetch サブコマンドを指定します、これでベースバックアップ後の WAL ファイルを順に取得して最後の WAL archive 時点まで復旧されます
cat <<_EOF_ | sudo -u postgres tee /var/lib/postgresql/9.3/main/recovery.conf
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile wal-fetch "%f" "%p"'
_EOF_
PostgreSQL の起動
sudo service postgresql start
ログ (/var/log/postgresql/postgresql-9.3-main.log) を確認 recovery.conf が recovery.done になっててデータが復元されていることを確認
指定の時刻の状態に復元する
さっきは LATEST 指定で最新のベースバックアップを取得したが、もっと前の状態に戻したいのでバックアップの名前指定で取得する
sudo service postgresql stop
sudo rm -fr /var/lib/postgresql/9.3/main
sudo install -o postgres -g postgres -m 0700 -d /var/lib/postgresql/9.3/main
sudo -u postgres envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-fetch /var/lib/postgresql/9.3/main base_000000010000000000000003_00000040
cat <<_EOF_ | sudo -u postgres tee /var/lib/postgresql/9.3/main/recovery.conf
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile wal-fetch "%f" "%p"'
recovery_target_time = '2016-09-01 14:49:30'
_EOF_
sudo service postgresql start
これで 2016-09-01 14:49:30 時点の状態に戻りました。recovery_target_time はミリ秒まで指定可能。
定期実行
ベースバックアップは cron などで日次や週次で定期的に実行します 毎日夜中の3時にベースバックアップを取得する設定
0 3 * * * /usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile backup-push /var/lib/postgresql/9.3/main
バックアップの削除
ベースバックアップは圧縮されてはいるもののフルバックアップなので沢山持つと大きなサイズになっていまいます。 そこからの WAL ファイルを全部持つのも大きなサイズになるので定期的に古いものを削除することになると思います。 次のように delete retain 3 とすることで最新の3つ残して古いものを削除することができます これも cron などで定期実行すると良いでしょう
/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e --aws-instance-profile delete --confirm retain 3
delete everything で全部、delete before base_000000010000000000000009_00000040 で指定のバックアップより古いもの(指定したものは残る)を削除できます –confirm を付けない場合は削除対象が表示されるだけです
ファイルの暗号化
gpg を使ってファイルを暗号化して保存することもできます
WAL-E を使った replication
マスタ側の archive_command で backup-push し、レプリカ側の recovery.conf で wal-fetch するようにしておけば S3 などを経由したレプリケーションを組むことも可能です。 Streaming Replication を組めないネットワーク環境では便利かも。