ストレージの設定
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_min
とretain_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/
を使ってください)