Skip to main content

第19章:バックアップを自動化:Windowsでも回るスクリプトにする⚙️

「手でコマンド打つバックアップ」は、忙しいと絶対サボります😂 なのでこの章は、**“ワンコマンドでバックアップができる仕組み”**を作ります💪✨

なお、コンテナのデータ(volume)の中身は イメージには入らないので、ちゃんと別で守る必要があります📦🛟 (Docker Documentation)


この章のゴール🎯

  • scripts/backup.ps1 を叩くと ✅ 指定した Docker volume が backups/yyyymmdd-hhmmss-....tar.gz として保存される
  • さらに ✅ タスク スケジューラで「毎日深夜に自動バックアップ」までできる

1) 自動化の“設計図”を先に理解する🧠🗺️

やることは超シンプルです👇

  1. Windows側に backups/ フォルダを用意📁

  2. 一時コンテナを起動(数秒で消える)⏱️

  3. その一時コンテナに

    • バックアップしたい volume/data にマウント📦
    • backups//backup にマウント📁
  4. コンテナ内で tar して、/backup.tar.gz を出す🗜️

  5. 一時コンテナは --rm で消える✨

この方式は Docker公式が案内している、volumeバックアップの基本形そのものです🧰 (Docker Documentation)


2) まず “volume名” を確定する🔎📦

✅ よくある落とし穴

Composeを使うと、volume名が プロジェクト名_volume名 みたいに 自動でプレフィックス付きになります😇

確認コマンド(まずこれ)

docker volume ls

「ぽい名前」を見つけたら、詳細確認👇

docker volume inspect <VOLUME_NAME>

3) scripts/backup.ps1 を作る🧰✨

プロジェクト直下にこんな構成を作るイメージです👇

  • scripts/backup.ps1
  • backups/(自動生成でもOK)

以下を そのまま scripts/backup.ps1 に保存してください👇😊

param(
[Parameter(Mandatory = $true)]
[string]$VolumeName,

[string]$OutDir = (Join-Path $PSScriptRoot "..\backups"),

# ファイル名の先頭につくやつ(用途で変える)
[string]$NamePrefix = "volume",

# “整合性が大事”なときだけ、止めたいサービス名(Composeのservice名)
# 例: -StopServices db
[string[]]$StopServices = @(),

# composeファイルの場所(必要なら変更)
[string]$ComposeFile = (Join-Path $PSScriptRoot "..\compose.yaml")
)

$ErrorActionPreference = "Stop"

function New-SafeName([string]$s) {
# ファイル名に危ない文字を潰す
return ($s -replace '[^a-zA-Z0-9_.-]', '_')
}

function Require-Command([string]$cmd) {
if (-not (Get-Command $cmd -ErrorAction SilentlyContinue)) {
throw "必要なコマンドが見つかりません: $cmd"
}
}

Require-Command "docker"

## 出力先フォルダを作る
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$OutDirAbs = (Resolve-Path $OutDir).Path

## volumeの存在チェック
try {
docker volume inspect $VolumeName | Out-Null
} catch {
throw "Volumeが見つかりません: $VolumeName`nまず 'docker volume ls' で名前を確認してね🙏"
}

$ts = Get-Date -Format "yyyyMMdd-HHmmss"
$volSafe = New-SafeName $VolumeName
$fileName = "{0}-{1}-{2}.tar.gz" -f (New-SafeName $NamePrefix), $volSafe, $ts
$outPath = Join-Path $OutDirAbs $fileName

## ログも一緒に残す(後で原因追いに便利)
$logPath = Join-Path $OutDirAbs ("{0}-{1}-{2}.log" -f (New-SafeName $NamePrefix), $volSafe, $ts)

$stopped = $false

try {
# 重要: DBなど “途中状態が怖い” 場合だけ止める(数秒)
if ($StopServices.Count -gt 0) {
if (Test-Path $ComposeFile) {
docker compose -f $ComposeFile stop @StopServices | Out-Null
$stopped = $true
} else {
throw "Composeファイルが見つからないので停止できません: $ComposeFile"
}
}

# 一時コンテナでtarして、ホスト側(backups/)へ吐き出す
# 公式のvolumeバックアップ手順と同系統のやり方✨
$cmd = @(
"run", "--rm",
"--mount", "type=volume,src=$VolumeName,dst=/data,readonly",
"--mount", "type=bind,src=$OutDirAbs,dst=/backup",
"busybox:stable",
"sh", "-c", "tar -czf /backup/$fileName -C /data ."
)

# 実行ログ
("[{0}] START backup volume={1} => {2}" -f (Get-Date), $VolumeName, $outPath) | Out-File -Append -Encoding UTF8 $logPath

docker @cmd 2>&1 | Out-File -Append -Encoding UTF8 $logPath

# 成功チェック
if (-not (Test-Path $outPath)) {
throw "バックアップファイルが作られてないっぽい…ログを見てね: $logPath"
}

$size = (Get-Item $outPath).Length
("[{0}] OK size={1} bytes" -f (Get-Date), $size) | Out-File -Append -Encoding UTF8 $logPath

Write-Host "✅ Backup OK: $outPath"
Write-Host "🧾 Log : $logPath"
}
catch {
("[{0}] ERROR {1}" -f (Get-Date), $_) | Out-File -Append -Encoding UTF8 $logPath
Write-Host "❌ Backup FAILED. Log: $logPath"
throw
}
finally {
# 止めたなら戻す
if ($stopped) {
docker compose -f $ComposeFile start @StopServices | Out-Null
}
}

