RDS(postgres)のデータダンプとリストアサンプル

私のトコだとRDSにPostgres入れて運用しています。普段はpgadmin3でデータダンプやリストアをやったりするのですが、RDSのスナップショットのような大掛かりなものではなく、一部のテーブルだけでいいので定期的なデータバックアップを取りたいという要望がありましたので作りました。以下実装録。

#要件定義
・AWS触れるの私だけ。
・そもそもSQL知ってるのが私だけ。
・個々のPCにpgadmin3インストールしてやったのに誰も触らない。
・定期バックアップを取りたいのは商品データ関連だけ。
・定期バックアップとは別に「今のデータを保存しとく」というのも欲しい。
・世代はそんなに必要ではない（というか世代管理という意識がなかったのでなんとなく３世代とした）。

#実装にむけてその１　どこに保存するか
これは考えるまでもなくローカルサーバー。何故ならば他にサーバーないから。

#実装にむけてその２　pgdumpとpsqlのインストール
2015/06/11現在RDSのPostgresは9.3.6でした。のでpgdumpとpsqlもそれに準じたものをインストールして使います。以下はローカルサーバー上で行ったPostgres-9.3.6のインストール手順です。
<pre>
cd /usr/local/src
wget http://ftp.postgresql.org/pub/source/v9.3.6/postgresql-9.3.6.tar.gz
tar zxvf postgresql-9.3.6.tar.gz
cd ./postgresql-9.3.6
./configure --without-readline
make
make install
</pre>
あくまでダンプ・リストアのツールとして使うだけなのでパスを切り替えたりする必要はありません。でもテスト環境のDBも本番と同じにしておきたいというならご随意に。

## ダンプ・リストアサンプル
※{}内は実際の値に置き換える。
{hostname}…RDSのホスト名。
{username}…接続ユーザ名。
{dbname}…データベース名。
{tablename}…テーブル名。
{port}…ポート番号。デフォルトだと5432。
{password}…パスワード。

・*pg_dumpサンプル*
<pre>
/usr/local/src/postgresql-9.3.6/src/bin/pg_dump/pg_dump -h {hostname} -U {username} {dbname} -t {tablename} > {tablename}.txt
</pre>

・*リストアサンプル*
<pre>
/usr/local/src/postgresql-9.3.6/src/bin/psql/psql -h {hostname} -U {username} {dbname} < {tablename}.txt
</pre>

#実装に向けてその３　パスワード入力を省く
いちいちパスワードを入力するのはタルいし自動ツールにならないのでなんとかします。具体的にはRDSへの接続ユーザーと同名のユーザー作ってパスワードファイルを配置します。

・RDSへの接続ユーザと同名のユーザを作成する（pg_dumpサンプルの{username}）
<pre>
useradd {username}
</pre>

・{username}ユーザのカレントディレクトリに以下のファイルを作成。※所有権は{username}ユーザにする。
<pre>
touch .pgpass
</pre>

・.pgpassの内容を以下のように。
<pre>
{hostname}:{port}:{dbname}:{password}
</pre>

#実装に向けてその４　実際に動かすスクリプト開発
以下のスクリプトは{username}ユーザーのホームディレクトリに置いて実行されることを想定しています。ホスト名とかの機密情報は当然{}に置き換えてありますのでこれをこのまま動かそうとしても動きません。

なおウチはEC-CUBEを使っているのでテーブル名を隠す必要もないのでそのまま書いてあります。置き換えなかった理由は置き換えるのが面倒だったからです。

・*rotate.sh*
ダンプを実行して３世代管理するスクリプト。なぜ名前がrotateなんだろう。なお編集上シャープが（＃）が使えなかったので＃!/bin/shは省略してあります。
<pre>
PATH=/usr/local/sbin:/usr/bin:/bin
BACKUP_DIR=/home/{username}/pgdata
PGDUMP=/usr/local/src/postgresql-9.3.6/src/bin/pg_dump/pg_dump
DATE=`/bin/date '+%Y%m%d'`
DELETE_DAY=`/bin/date -d '3 day ago' +%Y%m%d`

