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

コンテナは動いているのに定義ファイルが消えていた

イメージのバージョンを固定しようとして compose ファイルを探したら、 参照先のディレクトリごと存在しなかった。コンテナは1ヶ月動き続けていた。 消したら二度と同じ構成に戻せない状態だった。

気づき方

コンテナには、どの compose ファイルから作られたかがラベルで残っている。

$ docker inspect jellyfin --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'
/data/compose/1/docker-compose.yml

この /data/compose/<id>/ は管理 UI のボリュームの中にある。見に行ったら、

$ docker run --rm -v portainer_data:/d:ro alpine ls /d/compose/
12  14  3  4  9          ← 1 が無い

スタックを UI から削除したときにファイルだけ消え、コンテナは残ったのだと思う。 動いているので誰も気づかない。

動いているコンテナから compose を復元する

docker inspect は必要な情報を全部持っている。まとめて出す。

docker inspect <name> --format '
image      : {{.Config.Image}}
network    : {{.HostConfig.NetworkMode}}
restart    : {{.HostConfig.RestartPolicy.Name}}
user       : {{.Config.User}}
runtime    : {{.HostConfig.Runtime}}
entrypoint : {{json .Config.Entrypoint}}
cmd        : {{json .Config.Cmd}}
--- mounts ---{{range .Mounts}}
  {{.Type}} {{if .Name}}{{.Name}}{{else}}{{.Source}}{{end}} -> {{.Destination}} rw={{.RW}}{{end}}
--- env ---{{range .Config.Env}}
  {{.}}{{end}}'

これを見ながら書き起こす。今回の例だとこうなった。

services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.11
    container_name: jellyfin
    restart: unless-stopped
    user: "1000:1000"
    network_mode: host
    runtime: nvidia          # ハードウェアトランスコード用
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    volumes:
      - ~/media:/media
      - ~/jellyfin/cache:/cache
      - ~/jellyfin/config:/config

env の見分け方

.Config.Env にはイメージが元から持っている環境変数も全部混ざる。 そのまま compose に書き写すと大量のノイズになる。

PATH=...                    ← イメージ由来。書かない
LANG=en_US.UTF-8            ← イメージ由来。書かない
JELLYFIN_DATA_DIR=/config   ← イメージ由来。書かない
NVIDIA_VISIBLE_DEVICES=all  ← これは自分で指定したもの。書く

判別は docker image inspect <image> --format '{{json .Config.Env}}' と 突き合わせる。差分が自分で足したもの。

復元ファイルは必ず一度使う

試していない復元手順は、無いのとあまり変わらない。 書き起こしたら、実際にそのファイルでコンテナを作り直すところまでやる。
$ docker compose -p jellyfin -f ~/homelab/jellyfin/docker-compose.yml up -d
$ docker ps --filter name=jellyfin
jellyfin  jellyfin/jellyfin:10.11.11  Up 10 seconds (healthy)

設定が bind mount にあるなら、作り直してもデータは失われない。 バージョンと healthy、それとアプリ側の状態(ライブラリが見えるか等)まで確認する。

プロジェクト名を合わせること

-p <プロジェクト名> を間違えると、 名前付きボリュームの前置が変わって別のボリュームを掴む。 データが空になったように見える。既存の値を確認してから合わせる。

$ docker inspect <name> --format '{{index .Config.Labels "com.docker.compose.project"}}'

まとめて点検する

同じことが他にも起きていないか、一度は見ておく価値がある。

for c in $(docker ps --format '{{.Names}}'); do
  f=$(docker inspect "$c" --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}')
  [ -n "$f" ] && echo "$c: $f"
done

出てきたパスが管理 UI のボリュームの中なら、その中身が実在するかを確かめる。 ホスト上のパスなら、そのファイルがあるか確かめる。