MariaDBのバックアップを考える

Linux

Linuxを使ったサーバー運用は長年してはいるのですが、バックアップについてはあまり真面目に取り組んできませんでした。ほぼプライベート用途なので、壊れたら作り直せばいいや、的なノリで運用してきたからなのですが。で、それで最近痛い目を見た気もするのですががが。

痛い目を最近と言いましても数年前の事でして、それを機にサーバーを仮想化しています。かなり前にESXiの4・5辺りで構築したことがあるのですが、どうも仮想化環境が気持ち悪くて実マシンに戻していました。Windowsも含めると3台動かしていましたがそれ以外に作業用のマシンが複数台あるのでメンテも電気代も相当なものでした。その後数年が経ち仮想化にも抵抗がなくなった(というよりコスト的に受け入れざるを得なくなった)のでESXi8で一年弱運用しましたが例のアレで別の仮想化プラットフォームへ移行しました。今回は新環境にも慣れてきたので真面目にバックアップでもしておこうかな~というわけです。

バックアップにもいろいろあるんですが、今回はCMS等で使用するデータベースのバックアップをやってみます。(※おま環が十分考えられます。環境によっては思うような結果が出ない可能性がありますのでご注意ください。)

Linux環境

現在はAlmaLinux9を使用しています。以前はCentOSを使用していましたがあんなことになったので乗り換えました。CentOSは3くらいから7まで使っていまして、それ以前はTurbo LinuxやVine Linuxを使っていたような気がします。

  • AlmaLinux 9.*
  • MariaDB 11.*.*
  • PHP8.*

仮想化プラットフォームやLinuxバージョンを含めあまり細かい環境はセキュリティ上記載を控えますが大体こんな感じです。というかAlmaLinux10がリリースされているとは知りませんでした。うっかりです。

バックアップの方針

  • スクリプトファイル名は backup_mariadb.sh
  • 保存ディレクトリは /backup/mariadb
  • 保存期間は30日(以降は古い物から削除する)
  • データの圧縮はしない
  • システムDBは除外する
  • cronでの実行回数は一日一回、例として時間は午前3時

極力安全にバックアップが取れるように目指します。

スクリプト本体

#!/bin/bash
set -euo pipefail

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 設定
BACKUP_BASE="/backup/mariadb"   # 保存ディレクトリ
RETENTION_DAYS=30               # 保存期間(日数)

# バックアップ先ディレクトリ(例: /backup/mariadb/2025-11-20_030000)
TIMESTAMP="$(date +%F_%H%M%S)"
BACKDIR="${BACKUP_BASE}/${TIMESTAMP}"

# バックアップ先を作成
mkdir -p "${BACKDIR}"

# データベース一覧取得(システムDBを除外)→ 配列に格納
mapfile -t DBLIST < <(
  mariadb -B -N -e 'SHOW DATABASES;' \
    | grep -Ev '^(information_schema|performance_schema|mysql|sys)$'
)

# 各データベースをバックアップ
for dbname in "${DBLIST[@]}"; do
    logger -t mariadb-backup "start backup db=${dbname}"

    if mariadb-dump \
        --events \
        --single-transaction \
        --quick \
        --routines \
        "${dbname}" > "${BACKDIR}/${dbname}.sql" \
        2> >(logger -t mariadb-backup -p user.err); then
        logger -t mariadb-backup "success db=${dbname}"
    else
        logger -t mariadb-backup "FAILED db=${dbname}"
    fi
done

# 古いバックアップの削除(RETENTION_DAYS より古いディレクトリを削除)
find "${BACKUP_BASE}" -mindepth 1 -maxdepth 1 -type d -mtime +"${RETENTION_DAYS}" \
    -print -exec rm -rf {} \;

※環境(フォント)によりバックスラッシュ(\)が¥になっているかも知れません。
--routines オプションが付いていますがデータベース内にプロシージャやファンクションを使用していない場合はこのオプションは不要です。つけていても実害はないと思われますがその分の処理時間が加わります。

スクリプトの実行方法

/usr/local/sbin/にスクリプトを保存

viを起動しスクリプトを入力。保存すると /usr/local/sbin/backup_mariadb.sh で保存されます。vi以外のテキストエディタでもOK。

# vi /usr/local/sbin/backup_mariadb.sh

※他所で作成した場合は /usr/local/sbin/ にコピーしても構いません。ファイルの所有者はrootを想定しています。

次に実行権限を付与します。

sudo chmod 700 /usr/local/sbin/backup_mariadb.sh

バックアップ保存用ディレクトリを作成します。

sudo mkdir -p /backup/mariadb

次にディレクトリの所有者をrootにします。

