ストレージの設定

LXD を使ってストレージプールやストレージボリュームを管理、作成できます。 一般的な(設定)キーはトップレベルです。ドライバー特有のキーはドライバー名で名前空間を作ります。 ボリュームのキーは、ボリューム単位で値を上書きしない限りは、プール内に作られたすべてのボリュームに適用されます。

ストレージプールの設定

Key Type Condition Default API Extension Description
size string appropriate driver and source 0 storage ストレージプールのサイズ。バイト単位(suffixも使えます)(現時点では loop ベースのプールと zfs で有効)
source string - - storage ブロックデバイス、loop ファイル、ファイルシステムエントリーのパス
btrfs.mount_options string btrfs driver user_subvol_rm_allowed storage_btrfs_mount_options ブロックデバイスのマウントオプション
ceph.cluster_name string ceph driver ceph storage_driver_ceph ストレージプールを作る対象の Ceph クラスタ名
ceph.osd.force_reuse bool ceph driver false storage_ceph_force_osd_reuse 他の LXD インスタンスが使用中の OSD ストレージプールを強制的に使う
ceph.osd.pg_num string ceph driver 32 storage_driver_ceph OSD ストレージプールの Placement group 数
ceph.osd.pool_name string ceph driver プール名 storage_driver_ceph OSD ストレージプール名
ceph.osd.data_pool_name string ceph driver - storage_driver_ceph OSD データプール名
ceph.rbd.clone_copy string ceph driver true storage_driver_ceph フルデータセットのコピーの代わりに RBD Lightweight Clone を使うかどうか
ceph.user.name string ceph driver admin storage_ceph_user_name ストレージプールやボリュームを作成する際に使用する Ceph ユーザー名
cephfs.cluster_name string cephfs driver ceph storage_driver_cephfs 新しいストレージプールを作成する ceph のクラスター名
cephfs.path string cephfs driver / storage_driver_cephfs CEPHFS をマウントするベースのパス
cephfs.user.name string cephfs driver admin storage_driver_cephfs ストレージプールとボリュームを作成する際に用いる ceph のユーザー
lvm.thinpool_name string lvm driver LXDThinPool storage イメージを作る Thin pool 名
lvm.use_thinpool bool lvm driver true storage_lvm_use_thinpool ストレージプールは論理ボリュームに Thinpool を使うかどうか
lvm.vg_name string lvm driver プール名 storage 作成するボリュームグループ名
lvm.vg.force_reuse bool lvm driver false storage_lvm_vg_force_reuse 既存の空でないボリュームグループの使用を強制
volume.lvm.stripes string lvm driver - storage_lvm_stripes 新しいボリューム (あるいは thin pool ボリューム) に使用するストライプ数
volume.lvm.stripes.size string lvm driver - storage_lvm_stripes 使用するストライプのサイズ (最低 4096 バイトで 512 バイトの倍数を指定)
rsync.bwlimit string - 0 (no limit) storage_rsync_bwlimit ストレージエンティティーの転送にrsyncを使う場合、I/Oソケットに設定する制限を指定
volatile.initial_source string - - storage_volatile_initial_source 作成時に与える実際のソースを記録 (e.g. /dev/sdb).
volatile.pool.pristine string - true storage_driver_ceph プールが作成時に空かどうか
volume.block.filesystem string block based driver (lvm) ext4 storage 新しいボリュームに使うファイルシステム
volume.block.mount_options string block based driver (lvm) discard storage ブロックデバイスのマウントポイント
volume.size string appropriate driver unlimited (ブロックデバイスは 10GB) storage デフォルトのボリュームサイズ
volume.zfs.remove_snapshots bool zfs driver false storage 必要に応じてスナップショットを削除するかどうか
volume.zfs.use_refquota bool zfs driver false storage 領域の quota の代わりに refquota を使うかどうか
zfs.clone_copy bool zfs driver true storage_zfs_clone_copy ZFS のフルデータセットコピーの代わりに軽量なクローンを使うかどうか
zfs.pool_name string zfs driver プール名 storage Zpool 名

ストレージプールの設定は lxc ツールを使って次のように設定できます:

lxc storage set [<remote>:]<pool> <key> <value>

ストレージボリュームの設定

