PCバックアップシステムを自作する
情シス担当のますいです。
万一に備えてクライアントPCのバックアップをとっておくことは重要です。OS標準のバックアップ機能、バックアップ専用ソフト、クラウドバックアップサービスなど多様な方法があり、企業ではそれぞれの予算や方針に沿った方法を採用していると思います。
自作の経緯
弊社では、1年前まで「Windows Server Essenetialsエクスペリエンス」の機能を利用してバックアップをとっていました。
「Windows Server Essenetialsエクスペリエンス」(以降、「Essentials」と呼びます)とは、ユーザー数25名以内の小規模企業向けサーバーエディションである「Windows Server Essenetials」独自の機能を、Standard以上のエディションでも使えるようにしたものです(Windows Server 2012 R2以降のWindows Serverに標準で搭載)。
Essenetialsでは、対象PCにコネクターというソフトをインストールし、サーバーと接続することでサーバーからバックアップ対象フォルダなどを一元管理することができます。
しかし、Essenetialsには簡易的な機能しかなく不便に感じる部分も多々ありました。
・バックアップ先はUNCパスが指定できない
サーバのローカルドライブかiSCSIストレージに限られる
・バックアッププロセスは同時に1件しか走らない
1日にとれるバックアップ台数に限度がある
・バックアップ対象フォルダは1台ごとに設定する必要がある
共通設定ができず管理が煩雑になる
・バックアップ対象フォルダが除外指定方式
設定後に増えたフォルダは必要なくてもバックアップされてしまう
・ファイル名やファイル形式による除外指定ができない
不要なファイルまでバックアップされてストレージが肥大化してしまう
さらに、システム不具合の多発にも悩まされました。エラーが発生してバックアップの取得やバックアップからの復元作業が一切できなくなるという状態がたびたび発生し、エラーを修復する機能もあるのですが、この機能を使っても修復できなくなるケースが何度も発生しました。
こうなると、Essentialsを再構築して各PCで接続しなおす必要があり、悩みの種となっていました。
そこで他のバックアップシステムを模索していたのですが、結局スクリプトで自作することにしました。
制作にあたって設定した要件は下記の通りです。
- PCにはエージェントインストール等の手を加える必要はない
- バックアッププロセスの同時実行数は任意に設定可
- バックアップ対象フォルダは対象指定方式とし、共通設定と個別設定を可能にする
- 各PCのバックアップを1日1回程度とる
- ファイル履歴はファイルシステムの履歴機能で確保する
システム概要
■バックアップコマンド
バックアップの中核となるコマンドは、Windows Server 2008から標準で搭載されている robocopy を使用します。
robocopyはunix系OSにあるrsyncに近い機能を持ったコマンドで、詳細な使用方法は
robocopy /?
と打つことで確認することができます。
バックアップを取得するファイルサーバからドメインのadministrators権限で実行し、対象PCの管理共有から対象フォルダの差分コピーを実施することで、PCには手を加えることなくバックアップを取得することが可能になります。
管理共有とは、ドライブ名+"$"でドライブルートに共有フォルダとしてアクセスできる機能で、Administratorsグループに所属するユーザーだけがアクセスできます。
例;\\PC名\c$\users(対象PCのc:\usersへのアクセス)
コマンドオプションは下記のようにしています。
robocopy /MIR /SEC /XJ /R:1 /W:1 /IPG:10
/MIR コピー元とコピー先を同期する/SEC ファイルのセキュリティ情報もコピー/XJ ジャンクションとシンボリックリンクを除外/R:1 失敗したコピーに対する再試行数/W:1 再試行と再試行の間の待機時間(秒)/IPG:10 パケット間ギャップ (ミリ秒)
■バックアップ先
弊社ではファイルサーバを本番系と待機系の2台で運用しています。このうち待機系側にバックアップ保存用パーティションを作成し、バックアップ先としました。
本番系と待機系が入れ替わることがあった場合はバックアップの役割も交代することにしています。
バックアップ先パーティションではファイル履歴を有効にし、以前のバージョンを復元できるようにします。
クライアントからバックアップ先へはアクセスできないようにしてあり、バックアップからの復元は依頼により管理者が行うことにしています。
■スクリプト
システムはJScriptで作成しました。バックアップ対象の選定と実行制御を行う pcbackup.js と、そこから呼び出されて実際のバックアップを行う buexec.js という構成になっています。
バックアップ対象PCや対象フォルダはSQLite3のデータベースで管理しています。
◇ データベース構成
【テーブル pc】
pcname TEXT 対象PC名
username TEXT バックアップ対象ユーザフォルダ名(c:\users\ユーザ名)
lastsuccess TEXT 前回成功日時
nextrun INTEGER 次回実行日時(JScriptの getTime() でとれるミリ秒単位のエポックタイム)
【テーブル backupdir】
od INTEGER 実行順序
pcname TEXT 対象PC名。「*」にすると全PC対象となる。
dir TEXT バックアップ対象ディレクトリ
ignoredir TEXT 除外フォルダ名。robocopyの /XD オプションにそのまま渡す。
ignorefile TEXT 除外ファイル名。robocopyの /XF オプションにそのまま渡す。
◇ 処理概要
【pcbackup.js の処理】
下記の流れで処理します。これをタスクスケジューラで1分ごとに起動しています。
1. プロセス数確認
実行中のプロセス数を取得し、指定した最大同時実行数に達していたら終了。
2. 対象PC選定
テーブル pc から、nextrun がnullまたは現時刻以前のものを取得し、lastsuccessがnullのものまたは古い順に疎通確認を行い、最初に疎通のとれたもの1件を対象として選定する。
疎通のとれなかったPCは nextrun を規定のインターバル(3時間)後に更新する。
1件も抽出されなかったら終了。
3. buexec.js に処理を渡す
バックアップを開始し、同時に nextrun を23時間後に更新する。
なぜ24時間でなく23時間にしているかと言うと、対象PC選定時に実行待ちが多い場合は次回実行時刻が後ろにずれていき、待ちが少ない場合は前にずれていくことで、全体的に実行時刻が均されていく仕組みにしているためです。
4. プロセス管理
buexec.jsの実行時間が規定のタイムアウト値を過ぎた場合はプロセスを強制終了し、nextrun を規定のインターバル(6時間)後に更新する。
buexec.jsが終了しエラーコードが戻ってきた場合、nextrun を規定のインターバル(6時間)後に更新する。
buexec.jsが正常終了した場合は lastsuccess を現時刻に更新する。
【buexec.js の処理】
1. バックアップ対象ディレクトリの取得
テーブル backupdir から、該当PCのバックアップ対象ディレクトリ一覧を取得
2. バックアップの実行
バックアップ対象フォルダが存在するか確認し、存在したらrobocopyコマンドを実行する
3. 終了コードを返して終了
運用
■トラブル発生
運用開始と同時に、東京本社と大阪支社間で行うTV会議の通信が荒れるというクレームが届きました。
バックアップのトラフィックがTV会議の通信を圧迫してしまったようです。
QoSによる優先度制御を検討しましたが、使用しているネットワーク機器の制限でそれもできないことが判明したため、TV会議中はバックアップを停止するようスクリプトを改造しました。
pcbackup.jsの起動時にTV会議装置のIPにpingを打って、応答を検出したら中止します。また、バックアップ実行中も常時pingを監視して検出したらプロセスを強制終了するようにしました。
その後は動作も安定し、クライアント側からは気付かないレベルの軽い動作を実現しています。
■稼働監視
稼働状況の監視のため、1日のバックアップ済みPC台数をzabbixで取得しています。1日に120台程度のバックアップがとれていることがわかります。TV会議中はしっかり停止していることも見てとれます。
また、lastsuccessが一定期間以上更新されていないPCも抽出し、問題がないか調査しています。
今後の方針
現在でも1日で全台のバックアップは取れていないので、トラフィックの負荷を見ながら同時実行数を少しずつ増やしていきます。
また、スリープ中のPCをWOLにより起こしてバックアップを取れるようにすることも計画中です。
あとはネットワーク機器を整備してTV会議のQoSを実現し、いつでも気兼ねなくバックアップを実行できるようにしたいと思っています。