運用しやすさを考えてLXDコンテナでまとめる

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


タイトルとURLをコピーしました