sudo chown root:root /backup/mariadb

cronに登録する(毎日3時に実行する場合)

sudo crontab -e

エディタを起動して下記の一行を追加します。

0 3 * * * /usr/local/sbin/backup_mariadb.sh >/var/log/backup_mariadb.log 2>&1

これで

  • 毎日 3:00 にバックアップ実行
  • ログは /var/log/backup_mariadb.log に保存

手動で動作確認

sudo /usr/local/sbin/backup_mariadb.sh

上記コマンドでスクリプトを手動起動してみます。
/backup/mariadb に日付付きのディレクトリができているか、データベース名の .sql ファイルができているかを確認してください。

リストア方法

バックアップファイル名が wordpress_db、バックアップディレクトリが /backup/mariadb/2025-11-20_030000 であると仮定します。

データベースの作成

リストアを行う前に、対象のデータベースが MariaDB サーバー上に存在している必要があります。ない場合は作成します。

# 例: データベース名が 'wordpress_db' の場合
# 注: 認証情報(-u と -p)は環境に合わせて適切に指定
mysql -u [ユーザー名] -p -e "CREATE DATABASE IF NOT EXISTS wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
  • CREATE DATABASE IF NOT EXISTS: データベースがまだ存在しない場合のみ作成。
  • CHARACTER SET / COLLATE: 文字コードと照合順序は、元のデータベースの設定に合わせる。ここでは例として utf8mb4 を使用。

バックアップファイルからのデータインポート

作成したデータベースに対して対応する .sql ファイルを mysql コマンドでインポートします。

# 例: データベース名 'wordpress_db' にファイルをインポート
# 注: バックアップファイルへのパスは正確に指定
mysql -u [ユーザー名] -p wordpress_db < /backup/mariadb/2025-11-27_030000/wordpress_db.sql

リストア時の注意点

  • 認証情報: バックアップ時と同様に、リストアを行うユーザーが CREATE 権限対象データベースへの SELECT, INSERT, UPDATE, DELETE 権限 を持っている必要があります。
  • 既存データの上書き: 上記の方法でリストアすると、既存の同じ名前のデータベースが存在する場合、データが完全に上書きされます。稼働中のシステムに対して実行する場合は、細心の注意を払う必要があります。
  • 文字コード: CREATE DATABASE の際に指定する文字コードと照合順序は、バックアップ元の設定と完全に一致させる ことが必要です。

セキュリティ向上のためバックアップ専用ユーザーを検討

その他気になるであろう点について記載してみます。

バックアップ時にパスワードは必要ないの?

まれにバックアップスクリプトの例として、ROOTPASS=xxxxxxxx のようにパスワードを記入しているものがあります。
セキュリティ上好ましくないので記入しないほうがよいですし、今回の例ではrootユーザーで実行(unixソケット認証していますのでパスワード記入の必要がありません。

ではrootで実行することに問題はないの? との疑問が出てきますがあまり良い方法とは言えません。セキュリティの観点で考えればバックアップ専用のユーザーを作成した方が安全です。

その場合パスワードはどうするのか? という疑問が出てきますが、MariaDB / MySQLクライアントの仕様として my.cnf があると設定を自動で読む仕組みがあります。

  • 1 /etc/my.cnf
  • 2 /etc/mysql/my.cnf
  • 3 $HOME/.my.cnf ( rootの場合 /root/.my.cnf だがソケット認証する場合は不要)

    の順に読み込まれます。

この .my.cnf にはパスワードを記載するセクションがあります。バックアップ専用ユーザーの .my.cnf を作成して読ませればスクリプトにパスワードを記入する必要がなくなりますし、この .my.cnf の権限を厳しくすれば安全になるということです。

バックアップ専用ユーザーとは?

「専用のバックアップユーザー」は、セキュリティと堅牢性の観点から、Linux(OS)側MariaDB(データベース)側両方に作成します。

MariaDB(データベース)側のユーザー

これは、データベースにログインしデータにアクセスするために必須のユーザーです。

  • データベースへの認証: mariadb-dump がデータベースサーバーに接続するためのアカウント。
  • 権限の最小化: データベースの管理者である root ユーザーではなく、バックアップに必要な最低限の権限SELECT, LOCK TABLES, EVENT など)のみを持つユーザーを作成します。
  • セキュリティ境界: もしこのアカウントの情報が漏れたり、スクリプトが悪用されたりしても、root 権限のようにデータベース全体を破壊されるリスクを避けられます。
#バックアップユーザーの作成例:パスワードは堅牢なものに変更します。
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'secure_password';

#バックアップに必要な権限を付与
GRANT SELECT, LOCK TABLES, TRIGGER, EVENT, SHOW VIEW, ROUTINE
ON *.* TO 'backup_user'@'localhost';

