Setup a ZFS pool for your LXC containers with LXD

Setup a ZFS pool for your LXC containers with LXD

There are different storage types for LXC containers, from a basic storage directory to LVM volumes and more complex file systems like Ceph, Btrfs, or ZFS.

In this post, we're gonna setup a ZFS pool for our LXC containers, via LXD.

Why ZFS?#

ZFS is an awesome file system. It's a 128 bits file system meaning that we can store a nearly unlimited amount of data (no one will never attain its limit). It replaces RAID arrays by much simpler, safer and faster "pools", and had very good performance by using compression, copy-on-write, dynamic block size, dynamic stripping, and an extensive use of RAM cache.
The latter means it uses quite an amount of RAM, so I don't recommend to use it on small devices.

See this page for for details on these features.

Install ZFS#

On Ubuntu#

ZFS should be installed by default on Ubuntu Server. If it's not the case, install the zfsutils-linux package:

apt install zfsutils-linux

On Debian#

ZFS is available trough the contrib repository on Debian.

For Stretch, make sure you have contrib on for the main repo in /etc/apt/sources.list, e.g.:

deb http://deb.debian.org/debian stretch main contrib

For Jessie, it's available in the contrib backports:

deb http://deb.debian.org/debian jessie-backports main contrib

First, install the kernel headers. They will allow us to compile and install kernel modules.

apt install linux-headers-$(uname -r)

Then install ZFS and its DKMS module:

apt install zfs-dkms zfsutils-linux

The installation can take quite some time because it will build the ZFS kernel module, with DKMS.

When it's done, you will need to load the module:

modprobe zfs

By default you will have to do this after each reboot. To load the module automatically, add it to /etc/modules :

echo "zfs" >> /etc/modules

You should reboot to make sure all the ZFS services are running.

Setup the ZFS pool with LXD#

Creating and using a ZFS pool with LXD is super easy. Just run the lxd init command and choose to configure a new storage pool.

root@host:~# lxd init
Do you want to configure a new storage pool (yes/no) [default=yes]?
Name of the new storage pool [default=default]: zfs_lxd
Name of the storage backend to use (dir, btrfs, ceph, lvm, zfs) [default=zfs]:
Create a new ZFS pool (yes/no) [default=yes]?
Would you like to use an existing block device (yes/no) [default=no]?
Size in GB of the new loop device (1GB minimum) [default=15GB]: 20

If it's your first time running lxd init, you may want to setup a network bridge afterwards. Otherwise, just skip it:

Would you like to create a new network bridge (yes/no) [default=yes]? n
LXD has been successfully configured.

Use a pool on a real device#

Note that by default it will create a loop device for you ZFS pool, which means we're using ZFS over our existing filesystem.
This works, but it is not ideal so you may want to create a pool on a partition, a whole disk, or even mulitple disks.

To do that, select yes for Would you like to use an existing block device during lxd-init. You may then write the name of your drive (/dev/sdX) or partition (/dev/sdaX). This will erase data on the selected device

You can also create the pool manually with this command:

zpool create zpool_name /dev/sdX

Then select it:

root@root:~# lxd init
Do you want to configure a new storage pool (yes/no) [default=yes]?
Name of the new storage pool [default=default]: lxd_zfs
Name of the storage backend to use (dir, btrfs, ceph, lvm, zfs) [default=zfs]:
Create a new ZFS pool (yes/no) [default=yes]? n
Name of the existing ZFS pool or dataset: zpool_name

Using the ZFS pool#

To check our newly created pool, run:

root@host:~# zpool list
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
zfs_lxd 19.9G 267K 19.9G - 0% 0% 1.00x ONLINE -

You can also use:

root@host:~# zpool status
  pool: zfs_lxd
 state: ONLINE
  scan: none requested
config:

        NAME STATE READ WRITE CKSUM
        zfs_lxd ONLINE 0 0 0
          /var/snap/lxd/common/lxd/disks/zfs_lxd.img ONLINE 0 0 0

errors: No known data errors

Here, the whole ZFS filesystem is stored in /var/snap/lxd/common/lxd/disks/zfs_lxd.img. If you're running the pool on a drive, it'll look like this:

root@host:~# zpool status
  pool: zfs_lxd
 state: ONLINE
  scan: none requested
config:

        NAME STATE READ WRITE CKSUM
        zfs_lxd ONLINE 0 0 0
          sdb ONLINE 0 0 0

errors: No known data errors

The default profile is set automatically by lxd-init to use the ZFS pool:

root@host:~# lxc profile show default
config: {}
description: Default LXD profile
devices:
  eth0:
    nictype: bridged
    parent: lxdbr0
    type: nic
  root:
    path: /
    pool: zfs_lxd
    type: disk
