Dockerで複数サービスを運用すると管理が煩雑になるため、LXDコンテナ上でDockerを動かして「軽量VM」的に管理する選択肢があります。ここでは「LXD内でDockerを動かす」場合と「ベアメタルでDockerを動かす」場合の比較、ストレージ選定、運用上の注意点、そしてLXD上での実際のストレージ準備・マウント手順を整理して記します。
LXD内Docker vs ベアメタルDocker
まずは、LXD内でDockerを動かす場合と、マシン上で直接Dockerを動かす場合について。
パフォーマンス
- CPU / メモリ:ほぼ同等(通常差は1〜5%)。LXDはホストカーネルを共有するためオーバーヘッドは小さい。
- ディスクI/O:影響を受けやすく、構成次第で5〜20%低下することがある。特に ZFS + overlay2 の組合せは遅くなる場合あり。bind mount や btrfs プールで改善可能。
- ネットワーク:ブリッジやNAT経由だと数%〜10%程度の遅延/スループット低下。–net=host 相当や macvlan で回避可能。
- 実測目安:軽負荷で 1〜3% 差、I/O/ネットワーク重視なら 5〜15%(最悪 20% 前後)。最高性能が必須ならベアメタル推奨。
管理性
- ベアメタル(メリット):最大性能、構成がシンプル、トラブルシュートが直感的。
デメリット:ホストが「汚れる」、複数環境の分離が面倒、ホスト障害で全サービスに影響。 - LXD内Docker(メリット):強い隔離(スナップショット・バックアップ・マイグレーションが容易)、リソース制限・複製が簡単、ホストをクリーンに保てる。
デメリット:設定項目が増える(例:security.nesting 等)、ストレージ相性問題、二層デバッグ、AppArmor/SELinux の落とし穴。
ディスク容量目安
Ubuntu 24.04 ベース・LXDコンテナ1つあたりの例です。
- Dockerインストールのみ(最小):1.2〜2.5 GB(目安:約1.5 GB)
- 軽いテストイメージを数個:2〜4 GB
- 実運用開始後:プロジェクトごとに 5〜20+ GB が普通
- 複数コンテナ(例:3つ)のクリーンスタート:合計 5〜8 GB
- 容量節約策:minimal イメージ、docker system prune、ボリュームをホストに bind mount、LXD の quota 設定
選択の目安
- ベアメタル推奨:最高性能が必要、環境が少数でシンプル、ホストを専用化できる場合。
- LXD内Docker推奨:複数の独立環境を運用したい、スナップショットや移行を多用する、ホストを汚したくない、小〜中規模運用。
容量に心配がなければ、LXD内で運用するほうがシンプルになりそうです。
なお、LXDで運用するにしても、ストレージに何を使用するかは注意が必要そうです。
ストレージバックエンドの違い
LXDのストレージドライバで容量効率がかなり変わります。特にDockerネスト時はここがネックになります。
- btrfs(推奨、Dockerとの相性良好)
- Copy-on-Write が効き、overlay2 と相性が良い。初期オーバーヘッドが小さく実使用量に近い。
- 推奨運用:LXDで別プールを作り Docker 用コンテナを配置する(例: lxc storage create dockerpool btrfs source=/mnt/…)。
- ZFS(LXDデフォルト)
- 安定性・堅牢性が高いが、overlay2 との相性で非効率になることがある。スナップショットやコピーで容量増になる報告あり。Docker 側の storage driver を zfs にする運用も検討可。
- dir(シンプルだが非推奨)
- スナップショットが遅く、容量効率も悪いためテスト用途向け。
ZFS と Btrfs の使い分け
簡単に言えば、それぞれ次のようになりそうですね。個人用途であれば、即時スナップショット、コンテナ別クォータ、透過圧縮などの高度機能が使えるなど、Btrfsのメリットが多そうです。ただ、Btrfsを利用する場合も、注意が必要そうです。
- Btrfs が向く場面:単一SSDノート/小型サーバー、既存 EXT4 環境への導入、容量のオンライン拡張/縮小、軽量運用、Docker と LXD を同一FSで扱いたい場合。
- ZFS が向く場面:高信頼性優先の本番、RAID5/6 を使う大容量運用、高い IOPS 安定性が必要な場合。
- 注意:Btrfs は RAID5/6 の安定性や CoW による断片化に注意。可能ならホスト上の実パーティションで運用する。
ループバックファイル vs 専用パーティション
- ループバック(利点):追加ディスク不要、手早く導入・削除可能 → テスト向け。
欠点:ホストFS越しのI/Oで性能低下、断片化、サイズ縮小が難しい。 - 専用パーティション(利点):性能・信頼性が高い → 本番向け。
- 推奨:本番/長期運用や高負荷なら専用パーティション。短期テストやディスクが無い場合はループバック可。
LXDでbtrfsを使う場合の注意点
- ホストが btrfs でない場合、ループバックでの運用になり性能低下する可能性がある。
- 既存プールの source(デバイス)は UI から後で変更できないなどの制約がある。
- Dockerネスト時は overlay2 等のストレージドライバとの相性を事前に確認する。
ファイルシステムを何にするにしても、専用パーティションにしたほうが良さそうですね。
実践:専用Btrfsパーティションを作成してLXDに登録する手順
注意:ルートパーティションの縮小をライブで行う場合はライブUSBから作業してください。以降のコマンドは例であり、環境に応じてデバイス名やパスを置き換えてください。
1) パーティション操作(例: gparted)
- 既存パーティションを縮小して空き領域を作る。
- 空き領域に新規パーティションを作成、ファイルシステムは btrfs、ラベル例: lxd-btrfs。
- 変更を適用。
2) マウントポイントを作成
自動マウントではなく、システム起動時に必ず同じ場所にマウントされるようにします。ここではnvme0n1p3デバイスの例。
# マウントポイントを作成
sudo mkdir -p /mnt/lxd-storage
# いったんアンマウントして、固定場所にマウントし直す
sudo umount /run/media/user/btrfs
sudo mount /dev/nvme0n1p3 /mnt/lxd-storage
3) サブボリューム作成(btrfs-progs が必要)
LXDコンテナ内にマウントするポイントとして、単なるフォルダ(mkdir)ではなく、Btrfsの機能(スナップショット等)を個別に使える「サブボリューム」として作成します。まず、btrfs-progsをインストールします。
sudo apt update
sudo apt install -y btrfs-progs
# LXDのプール用(コンテナのOS等)
sudo btrfs subvolume create /mnt/lxd-storage/lxd-pool
# LXD内Dockerなどのデータ用(ホストからも見える場所)
sudo btrfs subvolume create /mnt/lxd-storage/lxd-data
4) LXDへデフォルトプールとして登録
LXDのストレージプールとして、作成したサブボリュームを指定します。

