<a id="storage-lvm"></a>

# LVM - `lvm`


            <p class="youtube_link">
              <a href="https://www.youtube.com/watch?v=AqLl2eMZE6U" target="_blank">
                <span title="LVM storage and LXD" class="play_icon">▶</span>
                <span title="LVM storage and LXD">Watch on YouTube</span>
              </a>
            </p>
        
 is a storage management framework rather than a file system.
It is used to manage physical storage devices, allowing you to create a number of logical storage volumes that use and virtualize the underlying physical storage devices.

Note that it is possible to over-commit the physical storage in the process, to allow flexibility for scenarios where not all available storage is in use at the same time.

To use LVM, make sure you have `lvm2` installed on your machine.

## Terminology

LVM can combine several physical storage devices into a *volume group*.
You can then allocate *logical volumes* of different types from this volume group.

One supported volume type is a *thin pool*, which allows over-committing the resources by creating thinly provisioned volumes whose total allowed maximum size (quota) is larger than the available physical storage.
Another type is a *volume snapshot*, which captures a specific state of a logical volume.

## `lvm` driver in LXD

The `lvm` driver in LXD uses logical volumes for images, and volume snapshots for instances and snapshots.

LXD assumes that it has full control over the volume group.
Therefore, you should not maintain any file system entities that are not owned by LXD in an LVM volume group, because LXD might delete them.
However, if you need to reuse an existing volume group (for example, because your setup has only one volume group), you can do so by setting the [`lvm.vg.force_reuse`](#storage-lvm-pool-conf:lvm.vg.force_reuse) configuration.

By default, LVM storage pools use an LVM thin pool and create logical volumes for all LXD storage entities (images, instances and custom volumes) in there.
This behavior can be changed by setting [`lvm.use_thinpool`](#storage-lvm-pool-conf:lvm.use_thinpool) to `false` when you create the pool.
In this case, LXD uses “normal” logical volumes for all storage entities that are not snapshots.
Note that this entails serious performance and space reductions for the `lvm` driver (close to the `dir` driver both in speed and storage usage).
The reason for this is that most storage operations must fall back to using `rsync`, because logical volumes that are not thin pools do not support snapshots of snapshots.
In addition, non-thin snapshots take up much more storage space than thin snapshots, because they must reserve space for their maximum size (quota) at creation time.
Therefore, this option should only be chosen if the use case requires it.

For environments with a high instance turnover (for example, continuous integration) you should tweak the backup `retain_min` and `retain_days` settings in `/etc/lvm/lvm.conf` to avoid slowdowns when interacting with LXD.

## Configuration options

The following configuration options are available for storage pools that use the `lvm` driver and for storage volumes in these pools.

<a id="storage-lvm-pool-config"></a>

### Storage pool configuration

<!-- Include content from [../metadata.txt](../metadata.txt) -->

<a id="storage-lvm-pool-conf:lvm.thinpool_metadata_size"></a>
`lvm.thinpool_metadata_size`

The size of the thin pool metadata volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:lvm.thinpool_metadata_size)

| **Key:**     | `lvm.thinpool_metadata_size`   |
|--------------|--------------------------------|
| **Type:**    | string                         |
| **Default:** | `0` (auto)                     |
| **Scope:**   | global                         |

By default, LVM calculates an appropriate size.

<a id="storage-lvm-pool-conf:lvm.thinpool_name"></a>
`lvm.thinpool_name`

Thin pool where volumes are created

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:lvm.thinpool_name)

| **Key:**     | `lvm.thinpool_name`   |
|--------------|-----------------------|
| **Type:**    | string                |
| **Default:** | `LXDThinPool`         |
| **Scope:**   | local                 |

<a id="storage-lvm-pool-conf:lvm.use_thinpool"></a>
`lvm.use_thinpool`

Whether the storage pool uses a thin pool for logical volumes

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:lvm.use_thinpool)

| **Key:**     | `lvm.use_thinpool`   |
|--------------|----------------------|
| **Type:**    | bool                 |
| **Default:** | `true`               |
| **Scope:**   | global               |

<a id="storage-lvm-pool-conf:lvm.vg.force_reuse"></a>
`lvm.vg.force_reuse`

Force using an existing non-empty volume group

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:lvm.vg.force_reuse)

| **Key:**     | `lvm.vg.force_reuse`   |
|--------------|------------------------|
| **Type:**    | bool                   |
| **Default:** | `false`                |
| **Scope:**   | global                 |

<a id="storage-lvm-pool-conf:lvm.vg_name"></a>
`lvm.vg_name`

Name of the volume group to create

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:lvm.vg_name)

| **Key:**     | `lvm.vg_name`    |
|--------------|------------------|
| **Type:**    | string           |
| **Default:** | name of the pool |
| **Scope:**   | local            |

<a id="storage-lvm-pool-conf:rsync.bwlimit"></a>
`rsync.bwlimit`

Upper limit on the socket I/O for `rsync`

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:rsync.bwlimit)