Key Type Condition Default API Extension Description
size string appropriate driver volume.size と同じ storage ストレージボリュームのサイズ
block.filesystem string block based driver volume.block.filesystem と同じ storage ストレージボリュームのファイルシステム
block.mount_options string block based driver volume.block.mount_options と同じ storage ブロックデバイスのマウントオプション
security.shifted bool custom volume false storage_shifted shiftfs オーバーレイを使って id をシフトさせる(複数の隔離されたインスタンスからアタッチしたストレージで、インスタンスそれぞれで指定したidになるようにする)
security.unmapped bool custom volume false storage_unmapped ボリュームに対する ID マッピングを無効化する
lvm.stripes string lvm driver - storage_lvm_stripes 新しいボリューム (あるいは thin pool ボリューム) に使用するストライプ数
lvm.stripes.size string lvm driver - storage_lvm_stripes 使用するストライプのサイズ (最低 4096 バイトで 512 バイトの倍数を指定)
snapshots.expiry string custom volume - custom_volume_snapshot_expiry スナップショットがいつ削除されるかを制御する( 1M 2H 3d 4w 5m 6y のような式を受け付ける)
snapshots.schedule string custom volume - volume_snapshot_scheduling Cron の書式 (<minute> <hour> <dom> <month> <dow>)
snapshots.pattern string custom volume snap%d volume_snapshot_scheduling スナップショットの名前を表す Pongo2 のテンプレート文字列(スケジュールされたスナップショットと無名のスナップショットに使用される)
zfs.remove_snapshots string zfs driver volume.zfs.remove_snapshots と同じ storage 必要に応じてスナップショットを削除するかどうか
zfs.use_refquota string zfs driver volume.zfs.zfs_requota と同じ storage 領域の quota の代わりに refquota を使うかどうか

ストレージボリュームの設定は lxc ツールを使って次のように設定できます:

lxc storage volume set [<remote>:]<pool> <volume> <key> <value>

ストレージバックエンドとサポートされる機能

機能比較

LXD では、イメージ、インスタンス、カスタムボリューム用のストレージとして ZFS、btrfs、LVM、単なるディレクトリが使えます。 可能であれば、各システムの高度な機能を使って、LXD は操作を最適化しようとします。

機能 ディレクトリ Btrfs LVM ZFS CEPH
最適化されたイメージストレージ no yes yes yes yes
最適化されたインスタンスの作成 no yes yes yes yes
最適化されたスナップショットの作成 no yes yes yes yes
最適化されたイメージの転送 no yes no yes yes
最適化されたインスタンスの転送 no yes no yes yes
コピーオンライト no yes yes yes yes
ブロックデバイスベース no no yes no yes
インスタントクローン no yes yes yes yes
コンテナー内でストレージドライバの使用 yes yes no no no
古い(最新ではない)スナップショットからのリストア yes yes yes no yes
ストレージクオータ yes(*) yes no yes no

おすすめのセットアップ

LXD から使う場合のベストなオプションは ZFS と btrfs を使うことです。
このふたつは同様の機能を持ちますが、お使いのプラットフォームで使えるのであれば、ZFS のほうがより信頼性が上です。

可能であれば、LXD のストレージプールにディスクかパーティション全体を与えるのが良いでしょう。
LXD で loop ベースのストレージを作れますが、プロダクション環境ではおすすめしません。

同様に、ディレクトリバックエンドも最後の手段として考えるべきでしょう。
LXD の主な機能すべてが使えますが、インスタントコピーやスナップショットが使えないので、毎回インスタンスのストレージ全体をコピーする必要があり、恐ろしく遅くて役に立たないでしょう。

最適化されたイメージストレージ

ディレクトリ以外のすべてのバックエンドには、ある種の最適化されたイメージ格納フォーマットがあります。
これは、一からイメージの tarball を展開するのではなく、あらかじめ作られたイメージボリュームから単にクローンして、瞬間的にインスタンスを作るのに使われます。

そのイメージで使えないストレージプールの上にそのようなボリュームを準備することは無駄なので、ボリュームはオンデマンドで作成されます。
したがって、最初のインスタンスはあとで作るインスタンスよりは作成に時間がかかります。

最適化されたインスタンスの転送

ZFS、btrfs、Ceph RBD は内部で send/receive メカニズムを持っており、最適化されたボリュームの転送ができます。 LXD はこのような機能を使い、サーバ間でインスタンスやスナップショットを転送します。

