Power ShellでRedmineをバックアップする。
概要
チケット管理システム「Redimine」のデータをバックアップするPower Shellスクリプトを作成します。
データの圧縮には、フリーの圧縮ソフト「7-zip」を使います。
実装する機能
-
圧縮保管
Redmineのバックアップに必要な以下のデータを圧縮して保管します。
- 画像ファイルが入っている「files」フォルダ
- その他の全てのデータが格納されているMySQLのDBデータ
世代管理
3世代まで保持します。4世代以上過去のデータは削除します。
ミラーリング
外付けHDDとミラーリングし、データを2箇所で保持します。
実装方法
■ 画像フォルダのバックアップ
圧縮保管
Redmineのバックアップに必要な以下のデータを圧縮して保管します。
- 画像ファイルが入っている「files」フォルダ
- その他の全てのデータが格納されているMySQLのDBデータ
世代管理
3世代まで保持します。4世代以上過去のデータは削除します。
ミラーリング
外付けHDDとミラーリングし、データを2箇所で保持します。
■ 画像フォルダのバックアップ
Power ShellのCopy-Item関数でバックアップします。
Copy-Item -Path (画像フォルダ) -Destination (バックアップ先) -Recurse
「-Recurse」を指定すると、フォルダ階層が深くても、再帰的にコピーしてくれます。
■ DBデータのバックアップ
MySQLに付属しているコマンド「mysqldump.exe」を使います。
mysqldump --defaults-file=(オプションファイル) --result-file=(バックアップデータ出力先) --log-error=(エラーログ出力先) DB名
引数で指定しているオプションファイルには、ログイン情報を指定します。
[mysqldump]
user=xxx
password=xxx
host=xx.xx.xx.xx
port=xxx
■ バックアップデータの圧縮
フリーの圧縮解凍ソフト「7-zip」に付属しているコマンドラインツールを使って圧縮します。1
圧縮形式は7zを使用します。
7z a -sdel (圧縮先の書庫) (圧縮元の画像フォルダ) (圧縮元のダンプファイル)
引数の意味は以下です。
- a : addの略。ファイルを圧縮先の書庫に入れる。
- -sdel : 圧縮処理の後、圧縮元ファイルを削除する。
■ バックアップデータのローテート
ファイル作成日付でソートし、作成日付の新しい3ファイルを残して、古いデータを削除します。
Get-ChildItem (バックアップフォルダ) |
Sort-Object CreationTime -Descending |
Select-Object -Skip 3 |
foreach{Remove-Item -Path $_.FullName}
■ バックアップデータのミラーリング
Windowsの付属コマンド「RoboCopy」を使います。
ROBOCOPY (コピー元のバックアップフォルダ) (コピー先のミラーフォルダ)/MIR
引数の「/MIR」はミラーリングするという意味です。
「/MIR」を指定すると、コピー元にだけあるファイルはコピー先に作成され、コピー元にないファイルは、コピー先から削除されます。
プログラム全体の構成
PowerShellで上記の処理を順番に呼び出します。
処理に必要なパスなどの情報は、設定ファイルに記述し、実行時に読み込む事にします。
処理に必要なフォルダは、初回実行時に作成します。
フォルダ構成
以下にフォルダ構成の例を示します。
内蔵HDD内で一度バックアップし、外付けHDDにミラーリングする、という流れです。
【内蔵HDD】
C:
└─Bitnami
└─redmineBackup
├─backup_files
│ redmineBackup_YYYY-MMDD-HHMMSS.7z
│ redmineBackup_YYYY-MMDD-HHMMSS.7z
│ redmineBackup_YYYY-MMDD-HHMMSS.7z
│
├─config
│ settings.ini
│ mysqldump-options.ini
│
├─log
│ dumpMySqlDataError.log
│ redmineBackup.log
│
├─scripts
│ redmine_backup.ps1
│
└─work
【外付けHDD】
E:
└─Bitnami
└─redmine_data_backup
redmineBackup_YYYY-MMDD-HHMMSS.7z
redmineBackup_YYYY-MMDD-HHMMSS.7z
redmineBackup_YYYY-MMDD-HHMMSS.7z
ソースコード
PowerShell
# --- ヘルパー関数 ---
function initializeFolders ($bkroot,$settings) {
createFolderIfNotExists (Join-Path $bkroot work)
createFolderIfNotExists (Join-Path $bkroot log)
createFolderIfNotExists (Join-Path $bkroot backup_files)
createFolderIfNotExists $settings.mir
}
function createFolderIfNotExists($path){
if(-not (Test-Path $path)){
New-Item $path -ItemType Directory
}
}
function deleteFileIfExists($path){
if(Test-Path $path){
Remove-Item $path
}
}
function getBackUpFileName($filenameExtension){
return "redmineBackup_" + (Get-Date -Format "yyyy-MMdd-HHmmss") + "." + $filenameExtension
}
function log($message, $bkroot){
Write-Output $message
Write-Output ((Get-Date -Format "yyyy-MM-dd HH:mm:ss") + " " + $message) | Out-File (Join-Path $bkRoot log\redmineBackup.log) -Encoding utf8 -Append
}
# --- 初期化 ---
# プログラムのルートフォルダを取得します。
$bkRoot = Split-Path $MyInvocation.MyCommand.Path -Parent | Split-Path -Parent
# アクセスするリソースのパスをINIファイルから読み込みます。
$s = Get-Content (Join-Path $bkRoot config\settings.ini) | ConvertFrom-StringData
# 処理対象となるフォルダを作成します。
initializeFolders $bkRoot $s
# 古いログファイルがあれば削除します。
deleteFileIfExists (Join-Path $bkRoot log\redmineBackup.log)
# --- バックアップ ---
log "添付ファイルが格納されているfilesフォルダをworkフォルダにコピーします。" $bkRoot
Copy-Item -Path $s.files -Destination (Join-Path $bkRoot work) -Recurse
log "mySqlに格納されているデータをworkフォルダに取得します。" $bkRoot
Start-Process -NoNewWindow `
-FilePath $s.mysqldump `
-ArgumentList ("--defaults-file=" + (Join-Path $bkRoot config\mysqldump-options.ini)) , `
("--result-file=" + (Join-Path $bkRoot work\databaseBackUp.sql)), `
("--log-error=" + (Join-Path $bkRoot log\dumpMySqlDataError.log)), `
$s.dbname `
-Wait
log "取得したバックアップデータを圧縮します。" $bkRoot
$backUpFile = getBackUpFileName "7z"
Start-Process -NoNewWindow `
-FilePath $s._7zip `
-ArgumentList a, `
-sdel, `
(Join-Path $bkRoot work | Join-Path -ChildPath $backUpFile), `
(Join-Path $bkRoot work\files), `
(Join-Path $bkRoot work\databaseBackUp.sql) `
-Wait
log "バックアップデータを保管用フォルダに移動します。" $bkRoot
Move-Item -Path (Join-Path $bkRoot work | Join-Path -ChildPath $backUpFile) -Destination (Join-Path $bkRoot backup_files)
log "4世代以前のバックアップファイルを削除します。" $bkRoot
Get-ChildItem (Join-Path $bkRoot backup_files) |
Sort-Object CreationTime -Descending |
Select-Object -Skip 3 |
foreach{Remove-Item -Path $_.FullName}
# --- ミラーリング ---
log "バックアップファイルを外付けHDDとミラーリングします。" $bkRoot
if((Join-Path $bkRoot backup_files | Get-ChildItem | Measure-Object).Count -ne 0){ # 万が一、コピー元が空で同期してしまうと、コピー先のファイルが全部消えるので。
ROBOCOPY (Join-Path $bkRoot backup_files) $s.mir /MIR
}
設定ファイル
settings.ini
\# redmineの画像データ「files」フォルダのパス
files=X:\\Bitnami\\xxx\\apps\\redmine\\htdocs\\files
\# MySQLからデータをダンプするツール「mysqldump」
mysqldump=X:\\xxx\\xxx\\bin\\mysqldump.exe
\# 「mysqldump」コマンドを用いてダンプするデータベース・インスタンス
dbname=xxx
\# 7-zipのコマンドラインツール「7z」
_7zip=X:\\xxx\\7-Zip\\7z.exe
\# ミラーリングする外部ストレージのフォルダパス
mir=Y:\\xxx\\xxx
環境
# --- ヘルパー関数 ---
function initializeFolders ($bkroot,$settings) {
createFolderIfNotExists (Join-Path $bkroot work)
createFolderIfNotExists (Join-Path $bkroot log)
createFolderIfNotExists (Join-Path $bkroot backup_files)
createFolderIfNotExists $settings.mir
}
function createFolderIfNotExists($path){
if(-not (Test-Path $path)){
New-Item $path -ItemType Directory
}
}
function deleteFileIfExists($path){
if(Test-Path $path){
Remove-Item $path
}
}
function getBackUpFileName($filenameExtension){
return "redmineBackup_" + (Get-Date -Format "yyyy-MMdd-HHmmss") + "." + $filenameExtension
}
function log($message, $bkroot){
Write-Output $message
Write-Output ((Get-Date -Format "yyyy-MM-dd HH:mm:ss") + " " + $message) | Out-File (Join-Path $bkRoot log\redmineBackup.log) -Encoding utf8 -Append
}
# --- 初期化 ---
# プログラムのルートフォルダを取得します。
$bkRoot = Split-Path $MyInvocation.MyCommand.Path -Parent | Split-Path -Parent
# アクセスするリソースのパスをINIファイルから読み込みます。
$s = Get-Content (Join-Path $bkRoot config\settings.ini) | ConvertFrom-StringData
# 処理対象となるフォルダを作成します。
initializeFolders $bkRoot $s
# 古いログファイルがあれば削除します。
deleteFileIfExists (Join-Path $bkRoot log\redmineBackup.log)
# --- バックアップ ---
log "添付ファイルが格納されているfilesフォルダをworkフォルダにコピーします。" $bkRoot
Copy-Item -Path $s.files -Destination (Join-Path $bkRoot work) -Recurse
log "mySqlに格納されているデータをworkフォルダに取得します。" $bkRoot
Start-Process -NoNewWindow `
-FilePath $s.mysqldump `
-ArgumentList ("--defaults-file=" + (Join-Path $bkRoot config\mysqldump-options.ini)) , `
("--result-file=" + (Join-Path $bkRoot work\databaseBackUp.sql)), `
("--log-error=" + (Join-Path $bkRoot log\dumpMySqlDataError.log)), `
$s.dbname `
-Wait
log "取得したバックアップデータを圧縮します。" $bkRoot
$backUpFile = getBackUpFileName "7z"
Start-Process -NoNewWindow `
-FilePath $s._7zip `
-ArgumentList a, `
-sdel, `
(Join-Path $bkRoot work | Join-Path -ChildPath $backUpFile), `
(Join-Path $bkRoot work\files), `
(Join-Path $bkRoot work\databaseBackUp.sql) `
-Wait
log "バックアップデータを保管用フォルダに移動します。" $bkRoot
Move-Item -Path (Join-Path $bkRoot work | Join-Path -ChildPath $backUpFile) -Destination (Join-Path $bkRoot backup_files)
log "4世代以前のバックアップファイルを削除します。" $bkRoot
Get-ChildItem (Join-Path $bkRoot backup_files) |
Sort-Object CreationTime -Descending |
Select-Object -Skip 3 |
foreach{Remove-Item -Path $_.FullName}
# --- ミラーリング ---
log "バックアップファイルを外付けHDDとミラーリングします。" $bkRoot
if((Join-Path $bkRoot backup_files | Get-ChildItem | Measure-Object).Count -ne 0){ # 万が一、コピー元が空で同期してしまうと、コピー先のファイルが全部消えるので。
ROBOCOPY (Join-Path $bkRoot backup_files) $s.mir /MIR
}
\# redmineの画像データ「files」フォルダのパス
files=X:\\Bitnami\\xxx\\apps\\redmine\\htdocs\\files
\# MySQLからデータをダンプするツール「mysqldump」
mysqldump=X:\\xxx\\xxx\\bin\\mysqldump.exe
\# 「mysqldump」コマンドを用いてダンプするデータベース・インスタンス
dbname=xxx
\# 7-zipのコマンドラインツール「7z」
_7zip=X:\\xxx\\7-Zip\\7z.exe
\# ミラーリングする外部ストレージのフォルダパス
mir=Y:\\xxx\\xxx
環境
Power Shell 5.1
7-zip 16.04
Bitnami Redmine Stack 3.3.2-2
・Redmine 3.3.2
・MySQL 5.6.35
windows 10 Home
github
ここで作成したプログラムは、以下に保存されています。
https://github.com/nogitsune413/redmineBackup
注釈
-
PowerShellにも標準で圧縮用の関数「Compress-Archive」が入っているのですが、Compress-Archive関数のバグを報告するWebサイトの記事をいくつか見かけたので、今回は7-zipを使って実装しました。 簡単なプログラムですので、標準関数であるCompress-Archiveを使いたい方は、Power Shell内に書かれた、圧縮処理のコードを書き換えてください。
【バグを報告しているサイト】
powershellのcompress-archiveコマンドで作成したzipに潜むちょっとした罠
これで解消!「KB2704299」でCompress-Archiveの文字化け対処 ↩
-
PowerShellにも標準で圧縮用の関数「Compress-Archive」が入っているのですが、Compress-Archive関数のバグを報告するWebサイトの記事をいくつか見かけたので、今回は7-zipを使って実装しました。 簡単なプログラムですので、標準関数であるCompress-Archiveを使いたい方は、Power Shell内に書かれた、圧縮処理のコードを書き換えてください。
【バグを報告しているサイト】
powershellのcompress-archiveコマンドで作成したzipに潜むちょっとした罠
これで解消!「KB2704299」でCompress-Archiveの文字化け対処 ↩
Author And Source
この問題について(Power ShellでRedmineをバックアップする。), 我々は、より多くの情報をここで見つけました https://qiita.com/nogitsune413/items/b446cfe28b02bf077bc0著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .