コンテナ更新の戻し方を用意してからlatestを追う(検証ログ)

家庭ラボのコンテナ更新は、latestタグより先に「戻し方」を決める(検証ログ)を描いたアイキャッチ画像
目次

latestタグは便利ですが、家庭ラボの更新計画には少し粗いです

平日はNAS上でHome Assistant周辺サービスや監視ツールを動かし続けたい。けれど更新作業に長い時間は取れない。その状態で一番こわいのは、新しい更新そのものではなく、更新したあとサービスが起動しなくなり、しかも元に戻せないことです。

コンテナはサービスの追加を簡単にしますが、latestタグや自動更新だけに任せると、関連ライブラリの変更・設定仕様の変更・データベース移行が静かに混入し、復旧が難しくなります。この記事は「新しい版へどう追従するか」ではなく、「壊れたとき、短時間でどう戻すか」を扱います。

結論から言うと、家庭ラボで先に決めるべきは自動更新ではなく、戻し点(タグ・Compose・データ)の確保と、失敗時の戻す順番です。これを実機で確認しました。

まず分けて考える:イメージ更新と永続データのバックアップは別物です

Docker Composeは「サービス定義(Composeファイル)」と「イメージの取得」を分けて扱います。さらにDockerのボリュームは、コンテナのライフサイクルと永続データを分離します。つまり家庭ラボの更新で守る対象は、少なくとも三つに分かれます。

  • イメージタグ:どの版で動かすか。latestは中身が変わり続けるため、戻し先を特定できません。
  • Composeファイル:サービス定義。更新時に書き換わると、戻すには元の定義が必要です。
  • 名前付きボリューム:永続データ。イメージを戻してもデータは戻りません。別に退避が要ります。

イメージを差し替えるだけのサービス(再生成が容易なステートレス)と、永続データを抱えるサービスとでは、復旧コストが大きく異なります。ここが後述の「自動更新してよい/手動確認すべき」の分かれ目になります。

比較:あなたが今すでに迷っている4つの更新運用

週末保守の家庭ラボ運用者が実際に比べているのは、おおむね次の4つです。復旧しやすさを軸に整理します。

運用方法 復旧しやすさ 更新頻度 停止時間 設定・データ保護 更新後の確認コスト
latestタグで自動更新 低い(戻し先が特定できない) 高い 不定(失敗時に長引く) 退避を別途仕込まない限り弱い 低く見えるが事故時に跳ね上がる
バージョンタグ固定+手動更新 高い(戻し先が明確) 自分で決められる 短くできる タグ+退避を組めば強い 手動分のコストはかかる
Watchtower系の自動更新 中(自動pullは速いが戻しは別設計) 高い 自動再起動で短い場合あり 自動更新自体はデータを守らない 異常検知の仕組みが別途必要
ComposeファイルをGit管理 高い(定義の差分・復元が容易) 任意 短くできる 定義は守れるがデータは別 低〜中(差分で把握しやすい)

ポイントは、Watchtowerやlatestは「追従の速さ」を上げますが、それ自体は永続データを守りません。Git管理はComposeファイル(定義)を守りますが、ボリュームのデータは別途退避が必要です。どれを選んでも、戻し点の確保は別の作業として残ります。

検証環境

  • 環境:Docker導入済みの使い捨て一時VM(作業後に破棄)
  • Docker:Docker Engine 29.6.0 / Docker Compose v5.1.4
  • 対象スタック:単一サービス(nginx固定タグ+名前付きボリューム+ヘルスチェック)
  • 目的:固定タグ運用を組み、更新失敗を意図的に再現したうえで、固定タグへの戻し・Composeファイル復元・名前付きボリュームからのデータ復元によるロールバックが実機で成立するかを確認する

検証は隔離した一時ディレクトリ内で完結させ、最後に必ず後片付け(ボリューム・コンテナ・作業ディレクトリの削除)まで行いました。

実行コマンドと結果

1. ベースライン(固定タグのComposeを起動)

固定タグ(nginx:1.27.0)でサービスを定義し、ヘルスチェックと名前付きボリュームを付けて起動します。

services:
  app:
    image: nginx:1.27.0
    volumes:
      - appdata:/usr/share/nginx/html
    healthcheck:
      test: ["CMD", "sh", "-c", "wget -qO- http://localhost/ >/dev/null"]
      interval: 5s
      timeout: 3s
      retries: 5
volumes:
  appdata:
docker compose -p rollback-lab up -d
docker compose -p rollback-lab ps

結果:nginx:1.27.0 のコンテナが起動し、ヘルスチェックが動き始めました(設定項目: Up, health: starting)。

2. 復元確認用の目印を永続データに書き込む

ロールバックでデータが本当に戻ったかを判定するため、ボリューム側に既知の内容を書き込みます。

docker compose -p rollback-lab exec -T app \
  sh -c 'echo baseline-marker > /usr/share/nginx/html/marker.txt'

結果:baseline-marker を書き込み・読み出しできることを確認。

3. 戻し点の確保(Composeとボリュームの退避)

ここが「更新前に最低限控えるべき」中身です。Composeファイルのコピーと、名前付きボリュームのtarバックアップを取ります。

cp compose.yml compose.yml.bak
docker run --rm \
  -v rollback-lab_appdata:/data \
  -v $(pwd):/backup busybox \
  tar czf /backup/volume-baseline.tgz -C /data .