ストレージドライバーがこのような機能をサポートしていない場合や、転送元と転送先のサーバのストレージバックエンドが違う場合で、このような機能が使えない場合は、
LXD は代わりに rsync を使った転送にフォールバックし、個々のファイルを転送します。

rsync を使う必要がある場合、LXD ではストレージプールのプロパティーである rsync.bwlimit を 0 以外の値に設定することで、ソケット I/O の流量の上限を設定できます。

デフォルトのストレージプール

LXD にはデフォルトののストレージプールの概念はありません。
代わりに、インスタンスのルートに使用するプールは、LXD 内で別の「ディスク」デバイスとして扱われます。

デバイスエントリーは次のようになります。

  root:
    type: disk
    path: /
    pool: default

この設定はインスタンスに直接指定できますし("-s"オプションを "lxc launch" と "lxc init" に与えて)、LXD プロファイル経由でも設定できます。

後者のオプションは、デフォルトの LXD セットアップ("lxd init" で実行します)が設定するものです。
同じことを次のように任意のプロファイルに対してマニュアルで実行できます:

lxc profile device add default root disk path=/ pool=default

I/O 制限

ストレージデバイスをインスタンスにアタッチする際に、IOPS や MB/s による I/O 制限を、ストレージデバイスに対して設定できます(詳しくは インスタンス をご覧ください)。

この制限は Linux の blkio cgroup コントローラーを使って適用します。ディスクレベルで I/O の制限ができます(それより粒度の細かい制限はできません)。

この制限は、パーティションやパスではなく、全物理ディスクに対して適用されるので、次のような制限があります:

  • 制限は仮想デバイス(例えば device mapper)によって実現しているファイルシステムには適用されません
  • 複数のブロックデバイス上に存在するファイルシステムの場合、それぞれのデバイスは同じ制限が適用されます
  • 同じディスク上に存在するふたつのディスクデバイスをインスタンスに与えた場合、ふたつのデバイスの制限は平均化されます

すべての I/O 制限は、実際のブロックデバイスにのみ適用されるので、制限を設定する際には、ファイルシステム自身のオーバーヘッドを考慮する必要があるでしょう。
このことは、キャッシュされたデータへのアクセスは、制限の影響を受けないことも意味します。

各ストレージバックエンドに対する注意と例

ディレクトリ

  • このバックエンドでは全ての機能を使えますが、他のバックエンドに比べて非常に時間がかかります。 これは、イメージを展開したり、インスタンスやスナップショットやイメージのその時点のコピーを作成する必要があるからです。
  • ファイルシステムレベルでプロジェクトクォータが有効に設定されている ext4 もしくは XFS で実行している場合は、ディレクトリバックエンドでクォータがサポートされます。

ディレクトリストレージプールを作成するコマンド

  • "pool1" という新しいディレクトリプールを作成します
lxc storage create pool1 dir
  • 既存のディレクトリ "pool2" を使います
lxc storage create pool2 dir source=/data/lxd

CEPH

  • イメージとして RBD イメージを使い、インスタンスやスナップショットを作成するためにスナップショットやクローンを実行します
  • RBD でコピーオンライトが動作するため、すべての子がなくなるまでは、親のファイルシステムは削除できません。 その結果、LXD は削除されたにもかかわらずまだ参照されているオブジェクトに、自動的に zombie_ というプレフィックスを付与します。 そして、参照されなくなるまでそれを保持します。そして安全に削除します
  • LXD は OSD ストレージプールを完全にコントロールできると仮定します。 LXD OSD ストレージプール内に、LXD が所有しないファイルシステムエンティティを維持し続けないことをおすすめします。 LXD がそれらを削除する可能性があるからです
  • 複数の LXD インスタンス間で、同じストレージプールを共有することはサポートしないことに注意してください。 lxd import を使って既存インスタンスをバックアップする目的のときのみ、OSD ストレージプールを複数の LXD インスタンスで共有できます。 このような場合には、ceph.osd.force_reuse プロパティを true に設定する必要があります。 設定しない場合、LXD は他の LXD インスタンスが OSD ストレージプールを使っていることを検出した場合には、OSD ストレージプールの再利用を拒否します
  • LXD が使う Ceph クラスターを設定するときは、OSD ストレージプールを保持するために使うストレージエンティティ用のファイルシステムとして xfs の使用をおすすめします。 ストレージエンティティ用のファイルシステムとして ext4 を使用することは、Ceph の開発元では推奨していません。 LXD と関係ない予期しない不規則な障害が発生するかもしれません