デフォルトプールに指定しておけば、今後も自動でこのプールが使われるので良いでしょう。

5) データ用ディレクトリもマウント
データ用ディレクトリも追加します。こちらもデフォルトプロファイルに登録しておくと、今後コンテナを作成するたびに作業しなくて済むので楽です。
「Mount host path」を選択し、それぞれ次のように指定します。
/mnt/lxd-storage/lxd-data
/opt/lxd-data


コンテナ(インスタンス)を作成します。作成したBtrfsが利用されているのを確認しましょう。
コンテナが起動したら、マウントするディレクトリを作成します。
ちなみに、Dockerを利用するならNestingをAllowにします。

6) コンテナを作成して起動
コンテナを作成して起動します。コンテナが起動したら、コンソールで作業しても良いですが、コンテナ内に入って作業するほうが楽でしょう。
lxc exec コンテナ名 -- bash
マウントしてディレクトリが見えているか確認してみましょう。
cd /opt
ls
ただ、現時点ではlxd-data内へ書き込みしようとするとエラーになります。
7) パーミッションと ID マッピング
コンテナ内のDocker(root)が書き込めるように、ホスト側のディレクトリの所有権を設定します。
これにはいくつか方法がありますが、手軽で安全なのは、コンテナの設定でIDマッピングを許可することです。通常、非特権 LXD コンテナでは、
- コンテナ内 uid=0(root) → ホスト uid=100000
- コンテナ内 uid=1000 → ホスト uid=101000
というように 10 万番台へ変換されて動きます。
このため、ホストの /opt/lxd-data の owner を 1000:1000 にしても、
コンテナ内のユーザー(uid=1000) は 101000 として扱われるので書き込みエラーが発生します。
書き込みを許可するには raw.idmap を使ってホストとコンテナの UID/GID を直接対応させます。
例(コンテナ内 uid=1000 をホストの uid=1000 にマップ)
lxc config set <コンテナ名> raw.idmap "both 1000 1000"
lxc restart <コンテナ名>
sudo chown 1000:1000 /mnt/lxd-storage/lxd-data
「both 1000 1000」は、コンテナ→ホスト、ホスト→コンテナの両方向で UID/GID 1000 を対応させるという意味で、これによりコンテナ内からもエラーなく書き込めるはずです。

