バックアップしたBlogコンテンツをDocker環境へ自動リストア

当BlogはVPS上のWordpressで運用しており、自動バックアップ機能を以下の記事の手順で実現しています。「さくらVPSのWordPress環境バックアップ自動化

今回、新たにバックアップコンテンツのリストア作業を自動化しましたのでその手順を公開します。

1.自動リストア実現の動機

今まで、バックアップしたBlogコンテンツを自宅サーバ環境にリストアする作業は手動で実施していました。参考「WordPress手動バックアップとDocker環境へのリストア

その為Blogを更新するとVPSのBlogとローカルバックアップ環境のBlogとでコンテンツに差異が発生し、手動でリストア作業を実施するまでバックアップ環境が最新化されないのが課題でした。Blogを更新したら自動的にバックアップ環境へも反映されるとストレスフリーで楽になりそうです。そこでこの自動リストアに取り組むことにしました。

2.前提

バックアップファイルはVPS上のWordpressより取得し自宅サーバ上のSamba公開ディレクトリに保存してあるものとします。リストア先は、Centos7.3で構築したDockerホストマシン上で動作しているdocker-composeで構築したWordpress環境(当記事参考)とします。

3.リストア作業の準備

自動リストア処理で必要となるツールやコンテナ環境を以下のように準備します。

(1)sambaマウントツール

Centosでsamba共有ディレクトリをマウントするには「cifs-utils」が必要です。yumでインストールします。

(2)ZIP暗号化解除

ZIPファイルを暗号化解除するにはUNZIPパッケージが必要です。yumでインストールします。

(3)mysqlコンテナへマウントフォルダ追加

Docker-composeで構築したWordpres環境のmysqlコンテナに新たなマウントディレクトリを追加します。理由は、リストア用SQLとそれを実行するshellスクリプトを格納しmysqlコンテナから実行するためです。通常は、以下のコマンドでホストからmysqlコンテナに接続しmysqlコマンドを実行できるのですが、WordpressDBをバックアップしたSQLファイルは容量が大きくこの方法ではエラーになってしいます。

ホストからmysqlコンテナに接続しmysqlコマンドを実行するコマンド

docker-compose.ymlに追加したマウント設定

5行目を追加。「data/sqltmp」ディレクトリをmysqlコンテナの「/home」にマウントしています。尚、Docker-composeでのWordpress環境構築及びコンテナ連携については以下の当Blog内記事を参照ください。

Docker-Composeでnginx,php,mysqlの3コンテナを連携する

DockerコンテナにWordPressをインストール

4.リストア処理手順と概要図
(1)リストア処理手順概要

バックアップファイルは自宅ファイルサーバのsamba共有ディレクトリに存在するのでDockerホストサーバからこのディレクトリをマウントします。マウント後に暗号化ZIP圧縮したコンテンツファイルと同じく暗号化ZIP圧縮したSQLファイルをコピーします。これを一旦ローカルに展開した後、対象とするDockerコンテナのマウントディレクトリにコピーします。SQLファイルをmysqlコンテナ上で実行します。実行するのはBlogDBよりバックアップしたSQLファイルとVPS向けURLをローカル向けURLに書き換えるSQLです。

(2)リストア全体概要図

上記手順のイメージ図がこちらになります。

大まかなイメージはつかめますが詳細は良くわからないですね。

後述するシェルスクリプトで詳細を説明します。

5.リストア手順詳細(ホスト用スクリプト)

こちらではDockerホストサーバで実行するシェルスクリプトを提示します。

FileRestore.sh  (2017/7/25 重複記述の6行を削除し行番号を訂正しました)

(1)環境準備

1-40行でマウント先ディレクトリやユーザーとパスワード、ファイル名等を定義しています。

(2)LOGファイル出力

42行目で1週間前の過去ログを削除し43行目でリストアトレースログを出力しています。

(3)sambaディレクトリマウント

46-49行でマウントディレクトリが存在ない場合ディレクトリを作成しています。
52行目でsamba共有ディレクトリをマウントしています。
このsamba共有ディレクトリにVPSからSCPでコピーしてきたバックアップファイルがあります。

