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(シンプルだが非推奨)
- スナップショットが遅く、容量効率も悪いためテスト用途向け。
dirとbtrfsの比較
LXDのストレージバックエンドとして「dir(ディレクトリ)」と「btrfs」を比較した場合、性能、機能、そして用途において明確な違いがあります。結論から言うと、単純なファイルアクセス性能は「dir」が上ですが、コンテナ管理機能と効率性を重視するなら「btrfs」が圧倒的に優れているそうです。
dir vs btrfs 比較まとめ
| 特徴 | dir (Directory) | btrfs |
|---|---|---|
| ファイルシステム | ホストのFS(ext4/xfs等)に直接保存 | btrfsボリューム上に構築 |
| コンテナ起動速度 | 普通 (コピーが発生) | 非常に速い (スナップショット) |
| スナップショット | 遅い (全ファイルコピー) | 一瞬 (高速・容量不要) |
| コンテナ作成 | 遅い (イメージから展開) | 一瞬 (クローン) |
| ストレージ効率 | 低い (コンテナごとの容量消費) | 高い (CoWによる重複排除) |
| 適した用途 | 軽量、テスト、単純な環境 | 本番運用、開発、バックアップ |
詳細比較
1. パフォーマンス(性能)
- dir (Directory): ホストOSのファイルシステム(通常はext4など)を直接使用します。オーバーヘッドが最も少なく、単純なファイル読み書き、ディスクI/Oにおいては、ストレージドライバーの中では最も高速な部類に入ります。
- btrfs: Copy-on-Write (CoW) 機能を持つため、ファイルを新しく書き込む際やスナップショット作成時のI/O負荷が低いです。しかし、非常に高負荷なランダム書き込みでは、dirやext4に比べてわずかに遅くなる場合があります。
2. 機能性と機能(スナップショット・イメージ)
- btrfs: LXDの「真の能力」を発揮できます。スナップショットが瞬時に作成でき、クローンも一瞬です。コンテナの作成、移行(マイグレーション)が圧倒的に速いため、開発・テスト環境、運用中のバックアップに最適です。
- dir: スナップショットの作成やコンテナのクローンは、物理的なファイルコピーを伴います。コンテナが増えるとディスク容量を大幅に消費し、作成速度も遅くなります。
3. ストレージ効率
- btrfs: 複数のコンテナがベースイメージを共有するため、合計のストレージ使用量を劇的に減らせます(重複排除機能)。
- dir: コンテナごとにOSイメージが展開されるため、コンテナの数だけストレージ容量が必要です。
用途別の推奨
- dir を使うべき場合
- コンテナの数やスナップショットの頻度が非常に少ない。
- 最強のディスクI/O性能が単一のコンテナで必要。
- btrfsやzfsの設定が面倒(単純なテスト用)。
- btrfs を使うべき場合
- コンテナを頻繁に作成・削除・スナップショットする(開発・ステージング環境)。
- ストレージ容量を節約したい。
- コンテナの起動速度を重視する。
LXDの機能(ライブマイグレーションや高速なスナップショット)をフルに活用したい場合、btrfs(またはZFS)を選択するのがよさそうです。
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
# UUIDを確認(デバイス名より安全、デバイス名がnvme0n1p3の場合)
sudo blkid /dev/nvme0n1p3
出てきたUUIDを使って /etc/fstab に追記。
sudo nano /etc/fstab
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/lxd-storage btrfs defaults 0 2
保存したら確認します。
# fstabのテスト(再起動不要で確認できる)
sudo mount -a
# マウントされたか確認
df -h | grep lxd-storage
リロードの表示が出ればリロード。これで完了です。
sudo systemctl daemon-reload
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のストレージプールとして、作成したサブボリュームを指定します。
マウント先のディレクトリを指定するためコマンドで作成します。ここではlxd-poolという名前で作成しています。
lxc storage create lxd-pool btrfs source=/mnt/lxd-storage/lxd-pool
続いて、プロファイルのRoot storageを作成してlxd-poolに変更します。

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


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 を対応させるという意味で、これによりコンテナ内からもエラーなく書き込めるはずです。