Linux側のユーザー(セキュリティ強化のため推奨)

これは、バックアップスクリプトを実際に実行するOS上のユーザーです。

  • スクリプトの実行主体: バックアップスクリプト (.sh ファイル) を実行するユーザーです。
  • 認証情報の保護: MariaDBのパスワード を格納した設定ファイル(.my.cnf)を所有し、他のOSユーザーから読み取れないようにパーミッション(600 など)を厳しく設定します。
  • プロセス分離: root 以外の専用ユーザーでスクリプトを実行することで、バックアッププロセスをシステム管理プロセスから分離し、OS側のセキュリティを強化します。万が一、バックアッププロセスに脆弱性があっても、その被害は専用ユーザーの権限範囲内に限定されます。
#例:システムにログインできない専用のユーザーを作成。
useradd -r -s /sbin/nologin backup_user

以下に解説します。

  • useradd: 新しいユーザーアカウントを作成するためのコマンド。
  • -r : このフラグは、作成されるアカウントが通常のユーザーではなく「システムアカウント」であることを示します。システムアカウントは、通常、システムサービスやアプリケーションによって内部的に使用されログインセッションを持つことを意図していません。
  • -s /sbin/nologin : このフラグは、新しく作成されるアカウントのデフォルトシェルとして /sbin/nologin を設定します。これにより、そのアカウントでログインしようとしたユーザーは、代わりに「This account is currently not available」といったメッセージを受け取り、シェルプロンプトにアクセスできなくなります。

バックアップユーザーでの実行環境を作る

上記の構成で、MariaDB用の backup_userLinux用の backup_user(ログイン不可) を使いバックアップ専用ユーザーで cron 実行する手順を考えます。
この方法を使う場合は上で説明したrootでのcron実行を止める必要があります。

backup_userのホームディレクトリを作る

backup_user は/home が無いシステムユーザーなので、.my.cnf を作成するためのホームディレクトリを作成し権限を設定します。

sudo mkdir -p /home/backup_user
sudo chown backup_user:backup_user /home/backup_user
sudo chmod 700 /home/backup_user

MariaDB の認証情報を .my.cnf に保存

Linuxユーザー backup_user のホームへ .my.cnf を作る。

sudo -u backup_user vi /home/backup_user/.my.cnf

.my.cnfの内容

[client]
user=backup_user
password=secure_password #パスワードは堅牢なものに変更する事
host=localhost

権限の変更

sudo chmod 600 /home/backup_user/.my.cnf

バックアップスクリプトを backup_user が実行できる様に変更

スクリプトの権限を変更する。
backup_user に実行を許可する必要があるので 750 にする。
backup_user をグループに入れて実行権限を与える。

sudo chmod 750 /usr/local/sbin/backup_mariadb.sh
sudo chown root:backup_user /usr/local/sbin/backup_mariadb.sh

cron を backup_user で実行する

まず backup_usercrontab を作る。

sudo -u backup_user crontab -e

エディタを起動して下記の一行を追加します。

0 3 * * * /usr/local/sbin/backup_mariadb.sh >/home/backup_user/backup_mariadb.log 2>&1
  • cronbackup_user 権限で起動
  • MariaDB 認証は backup_user.my.cnf を使用
  • MariaDB システムDBにはアクセス不可
  • バックアップ先は backup_user が書ける場所に限定する

バックアップ先ディレクトリの権限設定

backup_user /backup/mariadb に書き出せるようにします。

/backup/mariadb がない場合は下記を実行してディレクトリを作成します。

sudo mkdir -p /backup/mariadb

権限の変更。

sudo chown backup_user:backup_user /backup/mariadb
sudo chmod 700 /backup/mariadb

これで backup_user だけが書き込みできるようになります。

手動での動作テスト

backup_user で DB に接続できるかどうか。

sudo -u backup_user mariadb -e "SHOW DATABASES;"

手動でバックアップが動作するか。

sudo -u backup_user /usr/local/sbin/backup_mariadb.sh

cron が動作しているかログを確認

sudo -u backup_user crontab -l

これで比較的安全にバックアップが取れるのではないかと思います。
なかなか面倒な作業です。覚書を書いておかないと何をしたか忘れそうです。

本番環境でない限りrootのcronでよくね? と思ったりしますが、そもそも本番環境でないデータベースってあるかな・・・。

ということで、MariaDBのデータベースバックアップについて書いてみましたが、きちんと動作するという保証はありませんので参考程度に読んでいただけますと幸いです。

必ずテスト環境で動作確認をしてからお試しください。

コメント

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