これまでDBのバックアップはずっと手動で取っていました。必要なときにSSHで接続して mysqldump を叩く、という運用です。
ただ、これがじわじわと面倒になってきました。「あとでやろう」が積み重なると、いざというときにバックアップが古すぎて使えない……という事態も起こりかねません。
そこで、cronを使った自動バックアップの仕組みを作ることにしました。ついでに、バックアップが成功したかどうかをGmailで通知する機能も一緒に実装しています。
今回やったことの全体像
- バックアップ専用のMySQLユーザを作成し、最小権限で運用
- パスワードは
.my.cnfで安全に管理 - シェルスクリプトでダンプ → gzip圧縮 → 14日間保持
- cronで毎日AM3:00に自動実行
- 実行結果(成功 / 失敗)をGmail経由でメール通知
とくにつまずくところはありませんでした。Linux上でシェルスクリプトを書いた経験があれば、そこまで苦労しないと思います。
1. バックアップ専用ユーザの作成
まず、バックアップ用途に特化したMySQLユーザを作成します。rootでバックアップを取ることもできますが、万が一スクリプトに問題があったときのリスクを考えると、必要最小限の権限だけを持ったユーザを使うのが安全です。
MySQL# まずMySQLにログイン
mysql -u root -p
-- バックアップ専用ユーザを作成
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'your_password';
-- バックアップに必要な最小限の権限を付与
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, PROCESS, EVENT
ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
exit;
'your_password' の部分は、実際に使用する強力なパスワードに置き換えてください。
2. パスワードを安全に管理する
スクリプト内にパスワードを直書きするのは避けたいので、~/.my.cnf にMySQL接続情報を記述しておきます。パーミッションを 600 にすることで、自分以外は読めないようにします。
[mysqldump]
user=backup_user
password=your_password
パーミッション設定
chmod 600 ~/.my.cnf
これで mysqldump 実行時に --defaults-file オプションでこのファイルを指定すれば、コマンドラインにパスワードを書く必要がなくなります。
3. バックアップスクリプトの作成
バックアップ本体のシェルスクリプトを作成します。ダンプした結果をgzipで圧縮し、日付つきのファイル名で保存、古いファイルは自動削除する構成です。
ディレクトリ準備mkdir -p /home/centos/scripts
/home/centos/scripts/mysql_backup.sh
#!/bin/bash
# /home/centos/scripts/mysql_backup.sh
# 設定
DB_NAME="your_dbname"
BACKUP_DIR="/var/backups/mysql"
DATE=$(date +"%Y%m%d_%H%M%S")
RETENTION_DAYS=14 # 14日分保持
# ディレクトリがなければ作成
mkdir -p "$BACKUP_DIR"
# バックアップ実行
mysqldump --defaults-file=/home/centos/.my.cnf \
--single-transaction \
--routines \
--triggers \
--databases "$DB_NAME" \
| gzip > "$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"
# 結果チェック
if [ $? -eq 0 ]; then
echo "[$(date)] Backup succeeded: ${DB_NAME}_${DATE}.sql.gz" >> "$BACKUP_DIR/backup.log"
else
echo "[$(date)] Backup FAILED" >> "$BACKUP_DIR/backup.log"
fi
# 古いバックアップを削除
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
--single-transaction を付けることで、InnoDB環境であればテーブルロックなしで一貫性のあるバックアップが取れます。--routines と --triggers でストアドプロシージャやトリガーも含めてダンプしています。
4. 手動で動作確認
cronに登録する前に、まずスクリプトが正しく動くことを確認します。
動作確認コマンド# 実行権限を付与
chmod +x /home/centos/scripts/mysql_backup.sh
# 手動実行
sudo bash /home/centos/scripts/mysql_backup.sh
# バックアップファイルが作成されたか確認
ls -lh /var/backups/mysql/
# 中身が正しいか先頭を確認
gunzip -c /var/backups/mysql/your_dbname_*.sql.gz | head -50
ファイルが生成されていて、head -50 でSQLの中身が確認できれば成功です。
5. cronで定期実行を登録
動作確認ができたら、crontabに登録して自動化します。
crontab登録# cron編集画面を開く
sudo crontab -e
# 以下を追記(毎日 AM 3:00 にバックアップ実行)
0 3 * * * /bin/bash /home/centos/scripts/mysql_backup.sh
# 登録内容を確認
sudo crontab -l
これでバックアップの自動化は完了です。
バックアップを定期的に取っておくことで、単なる障害復旧だけでなく「過去14日間のデータで検証できる」という安心感が得られます。本番データの変更前後を比較したいときなどに、この仕組みがあるだけで心理的にかなり楽になりました。
6. Gmail送信による結果通知
バックアップが成功したのか失敗したのか、毎回サーバーにログインして確認するのは本末転倒です。そこで、実行結果をGmail経由でメール通知する仕組みも合わせて作りました。
Googleアプリパスワードの発行
まず、Gmailからプログラム経由で送信するために、アプリパスワードを発行します。
メール送信スクリプトの作成
/home/centos/scripts/send_mail.py#!/usr/bin/env python3
import smtplib
import sys
from email.mime.text import MIMEText
GMAIL_USER = "xxxx@gmail.com"
GMAIL_APP_PASS = "xxxx xxxx xxxx xxxx" # アプリパスワード
TO_ADDR = "xxxx@example.co.jp"
subject = sys.argv[1] if len(sys.argv) > 1 else "No Subject"
body = sys.argv[2] if len(sys.argv) > 2 else ""
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = GMAIL_USER
msg["To"] = TO_ADDR
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(GMAIL_USER, GMAIL_APP_PASS)
server.send_message(msg)
送信テスト
テスト送信python3 /home/centos/scripts/send_mail.py "test mail" "This is a test."
指定した送信先にメールが届けば成功です。あとはバックアップスクリプトの結果チェック部分からこのスクリプトを呼び出すようにすれば、バックアップの成功・失敗がメールで届くようになります。
このメール送信の仕組み自体はさほど難しくありません。バックアップの通知だけでなく、稼働中のシステムで何かしらの異常を検知したときの通知や、定期処理の完了報告など、さまざまな場面で使い回せそうです。
まとめ
今回のポイント
手動だったDBバックアップをcronで自動化し、Gmail通知と組み合わせることで「放っておいても安心」な仕組みが完成しました。過去14日間のデータを保持しているので、いざというときの復旧や検証にも対応できます。
Gmail送信の実装も簡単なので、バックアップに限らず、システム監視や定期処理の通知など幅広い用途に応用できるのが嬉しいポイントです。つまずく箇所もほとんどなく、やってみると「もっと早くやればよかった」と感じる改善でした。