Ceph ストレージプールを作成するコマンド

  • Ceph クラスター "ceph" 内に "pool1" という OSD ストレージプールを作成する
lxc storage create pool1 ceph
  • Ceph クラスター "my-cluster" 内に "pool1" という OSD ストレージプールを作成する
lxc storage create pool1 ceph ceph.cluster\_name=my-cluster
  • ディスク上の名前を "my-osd" で "pool1" という名前の OSD ストレージプールを作成する
lxc storage create pool1 ceph ceph.osd.pool\_name=my-osd
  • 既存の OSD ストレージプール "my-already-existing-osd" を使用する
lxc storage create pool1 ceph source=my-already-existing-osd

CEPHFS

  • カスタムストレージボリュームにのみ利用可能
  • サーバサイドで許可されていればスナップショットもサポート

Btrfs

  • インスタンス、イメージ、スナップショットごとにサブボリュームを使い、新しいオブジェクトを作成する際に btrfs スナップショットを作成します
  • btrfs は、親コンテナー自身が btrfs 上に作成されているときには、コンテナー内のストレージバックエンドとして使えます(ネストコンテナー)(qgroup を使った btrfs クオータについての注意を参照してください)
  • btrfs では qgroup を使ったストレージクオータが使えます。btrfs qgroup は階層構造ですが、新しいサブボリュームは自動的には親のサブボリュームの qgroup には追加されません。 このことは、ユーザーが設定されたクオータをエスケープできるということです。 もし、クオータを厳格に遵守させたいときは、ユーザーはこのことに留意し、refquota を使った zfs ストレージを使うことを検討してください。  

Btrfs ストレージプールを作成するコマンド

  • "pool1" という名前の loop を使ったプールを作成する
