Datasets
Every container resides in its own ZFS dataset, where its root file system
is stored. Name of that dataset can be obtained using osctl ct ls
:
osctl ct ls -o dataset,rootfs myct01
DATASET ROOTFS
tank/ct/myct01 /tank/ct/myct01/private
Notice that ROOTFS
is not directly in the dataset's mountpoint, i.e.
/tank/ct/myct01
. This is to ensure that the container does not have access
to the .zfs
special directory, which could be used to manipulate snapshots
from within the container.
Subdatasets
osctld also supports subdatasets, which can be used to logically divide data or provide specific configuration of ZFS properties. Subdatasets can be created using the zfs command-line utility, but you'd have to mount them manually, What's worse, osctld wouldn't be able to ensure that your mounts would work after container export/import or send to another vpsAdminOS node, which may have different pool paths. This is the reason why osctl has commands for manipulating container subdatasets.
Container's datasets can be listed with osctl ct dataset ls
:
osctl ct dataset ls myct01
NAME DATASET
/ tank/ct/myct01
NAME
is relative to the container's dataset, and in case of the container's
root dataset, it is /
. DATASET
is the dataset's full name, as ZFS knows it.
Let's create a subdataset:
osctl ct dataset new myct01 srv/data
osctl ct dataset ls myct01
NAME DATASET
/ tank/ct/myct01
srv tank/ct/myct01/srv
srv/data tank/ct/myct01/srv/data
As you can see, you can create nested subdatasets, all non-existing parents will
be created, i.e. in this case srv
and then srv/data
. The datasets were also
automatically mounted into the container:
osctl ct mount ls myct01
FS DATASET MOUNTPOINT TYPE OPTS
/tank/ct/myct01/srv/private srv /srv bind bind,rw,create=dir
/tank/ct/myct01/srv/data/private srv/data /srv/data bind bind,rw,create=dir
osctld is tracking the mount-dataset relation, so that when you remove a dataset,
corresponding mounts are either unmounted, or the removal fails. Datasets are
automatically mounted under their parent dataset's mountpoint. For example,
the parent of srv
is /
, so srv
will be mounted to /srv
. srv
is the
parent of srv/data
, which means that srv/data
will be mounted to /srv/data
.
The target mountpoint can be overriden using an optional argument:
osctl ct dataset new myct01 srv/www /var/www
osctl ct mount ls myct01
FS DATASET MOUNTPOINT TYPE OPTS
/tank/ct/myct01/srv/private srv /srv bind bind,rw,create=dir
/tank/ct/myct01/srv/data/private srv/data /srv/data bind bind,rw,create=dir
/tank/ct/myct01/srv/www/private srv/www /var/www bind bind,rw,create=dir
Subdatasets are automatically shifted into the container's user namespace:
zfs list -r -oname,uidmap,gidmap tank/ct/myct01
NAME UIDMAP GIDMAP
tank/ct/myct01 0:666000:65536 0:666000:65536
tank/ct/myct01/srv 0:666000:65536 0:666000:65536
tank/ct/myct01/srv/data 0:666000:65536 0:666000:65536
tank/ct/myct01/srv/www 0:666000:65536 0:666000:65536
All container's subdatasets are considered an integral part of the container, i.e. they are exported or sent together with the container. For this reason, it is not recommended to cross-mount subdatasets of one container to another container, as you would have to maintain that dependency on your own.
Using ZFS
Subdatasets can be created directly using ZFS, but they won't be automatically mounted into the container:
# Create the dataset
zfs create tank/ct/myct01/custom
# osctld will see it immediately
osctl ct dataset ls myct01
NAME DATASET
/ tank/ct/myct01
custom tank/ct/myct01/custom
srv tank/ct/myct01/srv
srv/data tank/ct/myct01/srv/data
srv/www tank/ct/myct01/srv/www
# No mountpoint is created
osctl ct mount ls myct01
FS DATASET MOUNTPOINT TYPE OPTS
/tank/ct/myct01/srv/private srv /srv bind bind,rw,create=dir
/tank/ct/myct01/srv/data/private srv/data /srv/data bind bind,rw,create=dir
/tank/ct/myct01/srv/www/private srv/www /var/www bind bind,rw,create=dir
# Because uidmap/gidmap properties are inherited, the subdataset is shifted
# into the container's user namespace
zfs list -r -oname,uidmap,gidmap tank/ct/myct01
NAME UIDMAP GIDMAP
tank/ct/myct01 0:666000:65536 0:666000:65536
tank/ct/myct01/custom 0:666000:65536 0:666000:65536
tank/ct/myct01/srv 0:666000:65536 0:666000:65536
tank/ct/myct01/srv/data 0:666000:65536 0:666000:65536
tank/ct/myct01/srv/www 0:666000:65536 0:666000:65536
Mounting datasets
Subdatasets can be mounted at any time using osctl ct mount dataset
. While they
could also be mounted using osctl ct mount new
, they wouldn't be tracked
as a subdataset mount, which could prevent successful container export/import
or send, as mentioned above.
osctl ct mount dataset myct01 custom /mnt/custom
osctl ct mount ls myct01
FS DATASET MOUNTPOINT TYPE OPTS
/tank/ct/myct01/srv/private srv /srv bind bind,rw,create=dir
/tank/ct/myct01/srv/data/private srv/data /srv/data bind bind,rw,create=dir
/tank/ct/myct01/srv/www/private srv/www /var/www bind bind,rw,create=dir
/tank/ct/myct01/custom/private custom /mnt/custom bind bind,rw,create=dir
Notice that when interacting with osctl, you always use the dataset's relative name to the container's root dataset, not its full name.
Removing subdatasets
The root dataset cannot be deleted while the container exists, but subdatasets
can be deleted using osctl ct dataset del
. It essentially calls zfs destroy
,
but first it checks that the dataset is not mounted, or that the mounts can
be unmounted. Without any options, a mounted dataset cannot be deleted:
osctl ct dataset del myct01 custom
error: the following mountpoints need to be unmounted:
/mnt/custom
Using option -u
, --unmount
, all relevant mounts are unmounted:
osctl ct dataset del --unmount myct01 custom
Another safe-check is that by default, a dataset cannot be deleted, if it has children:
osctl ct dataset del myct01 srv
error: dataset has children, recursive delete has to be enabled explicitly
Option -r
, --recursive
can be used to delete the dataset with all its
children, exactly like zfs destroy -r
does:
osctl ct dataset del -r myct01 srv
error: the following mountpoints need to be unmounted:
/var/www
/srv/data
/srv
Except the datasets are still mounted, so add --unmount
as well:
osctl ct dataset del --recursive --unmount myct01 srv