| **Key:**     | `rsync.bwlimit`   |
|--------------|-------------------|
| **Type:**    | string            |
| **Default:** | `0` (no limit)    |
| **Scope:**   | global            |

When `rsync` must be used to transfer storage entities, this option specifies the upper limit
to be placed on the socket I/O.

<a id="storage-lvm-pool-conf:rsync.compression"></a>
`rsync.compression`

Whether to use compression while migrating storage pools

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:rsync.compression)

| **Key:**     | `rsync.compression`   |
|--------------|-----------------------|
| **Type:**    | bool                  |
| **Default:** | `true`                |
| **Scope:**   | global                |

<a id="storage-lvm-pool-conf:size"></a>
`size`

Size of the storage pool (for loop-based pools)

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:size)

| **Key:**     | `size`                                                |
|--------------|-------------------------------------------------------|
| **Type:**    | string                                                |
| **Default:** | auto (20% of free disk space, >= 5 GiB and <= 30 GiB) |
| **Scope:**   | local                                                 |

When creating loop-based pools, specify the size in bytes ([suffixes](https://canonical.com/lxd/docs/default/reference/instance_units/index.html.md#instances-limit-units) are supported).
You can increase the size to grow the storage pool.

The default (`auto`) creates a storage pool that uses 20% of the free disk space,
with a minimum of 5 GiB and a maximum of 30 GiB.

<a id="storage-lvm-pool-conf:source"></a>
`source`

Path to an existing block device, loop file, or LVM volume group

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:source)

| **Key:**    | `source`   |
|-------------|------------|
| **Type:**   | string     |
| **Scope:**  | local      |

<a id="storage-lvm-pool-conf:source.wipe"></a>
`source.wipe`

Whether to wipe the block device before creating the pool

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-pool-conf:source.wipe)

| **Key:**     | `source.wipe`   |
|--------------|-----------------|
| **Type:**    | bool            |
| **Default:** | `false`         |
| **Scope:**   | local           |

Set this option to `true` to wipe the block device specified in `source`
prior to creating the storage pool.

#### TIP
In addition to these configurations, you can also set default values for the storage volume configurations. See storage-configure-vol-default.

<a id="storage-lvm-vol-config"></a>

### Storage volume configuration

<!-- Include content from [../metadata.txt](../metadata.txt) -->

<a id="storage-lvm-volume-conf:block.filesystem"></a>
`block.filesystem`

File system of the storage volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:block.filesystem)

| **Key:**       | `block.filesystem`                                |
|----------------|---------------------------------------------------|
| **Type:**      | string                                            |
| **Default:**   | same as `volume.block.filesystem`                 |
| **Condition:** | block-based volume with content type `filesystem` |
| **Scope:**     | global                                            |

Valid options are: `btrfs`, `ext4`, `xfs`
If not set, `ext4` is assumed.

<a id="storage-lvm-volume-conf:block.mount_options"></a>
`block.mount_options`

Mount options for block-backed file system volumes

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:block.mount_options)

| **Key:**       | `block.mount_options`                             |
|----------------|---------------------------------------------------|
| **Type:**      | string                                            |
| **Default:**   | same as `volume.block.mount_options`              |
| **Condition:** | block-based volume with content type `filesystem` |
| **Scope:**     | global                                            |

<a id="storage-lvm-volume-conf:lvm.stripes"></a>
`lvm.stripes`

Number of stripes to use for new volumes (or thin pool volume)

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:lvm.stripes)

| **Key:**     | `lvm.stripes`                |
|--------------|------------------------------|
| **Type:**    | string                       |
| **Default:** | same as `volume.lvm.stripes` |
| **Scope:**   | global                       |

<a id="storage-lvm-volume-conf:lvm.stripes.size"></a>
`lvm.stripes.size`

Size of stripes to use

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:lvm.stripes.size)

| **Key:**     | `lvm.stripes.size`                |
|--------------|-----------------------------------|
| **Type:**    | string                            |
| **Default:** | same as `volume.lvm.stripes.size` |
| **Scope:**   | global                            |

The size must be at least 4096 bytes, and a multiple of 512 bytes.

<a id="storage-lvm-volume-conf:security.shared"></a>
`security.shared`

Enable volume sharing

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:security.shared)

| **Key:**       | `security.shared`                           |
|----------------|---------------------------------------------|
| **Type:**      | bool                                        |
| **Default:**   | same as `volume.security.shared` or `false` |
| **Condition:** | virtual-machine or custom block volume      |
| **Scope:**     | global                                      |

Enabling this option allows sharing the volume across multiple instances despite the possibility of data loss.

<a id="storage-lvm-volume-conf:security.shifted"></a>
`security.shifted`

Enable ID shifting overlay

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:security.shifted)

| **Key:**       | `security.shifted`                           |
|----------------|----------------------------------------------|
| **Type:**      | bool                                         |
| **Default:**   | same as `volume.security.shifted` or `false` |
| **Condition:** | custom volume                                |
| **Scope:**     | global                                       |