結果:compose.yml.bak(定義の戻し先)と volume-baseline.tgz(データの戻し先)の2つが揃いました。

4. 更新失敗を意図的に再現する

latestや非互換タグへの更新で起こりがちな事故を、解決できないタグへの差し替えで再現します。

sed -i 's#image: nginx:1.27.0#image: nginx:nonexistent-tag-9999#' compose.yml
docker compose -p rollback-lab pull
docker compose -p rollback-lab up -d
docker compose -p rollback-lab ps

結果:pullが not found(タグ解決失敗)で失敗しました。重要なのは、pullに失敗した時点では稼働中のコンテナは旧版(nginx:1.27.0)のまま動き続けていたことです。つまり更新の失敗形態によって、すでに動いているサービスが即停止するとは限りません。逆に言えば、ここで「失敗に気づかないまま二度目の操作」をすると壊れ得る、という注意点でもあります。

5. ロールバック(戻す順番)

戻す順番を固定します。Composeファイルを戻す → 一度downする → ボリュームを復元する → upする → 目印を確認する、の順です。

cp compose.yml.bak compose.yml
docker compose -p rollback-lab down
docker run --rm \
  -v rollback-lab_appdata:/data \
  -v $(pwd):/backup busybox \
  sh -c 'rm -rf /data/* && tar xzf /backup/volume-baseline.tgz -C /data'
docker compose -p rollback-lab up -d
docker compose -p rollback-lab exec -T app cat /usr/share/nginx/html/marker.txt

結果:イメージが nginx:1.27.0 に戻り、コンテナがUp、marker.txt の中身も baseline-marker に復元されました。定義・イメージ・永続データの三つがすべて戻ったことを確認できました。

6. 自動更新可否の切り分け観測

復旧コストの差を記録します。

ステートレス(再生成容易)= イメージpull+再起動のみで復旧、データ退避不要
永続データ保持        = タグ戻しに加えボリューム復元が必須、復旧手順と停止時間が増加

7. 後片付け(必須)

docker compose -p rollback-lab down -v
rm -rf <作業ディレクトリ>

結果:コンテナ・ボリューム・ネットワーク・作業ディレクトリがすべて消え、残骸がないことを確認しました。検証用スタックは環境に残していません。

結果:戻せる更新運用の最小セット

今回の実機確認でそろえた「最小セット」は次の5点です。これだけ用意しておけば、更新が失敗しても短時間で戻せることを確認しました。

  1. イメージタグを固定するlatestではなくバージョンタグ)。戻し先を特定できるようにする。
  2. Composeファイルを退避する.bak、可能ならGit管理)。定義の差分と復元先を持つ。
  3. 名前付きボリュームをバックアップする(tarで退避)。イメージを戻してもデータは戻らないため別作業として行う。
  4. 更新後にヘルスチェックで確認する。Up表示だけでなく、応答するかまで見る。
  5. 戻す順番を決めておく(Compose復元 → down → ボリューム復元 → up → 目印確認)。

自動更新してよいサービスと、手動確認すべきサービスの切り分け

実機観測からの基準はシンプルです。

  • 再生成が容易なステートレスサービス(リバースプロキシ、静的配信、再構築できるキャッシュ系など)は、イメージのpullと再起動だけで復旧できます。自動更新を許容しやすい側です。
  • 永続データを抱えるサービス(データベース、Home Assistantの設定・履歴、メディア管理のメタデータなど)は、タグ戻しに加えてボリューム復元が必須で、復旧手順も停止時間も増えます。自動更新は避け、手動確認を残す側です。

つまり「全部を自動更新」でも「全部を手動」でもなく、データを持つサービスだけ手動確認に残すのが、週末保守の現実的な落とし所になります。

失敗・制約・再現条件

正直に範囲を区切ります。今回の確認はあくまで一度きりの限定検証です。

  • 単一サービスでの確認です。複数サービスが相互連携するスタックでの起動順序や部分復旧は未検証です。
  • データベースのスキーマ移行は未検証です。tarでのボリューム復元は「ファイルとして元に戻す」もので、更新側がデータ形式を不可逆に変換した後では、ボリューム復元だけで戻るとは限りません。DB系は更新前のダンプ取得まで含めて別途設計してください。
  • 更新失敗はタグ解決失敗で再現しました。設定仕様の非互換による起動後クラッシュなど、別の失敗形態は今回の対象外です。
  • 検証は使い捨ての一時VM上で一度実施し、終了後に破棄しています(一度きりの検証)。再現するには、Docker導入済みの隔離環境で同じ手順(固定タグ起動 → 退避 → 失敗再現 → ロールバック → 後片付け)を実行します。

まとめ

家庭ラボのコンテナ更新で先に決めるべきは、便利な自動化ではなく失敗時の戻し方です。タグを固定し、Composeとボリュームの戻し点を持ち、戻す順番を決めておけば、更新が失敗しても短時間で復旧できることを実機で確認しました。自動更新は、再生成が容易なサービスから少しずつ。データを持つサービスは、手動確認を残してください。

(参考:Docker公式ドキュメント Compose / services / volumes / compose pull)

この検証を回している環境

この検証は、自宅の常設ラボ(使い捨てVM/LXCを回す母艦+GPU+VLAN分離ネットワーク)で動かしています。使っている機材と選定理由、全体構成は1本にまとめています。

ラボ構成のまとめを見る →
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次