Skip to main content

第20章:“バックアップファイル”の管理:命名・世代・掃除🧽

バックアップって「取る」よりも、溜まり続けるファイルをちゃんと管理するほうが長期的に効きます😇 この章では、迷子にならない命名復元できる世代設計安全な掃除をセットで仕上げます💪✨


0) この章のゴール🏁✨

終わったら、これができるようになります👇

  • バックアップファイルを見て「いつ・何の・どの方式のバックアップか」すぐ分かる👀✅
  • 「何世代残す?」をルール化して、増えすぎ事故を防ぐ📅🧯
  • 削除前に必ず安全確認できる、掃除スクリプト(PowerShell)を持つ🧰🪄
  • 容量を定期チェックして、ディスク満杯で死ぬのを回避する🫠➡️🙂

1) まず“バックアップ置き場”を固定する📁🧷

バックアップは、置き場がブレると即カオスになります🤯 おすすめはプロジェクト直下にこう👇

  • backup/ … バックアップ本体(.tar/.tar.gz/.sql.gz など)
  • backup/_manifest/ … メタ情報(後述)
  • backup/_quarantine/ … 削除前の一時退避(安全のため)🛟

「消す」作業がある以上、退避フォルダがあるだけで事故率が激減します🙏🧯


2) 命名ルール:人間にも機械にも優しく😇🧠

2-1) 命名に“必須で入れるべき要素”✅

バックアップファイル名に最低これを入れると強いです👇

  1. プロジェクト名(例:myapp
  2. 対象(例:pgdata / redisdata / uploads
  3. 方式(例:voltar = volumeをtar、pgdump = 論理ダンプ)
  4. タイムスタンプ(例:20260211_142530
  5. 拡張子(例:.tar.gz / .sql.gz

さらに余裕があれば👇も入れると神😇✨

  • 環境dev / stg / prod
  • 世代や種別daily / weekly など)

2-2) おすすめ命名フォーマット(コピペ用)📌

例(物理バックアップ=volumeをtarで固める)👇

<project>__<target>__<method>__<YYYYMMDD_HHMMSS>.<ext>

具体例👇

myapp__pgdata__voltar__20260211_142530.tar.gz
myapp__pgdata__pgdump__20260211_142530.sql.gz
myapp__uploads__voltar__20260211_142530.tar.gz

章15でやった「volumeをtarでバックアップ」方式は、Docker公式でも tar で固める例が載っています(--volumes-from で対象volumeをマウントして tar する)✅ (Docker Documentation)

2-3) “ファイル名に入れない方がいいもの”🚫

  • スペース(扱いづらい)
  • 日本語(将来ツール連携で詰まりがち)
  • パスワード等の秘密(絶対ダメ)🔑💥

3) 世代管理:まずは“雑に強い”ルールでOK📅🛡️

設計が超入門でも大丈夫🙆‍♂️ まずは「毎日作る」前提で、こんな感じが事故りにくいです👇

3-1) まずのおすすめ(個人開発〜小規模)🌱

  • 直近のN個を残す(例:7個
  • さらに“古すぎるのは消す”(例:30日より古いのは削除対象

これだけで「増えすぎ」「古いの残りすぎ」が止まります🧯✨

3-2) ちょい強め(運用っぽくする)💪

  • daily:7世代
  • weekly:4世代
  • monthly:12世代

ただし最初から完璧にしなくてOK! まずは “7個 + 30日” みたいに小さく始めて、後で育てましょう🌱➡️🌳


4) 容量の把握:バックアップが太り始めたら即わかるように👀📈

4-1) Docker側の使用量(参考)🐳

Dockerが使ってるディスク量の概算はこれ👇

docker system df

docker system df は Dockerデーモンが使っているディスク使用量を表示します。(Docker Documentation)

⚠️ これは「バックアップフォルダのサイズ」ではなく、Docker全体(イメージ/コンテナ/キャッシュ等)の話です!

4-2) バックアップフォルダのサイズ(本命)📦

## backup フォルダの合計サイズをざっくり見る
$bytes = (Get-ChildItem -Recurse -File .\backup | Measure-Object -Sum Length).Sum
"{0:N2} GB" -f ($bytes / 1GB)

これを週1でも見るだけで、満杯事故が減ります🙂✨


5) 掃除(削除)は“事故りやすい”ので儀式化する🧯🙏

削除で一番多い事故👇

  • 「フォルダ指定ミス」
  • 「新しいのまで消した」
  • 「消した瞬間に戻せない」😱

なので、削除はこの順番が鉄板です👇

  1. **Dry-run(消す予定だけ表示)**👀
  2. **Quarantineへ移動(退避)**🛟
  3. **本削除(問題なければ)**🗑️

6) 実装:バックアップ掃除スクリプト(PowerShell)🧰🪄

やることはシンプル👇

  • 指定フォルダのバックアップを新しい順に並べる
  • 直近N個は絶対残す
  • それ以外は X日より古いものを削除(または退避)

6-1) scripts/cleanup-backups.ps1(コピペOK)📌

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

# 直近いくつ残す?
[int]$KeepLast = 7,

# 何日より古いものを削除対象にする?
[int]$DeleteOlderThanDays = 30,

# まずは消さずに「消す予定」を表示したい?
[switch]$DryRun = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$resolved = Resolve-Path $BackupDir
$backupPath = $resolved.Path

## 事故防止:ルート直下みたいな危険パスを弾く(ざっくり)
if ($backupPath.Length -lt 5) {
throw "BackupDir が短すぎます。事故防止で停止します: $backupPath"
}

