この文章は、Geminiと相談しながらやったサーバーの操作を最後に作業ログとして要約してもらったものです。
内容の正しさは一切保証できません!!!
目的: Proxmox上のlumine VMで発生しているToo many open files in systemエラーの根本原因を特定し、恒久的な解決策を講じる。
パート1: 問題の発生と原因究明
1. 問題の概要
Proxmox上のVM lumine (ID 100) において、ls /mnt/dataなどのファイルシステム操作時にToo many open files in systemエラーが頻発。これにより、同VM内のDockerで稼働しているJellyfin, Stash, Copypartyなどのサービスが正常に機能しない事態が発生した。
この問題は、ストレージ(8TB HDD)の共有方法を、VMへの直接パススルーから、Proxmoxホスト経由での複数ゲスト(lumine VM, nahida LXC)への共有に変更した直後から顕在化した。
2. 調査記録(思考とコマンドの変遷)
-
初期仮説: VM内のアプリケーション(Jellyfin, Netdata)がファイルディスクリプタをリークしているのではないか?
- 調査:
lumineVM内でlsofコマンドを実行。Terminal window sudo lsof | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10 - 結果:
jellyfinやnetdataが1万を超えるファイルを開いていることが判明。これらが容疑者として浮上。
- 調査:
-
仮説の修正: プロセス毎の上限値(
ulimit -n)は1,048,576と非常に高く、1万程度では上限に達しない。また、システム全体の上限(cat /proc/sys/fs/file-nr)も2400程度と低い値で、lsofの結果と矛盾する。- 考察: エラーメッセージはVM内で出ているが、リソース枯渇の真の原因はVMの外部にある可能性が浮上。VMへの共有方法であるVirtIO-FSが怪しいと判断。
-
真犯人の特定: Proxmoxホスト(
pve1)側で、lumineVMのために動作しているvirtiofsdプロセスを調査。- 調査:
pve1上でvirtiofsdプロセスのPIDを特定し、開いているファイル数を確認。Terminal window ps aux | grep virtiofsd# PID 454363 が怪しいと特定ls -l /proc/454363/fd | wc -l - 決定的証拠:
virtiofsdプロセスが約100万個のファイルディスクリプタを消費しており、プロセスの上限に達していることが判明。
- 調査:
3. 根本原因の結論
VM内でJellyfinやNetdataのようなファイルシステムを広範囲にスキャンするアプリケーションが動作すると、その大量のアクセス要求がVirtIO-FSの中継デーモン(virtiofsd)に集中する。このvirtiofsdが要求を捌ききれずにリソース(ファイルディスクリプタ)を枯渇させ、その結果としてVM側にToo many open filesエラーを返していた。
これは、広範囲スキャン型アプリケーションとVirtIO-FSという技術の間の、根本的な非互換性・相性問題であると結論付けた。
パート2: 解決策 - VMからLXCへのアーキテクチャ移行
1. 基本方針
VirtIO-FSの使用を完全にやめるため、lumineの役割をVMからLXCコンテナに移行する。LXCであれば、ホストのファイルシステムをバインドマウントというカーネルレベルの高速かつ安定した仕組みで共有できるため、virtiofsdのようなボトルネックは発生しない。
現在のdocker-compose.ymlによる運用スタイルを維持するため、単一のLXC内にDocker環境を構築し、既存の構成を丸ごと移行するという「現実的・実践的な最善手」を選択した。
2. 移行手順サマリー
フェーズ1: 新LXCの作成
Proxmox UIにて、以下の仕様で新しいLXCを作成。一時的なホスト名lumine-newを使用。
- ID: 103
- ホスト名:
lumine-new - リソース: 2コア, 8GB RAM, 64GB Disk
- テンプレート: Ubuntu 24.04
- ネットワーク:
lumineVMと同一のIP (192.168.x.201/24) とMACアドレス (BC:24:11:xx:xx:xx) を設定。 - オプション: ネスト化(Nesting) と キーコントロール(keyctl) を有効化。
フェーズ2: LXC設定の編集 (pve1ホストにて)
作成したLXCの設定ファイル (/etc/pve/lxc/103.conf) に、ストレージとハードウェアパススルーのための設定を追記。
# メディア用HDDをバインドマウントmp0: /mnt/storage-8tb,mp=/mnt/data
# Intel QSV (iGPU) パススルーlxc.cgroup2.devices.allow: c 226:* rwmlxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dirフェーズ3: LXC内部のセットアップ
- LXCを起動し、rootでログイン。
myuserユーザーを、古いVMと同じUID/GID (1000:1000) で作成。Terminal window groupadd -g 1000 myuseruseradd -m -s /bin/bash -u 1000 -g 1000 myuserpasswd myuserusermod -aG sudo myuser- DockerとDocker Composeをインストール。
Terminal window curl -fsSL https://get.docker.com -o get-docker.shsh get-docker.shapt install -y docker-compose-pluginusermod -aG docker myuser
フェーズ4: データの移行
IPアドレスの競合を避けるため、古いlumine VMのIPをnetplanで一時的に192.168.x.250に変更。その後、新しいLXCからrsyncでデータをコピー。
# lumine-new LXC側で実行mkdir -p /home/myuser/docker/mainrsync -avz --progress myuser@192.168.x.250:~/docker/main/ /home/myuser/docker/main/フェーズ5: サービスの起動と最終切り替え
- 新しいLXCで
docker-compose up -dを実行。 - 後述のトラブルシューティングを経て、全サービスの正常動作を確認。
- 古いVMと新しいLXCをシャットダウンし、Proxmox UIで名前を入れ替えた。(旧:
lumine→lumine-vm, 新:lumine-new→lumine) - 新しい
lumineLXCを本番機として起動。
パート3: 移行後のトラブルシューティング記録
移行は一直線ではなかった。いくつかの重要な問題が発生し、それぞれ調査と解決を要した。
問題1: AdGuard Homeのポート競合
- 現象:
docker-compose up -d実行時、adguardがaddress already in useエラーで起動失敗。 - 調査:
sudo lsof -i :53により、ホストOSのsystemd-resolvedがポート53を使用していることを特定。 - 解決:
systemd-resolvedを停止・無効化。Terminal window sudo systemctl stop systemd-resolvedsudo systemctl disable systemd-resolved - 追加問題: AdGuard Homeの初期設定で管理ポートを80にしてしまい、NPMと競合。
- 解決:
AdGuardHome.yamlを直接編集し、http.addressを:3000に修正。
問題2: Tailscaleデーモンの起動失敗
- 現象:
sudo tailscale upが失敗。tailscaledサービスがfailed (Result: exit-code)でクラッシュする。 - 調査:
sudo journalctl -u tailscaled.serviceで詳細ログを確認。という決定的エラーを発見。CreateTUN("tailscale0") failed; /dev/net/tun does not exist - 原因: Proxmoxホストに
tunカーネルモジュールがロードされておらず、結果としてLXC内に/dev/net/tunデバイスを作成できなかった。 - 解決: 2段階の修正を実施。
pve1ホスト側でtunモジュールをロードし、恒久化。Terminal window modprobe tunecho tun > /etc/modules-load.d/tun.confpve1ホスト側でLXCの設定ファイル (/etc/pve/lxc/103.conf) に、デバイスの作成権限とマウント設定を追記。lxc.cgroup2.devices.allow: c 10:200 rwmlxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
問題3: *.lumine形式でのアクセス失敗
- 現象:
IP:PORTでのアクセスは成功するが、memos.lumineのようなホスト名でのアクセスができない。 - 調査:
- クライアントPCでの
ping lumineが古いTailscale IPを返しており、名前解決がおかしいことが判明。 - AdGuard Homeのクエリ・ログに、クライアントPCからの問い合わせが一切記録されていないことを確認。
tcpdumpでも、クライアントPCからLXCへのパケットが届いていないことを確認。
- クライアントPCでの
- 原因: TailscaleのDNS設定にある「Override DNS servers」が有効になっており、クライアントPCのDNS設定を強制的に上書きしていた。これにより、LAN内のAdGuard Homeが使われず、名前解決が失敗していた。
- 解決: TailscaleのAdmin Console > DNS設定にて、以下を実施。
- 「Override DNS servers」をオフにする。
- 「Global nameservers」にAdGuard HomeのLAN IP (
192.168.x.201) を設定する。
パート4: 最終確認と得られた教訓
1. 最終的なシステム構成
lumineサービス群は、Proxmox上の軽量なLXCコンテナ内で、Docker Composeによって安定して稼働している。ストレージはホストからのバインドマウントで高速に共有され、ファイルディスクリプタの問題は完全に解消された。ネットワークはAdGuard HomeとTailscaleが協調して動作し、LAN内外から一貫したホスト名で各サービスにアクセス可能となっている。
2. 得られた教訓
- VirtIO-FSの限界: VirtIO-FSは便利だが、Jellyfinのようにファイルシステム全体を高頻度でスキャンするワークロードには不向きである。リソース枯渇のボトルネックになり得る。
- LXCの優位性: Dockerホストのような用途では、VMよりもLXCの方がオーバーヘッドが少なく、パフォーマンス(特にI/O)上有利である。バインドマウントは非常に強力。
- 体系的なトラブルシューティングの重要性:
lsof→journalctl→tcpdump→ クエリ・ログと、レイヤーを追って順に調査することで、複雑な問題も最終的に原因を特定できる。憶測で修正せず、事実に基づいて行動すること。 - DNSは常に疑え: ネットワークの問題、特に「名前でアクセスできない」場合は、DNSのどのレイヤー(クライアントキャッシュ、ローカルDNS、Tailscale MagicDNS)で問題が起きているかを切り分けることが解決への近道である。
3. 残存タスク
- [済] 古い
lumine-vmのバックアップ取得と削除。 - [済] 不要になった
systemd設定の削除。 - [済] 新しい
lumineLXCの内部ホスト名をlumineに変更。 - [要] 新しい
lumineLXCの定期バックアップジョブをProxmoxで設定する。
以上で、本件に関するすべての作業を完了とする。

↑nano-banana製。かわいい。