name: default

We can test it by creating a new CT:

root@host:~# lxc launch images:debian/9 c1
Creating c1
Starting c1

We can see it uses some space in our pool:

root@host:~# zpool list
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
zfs_lxd 19.9G 174M 19.7G - 0% 0% 1.00x ONLINE -

Experience the magic of COW. 🐄

root@host:~# lxc launch images:debian/9 c2
Creating c2
Starting c2
root@host:~# zpool list
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
zfs_lxd 19.9G 176M 19.7G - 0% 0% 1.00x ONLINE -

Awesome, isn't it?

Enjoy#

You now have a high-performance ZFS pool for you LXC containers. ZFS has a lot of features that I didn't use here as this is supposed to be more like a quick start guide for LXD + ZFS, but just using the defaults gives a lot of benefits!

Sources:

Stanislas
Author
Stanislas
I like building things with code and computers

Comments

9Atom feed
Markdown supported
  1. Anonymous

    How to add a second disk as a mirror. If I create the Mirror first 'zpool create mirror vmdata /dev/sdb /dev/sdc' will LXD init recognize it ? Using LXD as Snap in Ubuntu 18.04 . Seems impossible to remove LXD or refresh .

    1. Anonymous

      Okay answered my own questions. Rebooted this morning. Deleted the Zpool and this time Snap LXD remove worked version 3.9 might have solved this. Created zpool mirror and lxd init reflects the mirror . Now just have to figure out what images are deleted after 10 days means.

  2. Anonymous

    So, I just deployed for the first time ever, Ubuntu 18.04 with its Root File System on top of ZFS! Via MaaS! Very cool! However, there is a big "rpool" consuming my whole disk and I want to use LXD with ZFS but, how? I can't just point lxd init to rpool, the following error appeared: "Error: Failed to create storage pool 'containers': Provided ZFS pool (or dataset) isn't empty". So, no idea about how to use LXD with ZFS when it's the root file system and it's consuming everything.

    I thought that it would be similar with root file system on btrfs, single partition whole disk, where LXD can create subvolumes and use btrfs normally.

    I was planning to make the move to ZFS because it's also good for QCoW2, where btrfs fails, but, no good deal yet.

  3. Jesús Ángel

    Hello,

    Do you know if it's possible to access from the host to the containers' files when using a ZFS storage backend?

    I run a backup agent in the host and I want to backup up the containers' data.

    Thank you for the tutorial.

    Kind regards,

    1. Jesús Ángel

      Hi @angristan,

      Thank you for your answer but excuse me, I can't figure how to access the containers' data from the host. I have the default LXD ZFS pool created in a dedicated partition, but I can't see the data from the host. I have read the doc about the canmount property, but still don't know how can I mount the filesystem in the host OS to access its data.

      zpool list

      NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT default 49,2G 493M 48,8G - - 0% 0% 1.00x ONLINE -

      lxc profile list

      | NAME | USED BY |

      | default | 2 |

      lxc list

      | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |

      c1 | RUNNING | 10.196.237.140 (eth0) | | PERSISTENT | 0 |

      c2 | RUNNING | 10.196.237.223 (eth0) | | PERSISTENT | 0 |

    2. Jesús Ángel

      Hi again,

      I've figured out how to mount the filesystems. The command "zfs list" displays all file systems and volumes:

      NAME USED AVAIL REFER MOUNTPOINT default 493M 47,2G 24K none default/containers 193M 47,2G 24K none default/containers/c1 79,8M 47,2G 187M /var/snap/lxd/common/lxd/storage-pools/default/containers/c1 default/containers/c2 113M 47,2G 220M /var/snap/lxd/common/lxd/storage-pools/default/containers/c2

      So in order to mount the container filesystems in the mount point aforementioned you just have to write: zfs mount default/containers/c1 zfs mount default/containers/c2

  4. Simon

    sudo lxc profile show default gives me:

    config: {} description: Default LXD profile devices: eth0: name: eth0 network: lxdbr0 type: nic root: path: / pool: default type: disk name: default used_by:

    • /1.0/instances/iobroker
    • /1.0/instances/iobroker2
    • /1.0/instances/asterisk
    • /1.0/instances/reverse-proxy
    • /1.0/instances/nextcloud
    • /1.0/instances/OpenHAB

    So the pool is called default. But

    zpool list says: NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT bpool 1,88G 1,05G 840M - - 5% 56% 1.00x DEGRADED - rpool 920G 662G 258G - - 12% 71% 1.00x DEGRADED -

    So here I have only bpool and rpool. Where can I find the pool fromt the lxd config (called default?)