$now = Get-Date
$threshold = $now.AddDays(-$DeleteOlderThanDays)

## 対象拡張子(必要なら増やしてOK)
$targets = Get-ChildItem -Path $backupPath -File -Recurse |
Where-Object { $_.Name -match '\.(tar|tar\.gz|tgz|sql|sql\.gz)$' }

if (-not $targets) {
Write-Host "対象ファイルが見つかりません: $backupPath"
exit 0
}

## 新しい順
$sorted = $targets | Sort-Object LastWriteTime -Descending

## 残す(直近N個)
$keep = $sorted | Select-Object -First $KeepLast
$keepSet = @{}
$keep | ForEach-Object { $keepSet[$_.FullName] = $true }

## 削除候補(古い + KeepLast以外)
$candidates = $sorted | Where-Object {
(-not $keepSet.ContainsKey($_.FullName)) -and ($_.LastWriteTime -lt $threshold)
}

Write-Host "=== Backup cleanup plan ==="
Write-Host "BackupDir: $backupPath"
Write-Host "KeepLast : $KeepLast"
Write-Host "DeleteOlderThanDays: $DeleteOlderThanDays (threshold: $threshold)"
Write-Host ""
Write-Host ("Keep: {0} files" -f $keep.Count)
Write-Host ("Delete candidates: {0} files" -f ($candidates | Measure-Object).Count)
Write-Host ""

## 何を消す予定か表示
$candidates | Select-Object LastWriteTime, Length, FullName | Format-Table -AutoSize

if ($DryRun) {
Write-Host ""
Write-Host "DryRun=true なので削除しません🙂"
exit 0
}

## 本削除(慎重に)
Write-Host ""
Write-Host "削除を実行します…🗑️"
foreach ($f in $candidates) {
Remove-Item -LiteralPath $f.FullName -Force
}
Write-Host "完了✅"

6-2) 実行例(まずはDry-run)👀

## まずは Dry-run(デフォルト)で確認
.\scripts\cleanup-backups.ps1 -BackupDir .\backup -KeepLast 7 -DeleteOlderThanDays 30

6-3) 問題なければ本削除(DryRunをOFF)🗑️

.\scripts\cleanup-backups.ps1 -BackupDir .\backup -KeepLast 7 -DeleteOlderThanDays 30 -DryRun:$false

7) 仕上げ:メタ情報も一緒に残すと“復元が強くなる”🧾✨

ファイル名だけでも運用できます。 でも、復元時に助かるのが「メタ情報」😇

たとえばバックアップと同じ名前で、これを残す👇

  • myapp__pgdata__voltar__20260211_142530.tar.gz
  • myapp__pgdata__voltar__20260211_142530.manifest.json

manifest には最低これだけでOK👇

  • 作成日時
  • 対象(volume名、サービス名)
  • 方式(voltar / pgdump)
  • gitのコミットハッシュ(任意)
  • ひとことメモ(何を変えた直後か)

8) 「掃除」と「prune」は別物!ここ混ざると危険😱⚠️

8-1) docker volume prune は「未使用volume削除」🧨

docker volume pruneどのコンテナにも参照されていない未使用ローカルvolumeを削除します。(Docker Documentation) バックアップファイル(.tar.gz)を消すコマンドではありません🙅‍♂️

8-2) docker system prune は volume を勝手に消さない(通常は)🙂

Docker公式の pruning ガイドでは、docker system prune は基本的にイメージ/コンテナ/ネットワーク等を掃除するショートカットで、volume はデフォルトでは対象外、消すなら --volumes が必要、と説明されています。(Docker Documentation)

つまり

  • バックアップファイル整理 = この章のスクリプト
  • Docker内部の掃除 = prune 系 で、頭の引き出しを分けるのが安全です🧠🧷

9) Docker Desktop丸ごと系の話(補足)🧰

「PC引っ越し」「壊れた」みたいな時は、プロジェクト単位のバックアップと別に、Docker Desktop全体のバックアップ/リストア手順も公式にあります。 公式は、イメージやコンテナのデータのバックアップ/復元の流れや注意点(volumeの中身はイメージに含まれない等)を説明しています。(Docker Documentation)

この章のテーマ(バックアップ“ファイル”管理)とは別枠ですが、緊急時に助かるので存在だけ覚えておくと安心です🆘🙂


10) 成果物:運用ルール(3行でOK)📝✨

迷ったらこれでOK👇(そのまま README に貼れるやつ)

  1. 命名<project>__<target>__<method>__<YYYYMMDD_HHMMSS>.<ext>
  2. 世代:直近 7個は必ず残す+30日より古いのは削除対象
  3. 削除手順:まず Dry-run → 問題なければ本削除(スクリプトで統一)

11) AI(Copilot等)に手伝わせるなら、この聞き方が安全🛡️🤖

削除系は危ないので、AIにはこう頼むのが良いです👇

  • 「このPowerShell、消す条件を日本語で説明して」
  • 絶対消しちゃいけないケースを3つ挙げて」
  • 「Dry-runのままなら何が起きる?」
  • 「KeepLast と DeleteOlderThanDays の組み合わせで、削除されないケースは?」

コマンド丸投げより、条件の言語化をさせるとミスが減ります🙂🧠✨


次の章(第21章)は、ここで整えたバックアップに「秘密が混ざる問題」🚫🔑を潰しにいきます。 この第20章ができてると、21章がめちゃ楽になりますよ〜😆📦✨