lxc storage create pool1 btrfs
  • /some/path の既存の btrfs ファイルシステムを使って "pool1" という新しいプールを作成する。 <!-- Create a new pool called "pool1" using an existing btrfs filesystem at/some/path`. -->
lxc storage create pool1 btrfs source=/some/path
  • /dev/sdX 上に "pool1" という新しいプールを作成する
lxc storage create pool1 btrfs source=/dev/sdX

ループバックデバイスを使った btrfs プールの拡張

LXD では、ループバックデバイスの btrfs プールを直接は拡張できませんが、次のように拡張できます:

sudo truncate -s +5G /var/lib/lxd/disks/<POOL>.img
sudo losetup -c <LOOPDEV>
sudo btrfs filesystem resize max /var/lib/lxd/storage-pools/<POOL>/

(注意: snap のユーザーは /var/lib/lxd/ の代わりに /var/snap/lxd/common/lxd/ を使ってください)

LVM

  • イメージ用に LV を使うと、インスタンスとインスタンススナップショット用に LV のスナップショットを使います
  • LV で使われるファイルシステムは ext4 です(代わりに xfs を使うように設定できます)
  • デフォルトでは、すべての LVM ストレージプールは LVM thinpool を使います。すべての LXD ストレージエンティティ(イメージやインスタンスなど)のための論理ボリュームは、その LVM thinpool 内に作られます。 この動作は、lvm.use_thinpool を "false" に設定して変更できます。 この場合、LXD はインスタンススナップショットではないすべてのストレージエンティティ(イメージやインスタンスなど)に、通常の論理ボリュームを使います。 Thinpool 以外の論理ボリュームは、スナップショットのスナップショットをサポートしていないので、ほとんどのストレージ操作を rsync にフォールバックする必要があります。 これは、LVM ドライバがスピードとストレージ操作の両面で DIR ドライバに近づくため、必然的にパフォーマンスに重大な影響を与えることに注意してください。 このオプションは、必要な場合のみに選択してください。
  • 頻繁にインスタンスとのやりとりが発生する環境(例えば継続的インテグレーション)では、/etc/lvm/lvm.conf 内の retain_minretain_days を調整して、LXD とのやりとりが遅くならないようにすることが重要です。

LVM ストレージプールを作成するコマンド

  • "pool1" というループバックプールを作成する。LVM ボリュームグループの名前も "pool1" になります
lxc storage create pool1 lvm
  • "my-pool" という既存の LVM ボリュームグループを使う
lxc storage create pool1 lvm source=my-pool
  • ボリュームグループ "my-vg" 内の "my-pool" という既存の LVM thinpool を使う
lxc storage create pool1 lvm source=my-vg lvm.thinpool_name=my-pool
  • /dev/sdX に "pool1" という新しいプールを作成する。LVM ボリュームグループの名前も "pool1" になります
lxc storage create pool1 lvm source=/dev/sdX
  • LVM ボリュームグループ名を "my-pool" と名付け /dev/sdX を使って "pool1" というプールを新たに作成する
lxc storage create pool1 lvm source=/dev/sdX lvm.vg_name=my-pool

ZFS

  • LXD が ZFS プールを作成した場合は、デフォルトで圧縮が有効になります
  • イメージ用に ZFS を使うと、インスタンスとスナップショットの作成にスナップショットとクローンを使います
  • ZFS でコピーオンライトが動作するため、すべての子のファイルシステムがなくなるまで、親のファイルシステムを削除できません。 ですので、削除されたけれども、まだ参照されているオブジェクトを、LXD はランダムな deleted/ なパスに自動的にリネームし、参照がなくなりオブジェクトを安全に削除できるようになるまで、そのオブジェクトを保持します。
  • 現時点では、ZFS では、プールの一部をコンテナーユーザーに権限委譲できません。開発元では、この問題に積極的に取り組んでいます。
  • ZFS では最新のスナップショット以外からのリストアはできません。 しかし、古いスナップショットから新しいインスタンスを作成することはできます。 これにより、新しいスナップショットを削除する前に、スナップショットが確実にリストアしたいものかどうか確認できます。

また、インスタンスのコピーにスナップショットを使うので、インスタンスのコピーを削除することなく、最後のコピーの前に取得したスナップショットにインスタンスをリストアできないことにも注意が必要です。

必要なスナップショットを新しいインスタンスにコピーした後に古いインスタンスを削除できますが、インスタンスが持っているかもしれない他のスナップショットを失ってしまいます。

  • LXD は ZFS プールとデータセットがフルコントロールできると仮定していることに注意してください。 LXD の ZFS プールやデータセット内に LXD と関係ないファイルシステムエンティティを維持しないことをおすすめします。LXD がそれらを消してしまう恐れがあるからです。
  • ZFS データセットでクオータを使った場合、LXD は ZFS の "quota" プロパティを設定します。 LXD に "refquota" プロパティを設定させるには、与えられたデータセットに対して "zfs.use_refquota" を "true" に設定するか、 ストレージプール上で "volume.zfs.use_refquota" を "true" に設定するかします。 前者のオプションは、与えられたストレージプールだけに refquota を設定します。 後者のオプションは、ストレージプール内のストレージボリュームすべてに refquota を使うようにします。
  • I/O クオータ(IOps/MBs)は ZFS ファイルシステムにはあまり影響を及ぼさないでしょう。 これは、ZFS が(SPL を使った)Solaris モジュールの移植であり、 I/O に対する制限が適用される Linux の VFS API を使ったネイティブな Linux ファイルシステムではないからです。

ZFS ストレージプールを作成するコマンド

  • "pool1" というループバックプールを作成する。ZFS の Zpool 名も "pool1" となります
lxc storage create pool1 zfs
  • ZFS Zpool 名を "my-tank" とし、"pool1" というループバックプールを作成する
lxc storage create pool1 zfs zfs.pool\_name=my-tank
  • 既存の ZFS Zpool "my-tank" を使う
lxc storage create pool1 zfs source=my-tank
  • 既存の ZFS データセット "my-tank/slice" を使う
lxc storage create pool1 zfs source=my-tank/slice
  • /dev/sdX 上に "pool1" という新しいプールを作成する。ZFS Zpool 名も "pool1" となります
lxc storage create pool1 zfs source=/dev/sdX
  • /dev/sdX 上に "my-tank" という ZFS Zpool 名で新しいプールを作成する
lxc storage create pool1 zfs source=/dev/sdX zfs.pool_name=my-tank

ループバックの ZFS プールの拡張

LXD からは直接はループバックの ZFS プールを拡張できません。しかし、次のようにすればできます:

sudo truncate -s +5G /var/lib/lxd/disks/<POOL>.img
sudo zpool set autoexpand=on lxd
sudo zpool online -e lxd /var/lib/lxd/disks/<POOL>.img
sudo zpool set autoexpand=off lxd

(注意: snap のユーザーは /var/lib/lxd/ の代わりに /var/snap/lxd/common/lxd/ を使ってください)