Volumes

Volumes are the preferred mechanism for persisting data used by containers. While nullfs mounts are dependent on the directory structure of the host machine, volumes are managed by Kleene. Advantages of using volumes over nullfs mounts:

  • Volumes are easy to back up or migrate.
  • Volumes are stored within the Kleene root and can thus be managed together with the Kleene installation.
  • You can manage volumes using Klee.
  • New volumes can have their content pre-populated by a container.

Volumes are based on nullfs-mounts and can be seen as managed, but less flexible, version of nullfs mounts.

See the container create command for details on how to mount volumes with Klee.

When a volume is mounted into a container, a nullfs mount is created from the volume’s dataset into the target directory within the container.

Create and manage volumes

Unlike a nullfs mount, volumes can be created and managed by Kleene.

Create a volume:

$ klee volume create my-vol
my-vol

List volumes:

$ klee lsv
 VOLUME NAME   CREATED
─────────────────────────────
 my-vol        6 minutes ago

Inspect a volume:

$ klee volume inspect my-vol
{
  "mountpoints": [],
  "volume": {
    "created": "2024-02-29T14:54:05.317207Z",
    "dataset": "zroot/kleene/volumes/my-vol",
    "mountpoint": "/zroot/kleene/volumes/my-vol",
    "name": "my-vol"
  }
}

Note that the list of mountpoints is empty since the volume is not mounted it into any containers yet.

Remove a volume:

$ klee volume rm my-vol
my-vol

Prune volumes:

$ klee volume prune
WARNING! This will remove all unused volumes.
Are you sure you want to continue? [y/N]: y

Start a container with a volume

Starting a container with a volume that doesn’t yet exist, makes Klee create it automatically. The following example mounts the volume myvol2 into /app/ in the container.

$ klee run -d --name devtest --mount myvol2:/app FreBSD:latest

Use klee volume inspect myvol2 to verify that the volume was created and mounted correctly:

{
  "mountpoints": [
    {
      "container_id": "cc1ea0ff3f5a",
      "destination": "/app",
      "read_only": false,
      "source": "myvol2",
      "type": "volume"
    }
  ],
  "volume": {
    "created": "2024-02-29T15:07:02.291441Z",
    "dataset": "zroot/kleene/volumes/myvol2",
    "mountpoint": "/zroot/kleene/volumes/myvol2",
    "name": "myvol2"
  }
}

This shows the correct source and destination, and that the mount is read-write.

Stop the container and remove the volume.

$ klee container stop devtest
cc1ea0ff3f5a
$ klee container rm devtest
cc1ea0ff3f5a
$ klee volume rm myvol2
myvol2

Populate a volume using a container

If a container is created with a new or empty volume, and the target directory within the container such as /app/ is non-empty, the directory’s contents are copied into the volume (using cp -a) by Kleene. The container then mounts and uses the volume, and other containers which use the volume also have access to the pre-populated content.

To illustrate this, the following example starts an nginx container and populates the new volume nginx-vol with the contents of the container’s /usr/local/www/nginx directory. This is where Nginx stores its default HTML content.

The nginx image can be built like this:

$ cat Dockerfile
FROM FreeBSD:latest
RUN pkg install -y nginx
$ klee build -t nginx:latest .

Then run the nginx container using:

$ klee run --name nginxtest --mount nginx-vol:/usr/local/www/nginx nginx ls /usr/local/www/nginx
835b746a9e0d
created execution instance bd16b0b23a25
50x.html
EXAMPLE_DIRECTORY-DONT_ADD_OR_TOUCH_ANYTHING
index.html

executable bd16b0b23a25 and its container exited with exit-code 0

and verify that the files have appeared on the volume

$ ls /zroot/kleene/volumes/nginx-vol/
50x.html                                     EXAMPLE_DIRECTORY-DONT_ADD_OR_TOUCH_ANYTHING index.html

Then run the following commands to clean up both volume and container.

$ klee container rm nginxtest
835b746a9e0d
$ klee volume rm nginx-vol
nginx-vol

Use a read-only volume

For some development applications, the container only needs read access to the data. Multiple containers can mount the same volume, and it is possible to simultaneously mount a single volume as read-write for some containers and read-only for others.

The following example modifies the volume created above, but mounts the directory as a read-only volume, by adding :ro after the mount point.

$ klee run --name=nginxtest --mount nginx-vol:/usr/local/www/nginx:ro nginx:latest

Use klee container inspect nginxtest to verify that the read-only mount was created correctly. Look for the container_mountpoints section:

  "container_mountpoints": [
    {
      "container_id": "c0c874965b50",
      "destination": "/usr/local/www/nginx",
      "read_only": true,
      "source": "nginx-vol",
      "type": "volume"
    }
  ]

Stop and remove both container volume.

$ klee container stop nginxtest
$ klee container rm nginxtest
$ klee volume rm nginx-vol