if [ -e $BACKUP_DIR/$DATE ]; then
rm -rf $BACKUP_DIR/$DATE
fi
mkdir -p "$BACKUP_DIR/$DATE"
cd $BACKUP_DIR/$DATE
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_category  > dtb_category.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_product_categories > dtb_product_categories.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_products > dtb_products.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_products_class > dtb_products_class.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_class_combination > dtb_class_combination.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_classcategory > dtb_classcategory.txt
$PGDUMP -h {hostname} -U {username} {dbname} -t dtb_class > dtb_class.txt

if [ -d "$BACKUP_DIR/$DELETE_DAY" ]; then
cd "$BACKUP_DIR"

rm -rf "$BACKUP_DIR/$DELETE_DAY"
echo $TEST_DAY
fi
</pre>

・*restore.sh*
リストア用スクリプト。よく読むとわかるけど一番直近のデータをリストアするように作ってある。
<pre>
PATH=/usr/local/sbin:/usr/bin:/bin
BACKUP_DIR=/home/{username}/pgdata
TARGETDIR=`/bin/ls -1 $BACKUP_DIR  | /usr/bin/tail -1`
PSQL=/usr/local/src/postgresql-9.3.6/src/bin/psql/psql

$PSQL -U {username} -h {hostname} {dbname} << EOF
drop view uvw_parent_category_name;
drop table dtb_category;
drop table dtb_class;
drop table dtb_class_combination;
drop table dtb_classcategory;
drop table dtb_product_categories;
drop table dtb_products;
drop table dtb_products_class;
\q
EOF
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_category.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_class.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_class_combination.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_classcategory.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_product_categories.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_products.txt
$PSQL -U {username} -h {hostname} {dbname}  < $BACKUP_DIR/$TARGETDIR/dtb_products_class.txt
EOF
</pre>


#実装に向けてその５　crontab設定
別に特別な事はなにもありません。起動時間もどうぞご自由に。あえて注意すると{username}ユーザーのcronに書いておかないと実行権限とかパスとかの問題で動かないと思います。
<pre>
45  2  *  *  * /home/{username}/rotate.sh
</pre>

#最後の課題　WindowsUIの提供
私はずーっとlinux環境での開発しかやってこなかったのでWindows系の開発はトンと分かりません。のでどうやってWindows上で動くUIを提供するかを悩みましたが、結局いつも使ってるteratermのオマケに入ってるttpmacroを使ってマクロを組むのが一番ラクだったのでそうしました。

{localserverip}…ローカルサーバーIP。ドメインでも可。
{username}…起動ユーザー。この場合はlinuxログインユーザ。
{linux-passowrd}…linuxログインユーザーのパスワード。

・*商品データ手動バックアップ.ttl*
<pre>
;============================================== 
;; 接続先ホスト／ユーザ名／パスワード設定 
HOSTADDR = '{localserverip}' 
USERNAME = '{username}' 
PASSWORD = '{linux-passowrd}' 
;============================================== 
;; ①コマンド組立て 
COMMAND = HOSTADDR 
strconcat COMMAND ':22 /ssh /2 /auth=password /user=' 
strconcat COMMAND USERNAME 
strconcat COMMAND ' /passwd=' 
strconcat COMMAND PASSWORD

;; ②接続 
connect COMMAND

wait '$'
sendln './restore.sh'
wait '$'
sendln 'logout'

;; ③マクロ終了 
end
</pre>

・*商品データリストア.ttl*
<pre>
;============================================== 
;; 接続先ホスト／ユーザ名／パスワード設定 
HOSTADDR = '{localserverip}' 
USERNAME = '{username}' 
PASSWORD = '{linux-passowrd}' 
;============================================== 
;; ①コマンド組立て 
COMMAND = HOSTADDR 
strconcat COMMAND ':22 /ssh /2 /auth=password /user=' 
strconcat COMMAND USERNAME 
strconcat COMMAND ' /passwd=' 
strconcat COMMAND PASSWORD

;; ②接続 
connect COMMAND

wait '$'
sendln './restore.sh'
wait '$'
sendln 'logout'

;; ③マクロ終了 
end
</pre>

よく読むとわかるけど世代バックアップも手動バックアップも同じ本日フォルダに入れてるんだなこれが。