ポイントはここ👇

  • busybox:stable の一時コンテナを使って tar してます🧳
  • volumeバックアップの“基本形”と同じ発想です📦 (Docker Documentation)

4) 使い方(まずは手動で試す)▶️🧪

例:volume名が myproj_db-data の場合

.\scripts\backup.ps1 -VolumeName "myproj_db-data"

DBなどで “整合性が超大事” な場合(数秒だけ止める)

.\scripts\backup.ps1 -VolumeName "myproj_db-data" -StopServices db

Dockerのvolumeバックアップは「ファイルを固める」方式なので、DBみたいに書き込み中だと“中途半端状態”が入りえます😱 だから 止めるか、(第14章の)ダンプ方式に寄せるのが安全寄りです🛡️


5) タスク スケジューラで毎日自動実行する📅🤖

ここまでできたら勝ちです🏆 Windowsのタスクスケジューラから 毎日 03:00 に動かす例いきます😴🌙

A) GUIで設定(簡単)🖱️

  1. 「タスク スケジューラ」起動

  2. 「基本タスクの作成」

  3. トリガー:毎日 03:00

  4. 操作:プログラムの開始

    • プログラム:PowerShell.exe

    • 引数(例):

      • -NoProfile -ExecutionPolicy Bypass -File "C:\path\to\scripts\backup.ps1" -VolumeName "myproj_db-data"
  5. 「開始(オプション)」にプロジェクトルートを入れると事故りにくいです📌

-ExecutionPolicy Bypass は “その実行だけ” ポリシーを回避する指定で、PowerShellの実行ポリシー自体は「うっかり事故防止」寄りの仕組みです🧯 (Microsoft Learn)

B) PowerShellでタスク登録(玄人っぽい)🧙‍♂️

公式の Register-ScheduledTask を使う形です🧩 (Microsoft Learn)

$script = "C:\path\to\scripts\backup.ps1"
$args = "-NoProfile -ExecutionPolicy Bypass -File `"$script`" -VolumeName `"myproj_db-data`""

$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $args
$trigger = New-ScheduledTaskTrigger -Daily -At 3:00am

Register-ScheduledTask -TaskName "DockerVolumeBackup" -Action $action -Trigger $trigger

6) よくある詰まりポイント集(ここで9割助かる)🧯🧠

❌ 「Volumeが見つからない」

  • docker volume ls実在する名前を確認してね🔎
  • Composeのプロジェクト名が変わると、volume名も変わりがちです😇

❌ タスクスケジューラで動かない

  • パスは 必ず絶対パスにする📌
  • ログ(.log)を見る:スクリプトは必ずログを残す設計にしてあります🧾
  • 実行ポリシーが絡むなら、-ExecutionPolicy Bypass を付ける(上の例)✅ (Microsoft Learn)

❌ バックアップはできるけど“復元できる気がしない”

それ普通です🤣 だから次の章(世代管理)と、復元テスト章(DRごっこ)につながります🎭✨


7) AI(Copilot/Codex)を安全に使うコツ🤖🛡️✨

AIに頼むと速いんだけど、破壊系コマンドが混ざる事故があるので、こう聞くのが安全です👇

  • 「PowerShellで、docker run --rm を使って volumeをtar.gzにバックアップするだけのスクリプトを書いて。docker volume inspect で存在確認も入れて。docker system prune みたいな削除コマンドは絶対に入れないで」
  • 「パスはWindowsの絶対パスで。ログも backups/ に出して」

会社名だけ出すなら:GitHub の Copilot / OpenAI の Codex みたいな補助は“下書き生成”に使って、最後は人間が安全確認が鉄則です🛡️🙂


ミニ課題🎓✨(5〜10分)

  1. docker volume ls でvolume名を1つ特定🔎
  2. backup.ps1 を手で実行して backups/.tar.gz ができるのを確認✅
  3. 可能なら -StopServices db を付けて、止め→バックアップ→再開の流れを体験🎬

次(第20章)は、この backups/ が増え続けて地獄になるので😂 命名・世代・掃除を“運用ルール化”していきます🧽📦