Nullfs mounts

When using a nullfs mount, a file or directory on the host machine is mounted into a container. By contrast, when using a volume, a new directory is created within Kleene’s root dataset on the host, and Kleene manages that directory’s contents.

See the container create command for details on how to specify nullfs mounts with Klee.

Nullfs mounts allow access to sensitive files

One side effect of using nullfs mounts, for better or for worse, is that the host filesystem can be changed via processes running in a container, including creating, modifying, or deleting important system files or directories. This is a powerful ability which can have security implications, and potentially impacting non-Kleene processes on the host system.

Good use cases for nullfs mounts

In general, you should use volumes where possible. Nullfs mounts are appropriate for the following types of use case:

  • Sharing content used in development within a container. See the Get started guide for an example of this.

  • Having storage that is not based on ZFS, such as NFS-mounts, that needs to be accessible in a container.

Start a container with a nullfs mount

Consider a case with a directory source that contains source code, which, when compiled, produce artifacts saved into the subdirectory source/target/. The artifacts should be available within a container at /app/, and always be up to date with the newest build, everytime it is produced on the host. Use the following command to nullfs-mount the source/target/ directory into a container at /app/ (run the command from within the source directory). The $(pwd) sub-command expands to the current working directory, i.e., source.

$ klee run --name devtest --mount "$(pwd)"/target:/app nginx:latest

Use klee container inspect devtest to verify that the nullfs mount was created correctly. Look for the container_mountpoints section:

  "container_mountpoints": [
    {
      "container_id": "952441c02655",
      "destination": "/app",
      "read_only": false,
      "source": "/tmp/source/target",
      "type": "nullfs"
    }
  ]

This shows that the mount is of type nullfs, and it shows the correct source and destination.

Stop and remove the container:

$ klee rmc -f devtest

Mount into a non-empty directory on the container

If a directory is nullfs-mounted into a non-empty directory on the container, the directory’s existing contents are hidden by the nullfs mount. This can be beneficial when testing a new version of an application without building a new image, as illustrated in the Get started guide. However, it can also be confusing to keep track of the state of files within the target directory.

This example is contrived to the extreme, but replacing the contents of the container’s /etc/ directory with the /tmp/ directory on the host machine will, in most cases, result in a non-functioning container.

$ klee run --name broken-container --mount /tmp:/etc nginx:latest
217b19d8b21e
created execution instance 27b977efaa46
jail: getpwnam root: No such file or directory
jail: /usr/bin/env IGNORE_OSVERSION=yes /bin/sh /etc/rc: failed

executable 27b977efaa46 and its container exited with exit-code 1

The container is created but did not start. Remove it afterwards:

$ klee rmc broken-container

Use a read-only nullfs mount

For some development applications, the container only needs read access.

By modifying the previous example, the source directory is mounted as a read-only by adding :ro after the mount point.

$ klee run --name devtest --mount $(pwd)/target:/app:ro nginx:latest

Use klee container inspect devtest to verify that the nullfs mount was created correctly. Look for the container_mountpoints section:

"container_mountpoints": [
  {
    "container_id": "1459b8c75028",
    "destination": "/app",
    "read_only": true,
    "source": "/tmp/source/target",
    "type": "nullfs"
  }
]

Stop and remove the container:

$ klee rmc -f devtest