MySQLの積上げ式バックアップファイル作成

未分類
スポンサーリンク

Ubuntu 24.04 において、標準ライブラリのみで「毎日 0:00 に前日分のデータをバックアップし、3週間で自動削除する」仕組みをまとめました。


1. セキュリティ設定(パスワードの隠蔽)

Pythonスクリプトにパスワードを書かないよう、MySQLの設定ファイルを作成します。

設定ファイルの作成:

nano ~/.my.cnf

内容:

[client]
user = あなたのユーザー名
password = "あなたのパスワード"

権限変更(自分だけが読めるようにする):

chmod 600 ~/.my.cnf

2. Pythonスクリプト (mysql_backup.py)

追加ライブラリ(pip等)は一切不要です。標準機能だけで動作します

import subprocess
import datetime
import os
import glob

# --- 設定項目 ---
DB_NAME = "あなたのデータベース名"
BACKUP_DIR = "/home/user/mysql_backups" # 保存先(絶対パス)
RETENTION_DAYS = 21                    # 3週間(21日)
TIME_COLUMNS = ['created_at', 'timestamp', 'date'] # 日時カラム名の候補

def run_mysql_query(query):
    """MySQLコマンドを直接呼び出して結果を取得する"""
    cmd = ["mysql", "-NB", "-e", query, DB_NAME]
    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
    return result.stdout.strip().split('\n')

def run_backup():
    # 準備:昨日の日付と範囲を計算
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    start_dt = f"{yesterday} 00:00:00"
    end_dt = f"{yesterday} 23:59:59"
    
    if not os.path.exists(BACKUP_DIR):
        os.makedirs(BACKUP_DIR)
    
    backup_path = os.path.join(BACKUP_DIR, f"backup_{yesterday}.sql")

    # 1. テーブル一覧を取得
    tables = run_mysql_query("SHOW TABLES")
    
    with open(backup_path, "w") as f:
        f.write(f"-- Daily Backup: {yesterday}\n")

    for table in tables:
        if not table: continue
        
        # 2. テーブルのカラムを確認
        cols_info = run_mysql_query(f"SHOW COLUMNS FROM {table}")
        cols = [line.split('\t')[0] for line in cols_info if line]
        
        # 候補のカラム名がテーブルにあるか探す
        time_col = next((c for c in TIME_COLUMNS if c in cols), None)

        # 3. バックアップ実行(mysqldump)
        cmd = [
            "mysqldump",
            DB_NAME,
            table,
            "--no-create-info",   # テーブル作成文は含めない(追記用)
            "--insert-ignore",    # 重要:重複データは無視してリストア
            "--complete-insert",  # カラム名を指定したINSERT文にする
            "--single-transaction"
        ]

        if time_col:
            cmd.append(f"--where={time_col} >= '{start_dt}' AND {time_col} <= '{end_dt}'")
            print(f"Backup: {table} ({yesterday})")
        else:
            print(f"Skip: {table} (No time column)")
            continue

        # ファイルに追記
        with open(backup_path, "a") as f:
            subprocess.run(cmd, stdout=f, check=True)

    print(f"Done: {backup_path}")

    # 4. 3週間以上前のファイルを削除
    cutoff = datetime.datetime.now() - datetime.timedelta(days=RETENTION_DAYS)
    for f in glob.glob(os.path.join(BACKUP_DIR, "backup_*.sql")):
        if datetime.datetime.fromtimestamp(os.path.getmtime(f)) < cutoff:
            os.remove(f)
            print(f"Deleted old backup: {f}")

if __name__ == "__main__":
    run_backup()

3. Node-RED での設定

毎日 0:00 にこの Python スクリプトを起動するように設定します。

  1. Injectノード:
    • 繰り返し設定:指定時刻(at a specific time)
    • 時刻:00:00
  2. Execノード:
    • コマンド:python3
    • 引数:/home/user/mysql_backup.py(スクリプトのフルパス)
  3. Debugノード:
    • Execノードの出力を接続して、実行結果を確認。

4. リストア(復元)の考え方

この方式で取ったバックアップは、以下のように**「必要な分だけ積み上げる」**ことができます。

  • 1日目だけ戻したい場合:
    mysql -u ユーザー名 -p DB名 < backup_2023-10-01.sql
  • 3日分まとめたい場合:
    1日目、2日目、3日目のファイルを順番に読み込ませるだけです。
    –no-create-info のおかげで、2日目を流し込んでも1日目のデータは消えません。
  • データが重複している場合:
    –insert-ignore のおかげで、既に存在するデータ(Primary Keyが同じもの)は自動的にスキップされ、エラーにならずに新しいデータだけが追加されます。

メリットのまとめ

  • 容量節約: 毎日「全件」ではなく「昨日分だけ」なのでファイルが小さい。
  • 安全: DROP TABLE が含まれないので、既存データを誤って消すリスクがない。
  • オフライン対応: Ubuntu標準の python3 と mysql-client だけで完結する。
  • 自動管理: 21日経つと Python が古いファイルを自動で掃除する。

コメント

タイトルとURLをコピーしました