Enabling this option allows attaching the volume to multiple isolated instances.

<a id="storage-lvm-volume-conf:security.unmapped"></a>
`security.unmapped`

Disable ID mapping for the volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:security.unmapped)

| **Key:**       | `security.unmapped`                            |
|----------------|------------------------------------------------|
| **Type:**      | bool                                           |
| **Default:**   | same as `volume.security.unmappped` or `false` |
| **Condition:** | custom volume                                  |
| **Scope:**     | global                                         |

<a id="storage-lvm-volume-conf:size"></a>
`size`

Size/quota of the storage volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:size)

| **Key:**       | `size`                |
|----------------|-----------------------|
| **Type:**      | string                |
| **Default:**   | same as `volume.size` |
| **Condition:** | appropriate driver    |
| **Scope:**     | global                |

<a id="storage-lvm-volume-conf:snapshots.expiry"></a>
`snapshots.expiry`

When snapshots are to be deleted

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:snapshots.expiry)

| **Key:**       | `snapshots.expiry`                |
|----------------|-----------------------------------|
| **Type:**      | string                            |
| **Default:**   | same as `volume.snapshots.expiry` |
| **Condition:** | custom volume                     |
| **Scope:**     | global                            |

Specify an expression like `1M 2H 3d 4w 5m 6y`.

<a id="storage-lvm-volume-conf:snapshots.pattern"></a>
`snapshots.pattern`

Template for the snapshot name

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:snapshots.pattern)

| **Key:**       | `snapshots.pattern`                            |
|----------------|------------------------------------------------|
| **Type:**      | string                                         |
| **Default:**   | same as `volume.snapshots.pattern` or `snap%d` |
| **Condition:** | custom volume                                  |
| **Scope:**     | global                                         |

You can specify a naming template that is used for scheduled snapshots and unnamed snapshots.

The `snapshots.pattern` option takes a Pongo2 template string to format the snapshot name.

To add a time stamp to the snapshot name, use the Pongo2 context variable `creation_date`.
Make sure to format the date in your template string to avoid forbidden characters in the snapshot name.
For example, set `snapshots.pattern` to `{{ creation_date|date:'2006-01-02_15-04-05' }}` to name the snapshots after their time of creation, down to the precision of a second.

Another way to avoid name collisions is to use the placeholder `%d` in the pattern.
For the first snapshot, the placeholder is replaced with `0`.
For subsequent snapshots, the existing snapshot names are taken into account to find the highest number at the placeholder’s position.
This number is then incremented by one for the new name.

<a id="storage-lvm-volume-conf:snapshots.schedule"></a>
`snapshots.schedule`

Schedule for automatic volume snapshots

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:snapshots.schedule)

| **Key:**       | `snapshots.schedule`         |
|----------------|------------------------------|
| **Type:**      | string                       |
| **Default:**   | same as `snapshots.schedule` |
| **Condition:** | custom volume                |
| **Scope:**     | global                       |

Specify either a cron expression (`<minute> <hour> <dom> <month> <dow>`), a comma-separated list of schedule aliases (`@hourly`, `@daily`, `@midnight`, `@weekly`, `@monthly`, `@annually`, `@yearly`), or leave empty to disable automatic snapshots (the default).

<a id="storage-lvm-volume-conf:volatile.idmap.last"></a>
`volatile.idmap.last`

JSON-serialized UID/GID map that has been applied to the volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:volatile.idmap.last)

| **Key:**       | `volatile.idmap.last`   |
|----------------|-------------------------|
| **Type:**      | string                  |
| **Condition:** | filesystem              |

<a id="storage-lvm-volume-conf:volatile.idmap.next"></a>
`volatile.idmap.next`

JSON-serialized UID/GID map that has been applied to the volume

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:volatile.idmap.next)

| **Key:**       | `volatile.idmap.next`   |
|----------------|-------------------------|
| **Type:**      | string                  |
| **Condition:** | filesystem              |

<a id="storage-lvm-volume-conf:volatile.uuid"></a>
`volatile.uuid`

The volume’s UUID

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-volume-conf:volatile.uuid)

| **Key:**     | `volatile.uuid`   |
|--------------|-------------------|
| **Type:**    | string            |
| **Default:** | random UUID       |
| **Scope:**   | global            |

### Storage bucket configuration

To enable storage buckets for local storage pool drivers and allow applications to access the buckets via the S3 protocol, you must configure the [`core.storage_buckets_address`](https://canonical.com/lxd/docs/default/server/index.html.md#server-core:core.storage_buckets_address) server setting.

<!-- Include content from [../metadata.txt](../metadata.txt) -->

<a id="storage-lvm-bucket-conf:size"></a>
`size`

Size/quota of the storage bucket

[<i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i>](#storage-lvm-bucket-conf:size)

| **Key:**       | `size`                |
|----------------|-----------------------|
| **Type:**      | string                |
| **Default:**   | same as `volume.size` |
| **Condition:** | appropriate driver    |
| **Scope:**     | local                 |
