homelab notes ポート開放できない家の自宅サーバー

コンテナのバージョンを上げる手順

6つのサービスをまとめて上げた。うち2つは DB マイグレーションが一方向で、 戻すにはバックアップから復元するしかない。順番が大事だった。

固定と更新を分ける

:latest のまま運用していると、いつ何が変わったのか分からない。 まず今動いているバージョンに固定してから、改めて上げる。

  1. 稼働中の実バージョンを調べる
  2. そのバージョンのタグに固定する(このとき何も変わらないことを確認)
  3. そのあとで、意識してバージョンを上げる

混ぜると、問題が出たときに固定のせいか更新のせいか切り分けられない。

実バージョンはアプリに聞く

タグ名は当てにならないので、動いているものに直接聞く。

curl -s http://127.0.0.1:3000/api/health          | jq -r .version   # Grafana
curl -s http://127.0.0.1:9090/api/v1/status/buildinfo | jq -r .data.version
curl -s http://127.0.0.1:8096/System/Info/Public | jq -r .Version   # Jellyfin
curl -sk https://127.0.0.1:9443/api/status       | jq -r .Version   # Portainer
curl -s http://127.0.0.1:11434/api/version       | jq -r .version   # Ollama
curl -s http://127.0.0.1:9100/metrics | grep -m1 '^node_exporter_build_info'

固定は「何も起きない操作」にする

固定先タグのダイジェストが、今動いているものと同一かを書き換える前に確認する。 一致していれば、再ダウンロードもバージョン変化も起きない。

ローカル  prom/prometheus:latest   の digest
レジストリ prom/prometheus:v3.13.2  の digest
   → 一致すれば安全に書き換えられる

上げる前に

DB マイグレーションは一方向。 新しいバージョンで起動した瞬間にスキーマが変換され、古いバージョンでは読めなくなる。 イメージのタグを戻しても直らない。戻す手段はバックアップからの復元だけ。 上げる直前にスナップショットを取り、その ID を控えておく。

イメージは先に全部取得しておく。落としながら適用すると待ち時間が読めない。

for i in <image1> <image2> ...; do
  printf '%-48s ' "$i"
  docker pull -q "$i" >/dev/null 2>&1 && echo OK || echo 失敗
done

リスクの低い順に上げる

種類リスク
状態を持たない exporternode-exporter, cadvisor低い。壊れても再起動で戻る
時系列 DBPrometheus中。データ形式は同一メジャーなら安定
設定を DB に持つものGrafana, 管理 UI高い。マイグレーションが一方向
マイナーを飛ばすもの3世代ぶんの更新など高い。単独でやる

上げたあとに見るもの

起動しただけでは確認にならない。中身が残っているかまで見る。

# バージョンが変わったか
curl -s http://127.0.0.1:3000/api/health | jq -r '.version, .database'

# データが残っているか(DB を直接数える)
sqlite3 grafana.db "select count(*) from dashboard;"
sqlite3 grafana.db "select count(*) from data_source;"

# マイグレーションのログ
docker logs <name> 2>&1 | grep -iE 'migrat|alembic|error'

「0件」を見たら更新前と比べる

更新後にダッシュボードが 0 件で、消えたかと思った。 更新直前のスナップショットから DB を取り出して数えたら、更新前も 0 件だった。

$ restic restore <更新直前のID> --target /tmp/t --include /src/vol/grafana
$ sqlite3 /tmp/t/src/vol/grafana/grafana.db "select count(*) from dashboard;"
0        ← 元から 0。消失ではない
「更新後の値」だけ見ても、それが異常なのか元からなのか分からない。 バックアップを取っておくと、復元手段としてだけでなく比較対象として使える。 これが一番役に立った場面だった。

段階を分けた例

更新の止まった非公式ミラーから本家へ移りつつ、3世代ぶんの更新も必要だったとき、 2回に分けた。

  1. 同じバージョンのままレジストリだけ本家に移す(0.8.12 → 0.8.12)
  2. そのあとバージョンを上げる(0.8.12 → 0.11.3)

1 では何も起きないことを確認でき、2 ではマイグレーション7段だけを単独で観測できた。 まとめてやっていたら、問題が出ても原因を絞れなかった。