(4)ファイルタイムスタンプ比較

55-80行目でバックアップDBファイルとバックアップコンテンツファイルのそれぞれでファイル作成日付が前回リストアで使用したファイルと比較して新しくなっているか確認し新しい場合のみリストアを実施しています。(古いファイルをリストアして上書きしないための考慮)

(5)リストア処理本体

83行目のIF文でバックアッファイルが新しくなっている場合にリストア処理を行います。
84,86行目でバックアップファイルを中間ファイルにコピーします。
90,93行目で暗号化ZIPファイルを/restoreディレクトリに展開しています。
96行目で展開したWordpressコンテンツフォルダ一式ををDockerマウントディレクトリに上書きコピーしています。
97行目でコピーしたディレクトリのオーナーをコンテナとホスト間の共通ユーザー「nginx_docker」に変更しています。(当記事参照
99行目でUNZIPしたSQLファイルをmysqlコンテナがマウントしているディレクトリにコピーします。
100行目でDB内のURLを書き換えるSQLをroot直下からマウントディレクトリにコピーしています。
101行目でmysqlコンテナ内で実行するshellスクリプトをmysqlコンテナがマウントしているディレクトリにコピーしています。
102行目でコピーしたシェルスクリプトに実行権限を付与しています。
105行目でmysqlコンテナに接続し、上記sqlexec.shのシェルスクリプトを実行しています。
これでDBが最新になります。

(6)後処理

108,109行目でunzip展開したファイルを削除します。
110,111行目でコピーした中間ファイル名を正式ファイル名にリネームしています。
114行目でmauntディレクトリをアンマウントして終了です。

6.リストア手順詳細(mysqlコンテナ用スクリプト)

こちらではDockerホストサーバから呼び出され、mysqlコンテナ内でSQLファイルを実行するシェルスクリプトを提示します。

sqlexec.sh

(1)環境準備

1-7行目で実行するSQLファイルのパスと実行ユーザ・パスワードを定義しています。

(2)sql実行

11-12行目で定義したSQLファイルを実行しblogdbを更新しています。11行目がVPSのWordpressDBよりバックアップしたSQLファイル。12行目がVPS向けURLをローカル向けURLに書き換えるSQLです。

7.Cronへの登録

上記スクリプトがDockerホストサーバで定期的に実行されるよう/etc/cron.d/restore
ファイルを用意し以下のように設定します。

毎朝5時30分にBLOGのリストア処理が実行されます。

8.成功までの顛末
(1)Cron失敗

実は、当初Cronからの自動リストアはうまく動作していませんでした。ターミナルからの実行では問題無く動作するのですが。

(2)調査結果

調査したところDockerに接続してシェルスクリプトを実行する以下の行がうまく動作していませんでした。

コンテナで実行するsqlexec.shに調査ログを仕込んで実行結果を見てみるとログが出力されていません!Cronからシェルスクリプトを起動すると動作しないようです。

(3)試行錯誤

これらをヒントにGoogleで調査してみましたがどこにも適切な回答はありません。そこで基本に戻りDocker公式日本語マニュアルを精査してみました。

exec

最初に試したのは 「-u root」オプションの追加。しかし状況は変化なし。Cronではroot指定で実行しているので当然であります。

次に試したのは「-t」オプションの削除。Cronで実行時に疑似ターミナルは割り当てできないのではとの推論の元。結果は予想通りでした。以下が変更後のコマンド行です。

合わせて「 2>&1」のリダイレクトで標準エラー出力もログに出力するようにしています。

(4)結論

Cronから実行するShellScript内でDockerコンテナに接続し、コンテナ内のShellスクリプトを実行する場合は、execコマンドのオプションに-tを付加しない

通常は「Dockerコンテナに接続しコンテナ内のShellスクリプトを実行する」の前提はターミナルから実行するなのでこの-tオプションがついていても問題はありません。

検索結果を流用する際には、訳も分らずコピペするのではなくマニュアルを参照してオプションの意味や条件を良く理解したうえで使用するのがよろしいようです。自分への教訓です。