2123 文字
11 分
lumine VMの Too many open files 問題の解決とLXCへの移行メモ
2025-10-21

この文章は、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. 調査記録(思考とコマンドの変遷)#

  1. 初期仮説: VM内のアプリケーション(Jellyfin, Netdata)がファイルディスクリプタをリークしているのではないか?

    • 調査: lumine VM内でlsofコマンドを実行。
      Terminal window
      sudo lsof | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
    • 結果: jellyfinnetdataが1万を超えるファイルを開いていることが判明。これらが容疑者として浮上。
  2. 仮説の修正: プロセス毎の上限値(ulimit -n)は1,048,576と非常に高く、1万程度では上限に達しない。また、システム全体の上限(cat /proc/sys/fs/file-nr)も2400程度と低い値で、lsofの結果と矛盾する。

    • 考察: エラーメッセージはVM内で出ているが、リソース枯渇の真の原因はVMの外部にある可能性が浮上。VMへの共有方法であるVirtIO-FSが怪しいと判断。
  3. 真犯人の特定: Proxmoxホスト(pve1)側で、lumine VMのために動作している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
  • ネットワーク: lumine VMと同一の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:* rwm
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
フェーズ3: LXC内部のセットアップ#
  1. LXCを起動し、rootでログイン。
  2. myuserユーザーを、古いVMと同じUID/GID (1000:1000) で作成。
    Terminal window
    groupadd -g 1000 myuser
    useradd -m -s /bin/bash -u 1000 -g 1000 myuser
    passwd myuser
    usermod -aG sudo myuser
  3. DockerとDocker Composeをインストール。
    Terminal window
    curl -fsSL https://get.docker.com -o get-docker.sh
    sh get-docker.sh
    apt install -y docker-compose-plugin
    usermod -aG docker myuser
フェーズ4: データの移行#

IPアドレスの競合を避けるため、古いlumine VMのIPをnetplanで一時的に192.168.x.250に変更。その後、新しいLXCからrsyncでデータをコピー。

Terminal window
# lumine-new LXC側で実行
mkdir -p /home/myuser/docker/main
rsync -avz --progress myuser@192.168.x.250:~/docker/main/ /home/myuser/docker/main/
フェーズ5: サービスの起動と最終切り替え#
  1. 新しいLXCでdocker-compose up -dを実行。
  2. 後述のトラブルシューティングを経て、全サービスの正常動作を確認。
  3. 古いVMと新しいLXCをシャットダウンし、Proxmox UIで名前を入れ替えた。(旧: luminelumine-vm, 新: lumine-newlumine
  4. 新しいlumine LXCを本番機として起動。

パート3: 移行後のトラブルシューティング記録#

移行は一直線ではなかった。いくつかの重要な問題が発生し、それぞれ調査と解決を要した。

問題1: AdGuard Homeのポート競合#

  • 現象: docker-compose up -d実行時、adguardaddress already in useエラーで起動失敗。
  • 調査: sudo lsof -i :53により、ホストOSのsystemd-resolvedがポート53を使用していることを特定。
  • 解決: systemd-resolvedを停止・無効化。
    Terminal window
    sudo systemctl stop systemd-resolved
    sudo 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段階の修正を実施。
    1. pve1ホスト側tunモジュールをロードし、恒久化。
      Terminal window
      modprobe tun
      echo tun > /etc/modules-load.d/tun.conf
    2. pve1ホスト側でLXCの設定ファイル (/etc/pve/lxc/103.conf) に、デバイスの作成権限とマウント設定を追記。
      lxc.cgroup2.devices.allow: c 10:200 rwm
      lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

問題3: *.lumine形式でのアクセス失敗#

  • 現象: IP:PORTでのアクセスは成功するが、memos.lumineのようなホスト名でのアクセスができない。
  • 調査:
    1. クライアントPCでのping lumine古いTailscale IPを返しており、名前解決がおかしいことが判明。
    2. AdGuard Homeのクエリ・ログに、クライアントPCからの問い合わせが一切記録されていないことを確認。
    3. tcpdumpでも、クライアントPCからLXCへのパケットが届いていないことを確認。
  • 原因: TailscaleのDNS設定にある「Override DNS servers」が有効になっており、クライアントPCのDNS設定を強制的に上書きしていた。これにより、LAN内のAdGuard Homeが使われず、名前解決が失敗していた。
  • 解決: TailscaleのAdmin Console > DNS設定にて、以下を実施。
    1. 「Override DNS servers」をオフにする。
    2. 「Global nameservers」にAdGuard HomeのLAN IP (192.168.x.201) を設定する。

パート4: 最終確認と得られた教訓#

1. 最終的なシステム構成#

lumineサービス群は、Proxmox上の軽量なLXCコンテナ内で、Docker Composeによって安定して稼働している。ストレージはホストからのバインドマウントで高速に共有され、ファイルディスクリプタの問題は完全に解消された。ネットワークはAdGuard HomeとTailscaleが協調して動作し、LAN内外から一貫したホスト名で各サービスにアクセス可能となっている。

2. 得られた教訓#

  1. VirtIO-FSの限界: VirtIO-FSは便利だが、Jellyfinのようにファイルシステム全体を高頻度でスキャンするワークロードには不向きである。リソース枯渇のボトルネックになり得る。
  2. LXCの優位性: Dockerホストのような用途では、VMよりもLXCの方がオーバーヘッドが少なく、パフォーマンス(特にI/O)上有利である。バインドマウントは非常に強力。
  3. 体系的なトラブルシューティングの重要性: lsofjournalctltcpdump → クエリ・ログと、レイヤーを追って順に調査することで、複雑な問題も最終的に原因を特定できる。憶測で修正せず、事実に基づいて行動すること。
  4. DNSは常に疑え: ネットワークの問題、特に「名前でアクセスできない」場合は、DNSのどのレイヤー(クライアントキャッシュ、ローカルDNS、Tailscale MagicDNS)で問題が起きているかを切り分けることが解決への近道である。

3. 残存タスク#

  • [済] 古いlumine-vmのバックアップ取得と削除。
  • [済] 不要になったsystemd設定の削除。
  • [済] 新しいlumine LXCの内部ホスト名をlumineに変更。
  • [要] 新しいlumine LXCの定期バックアップジョブをProxmoxで設定する。

以上で、本件に関するすべての作業を完了とする。

↑nano-banana製。かわいい。

封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00