🐳

Dockerコンテナ内のMysqlのバックアップをホストのCronで取る方法

2022/10/17に公開約3,200字

はじめに

最近Dockerを使い始めました。
めちゃくちゃ簡単に環境が構築できて、なぜ今まで使わなかったか不思議です。
さて、そんな感じでDockerは便利なのですが、タイトルにもあるようにDockerコンテナ内のMySQLの定期バックアップのやり方の情報がネット上に少なくて苦労したので、備忘録がてら、ここに残しておこうと思います。

コード

backup.sh
#!/bin/bash

# MYSQL 環境変数
# ---------------------------------------------------------------------------------
MYSQL_USER=ユーザー名
MYSQL_PASS=パスワード
MYSQL_DATABASE=データベース名
TZ=Asia/Tokyo
# ---------------------------------------------------------------------------------

# 年、月、日をそれぞれ取得
YEAR=`date '+%Y'`
MONTH=`date '+%m'`
DATE=`date '+%Y%m%d'`

# スクリプトファイルの場所を取得
SCRIPT_DIR=$(cd $(dirname $0); pwd)

# バックアップファイルを保存するためのディレクトリを作成
mkdir -p ${SCRIPT_DIR}/${YEAR}/${MONTH}
                                               
# Docker内のmysqlに接続してバックアップをする部分(gzipでファイルの圧縮もしている)
/usr/bin/docker exec -i mysql /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASS} ${MYSQL_DATABASE} | gzip > ${SCRIPT_DIR}/${YEAR}/${MONTH}/backup${DATE}.sql.gz

解説

このスクリプトがすること

ファイルを保存するためのディレクトリの作成

  1. スクリプトファイルの置かれている場所に、実行された時の年ディレクトリを作成する。
  2. 作成された年ディレクトリの下に月に対応したディレクトリを作成する

mysqlコンテナの指定したデータベースのフルバックアップを保存

  1. docker内のmysqlにrootとしてログインしてmysqlumpコマンドを実行
  2. ホストOSのgzipコマンドにパイプで上記の実行結果を渡して圧縮する
  3. 最後に圧縮されたファイルを先ほど作成した月に対応したディレクトリ内にbackup<今日の日付>.sql.gzという名前で保存する

実行結果の例

2022/9/22~2022/9/23まで動かした場合

├── 2022
│   └── 09
│       ├── backup20220922.sql.gz
│       └── backup20220923.sql.gz
└── backup.sh

上記のように、シェルスクリプトと同じ階層に年ディレクトリが作成され、さらその中に月ディレクトリが作成され、その中に年、月、日付の圧縮されたsqlファイルが保存されます。

cronの設定

使用方法

cronの基本的な使い方はたくさん記事があるのでそちらを参照されると良いかと思います。
https://qiita.com/ryota_i/items/2db9b8340c9fb8f42aad

自分の設定

00 09 * * * bash <backup.shまでのフルパス>

私は、夜中に自動でプログラムを動かして、 朝方にその結果のバックアップを取るといった使い方をしているので、毎日、朝9時丁度に実行するように設定しています。
バックアップを取る周期や時間については適宜設定してください。

軌跡

苦労した点

1. 実行するとパスワードフィールドが出てしまう。

発生した問題

-uオプションと-pオプションでログイン情報を指定しているはずなのに、実行するとパスワードが聞かれる。
この状態では当然、cronでは実行できない。

原因と解決方法

-uと-pのオプションのあとにスペースがあったことが原因

bad
-u ${MYSQL_USER} -p${MYSQL_PASS}

ではなく

good
-u${MYSQL_USER} -p${MYSQL_PASS}

にしたらうまく動いた

2.terminalから手動で実行できるが、cronからは実行できない

発生した問題

「問題1」を解決した後、最初はバックアップを取る部分を以下のようにしていた

/usr/bin/docker exec -it mysql /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASS} ${MYSQL_DATABASE} | gzip > ${SCRIPT_DIR}/${YEAR}/${MONTH}/backup${DATE}.sql.gz

terminalから実行した場合は上手く動くが、なぜかcronだと実行されない

原因と解決方法

-tオプションがついていたことが原因

bad
/usr/bin/docker exec -it mysql /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASS} ${MYSQL_DATABASE} | gzip > ${SCRIPT_DIR}/${YEAR}/${MONTH}/backup${DATE}.sql.gz

なので、-tを消したら治った。

good
/usr/bin/docker exec -i mysql /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASS} ${MYSQL_DATABASE} | gzip > ${SCRIPT_DIR}/${YEAR}/${MONTH}/backup${DATE}.sql.gz

最後に

「dockerでバックアップ取る方法」と、「cronでmysqlのバックアップを取る方法」はあったのですが、「dockerのmysqlのバックアップをcronで取る方法」がネットで見つけられなかったので今回記事にしました。
この記事を読んでくださった方のお役に立てていれば、幸いです。

参考資料

https://blog.amedama.jp/entry/shell-script-abs-dir
https://zenn.dev/swata_dev/articles/2f85a3f4b3022c
https://mi-rai.co.jp/blog/6566

Discussion

ログインするとコメントできます