7. Firecracker Volumes
Hint
Abstract
This chapter explains how a local host path is made available inside of a Firecracker VM application, which commands create and delete that setup and how the result looks in the flake configuration.
A Firecracker VM has no way to share a directory with the host
directly, unlike a container it does not use the host kernel and
therefore cannot bind mount a host path into the guest. flake-pilot
bridges this gap with NFS: a local path is exported by the host and
mounted by the guest over the private network described in
Firecracker Networking. The setup is created and deleted with
the flake-ctl firecracker volume commands, no manual NFS
configuration is needed.
The setup works within the following requirements:
The application has to be connected to the host network with
flake-ctl firecracker network add, see Firecracker Networking. The volume setup reads the gateway address from that network setup.The guest needs a working network setup at boot and has to provide the NFS client tools, in particular the
mount.nfshelper program.
Managing volumes is a two step process: a local path is exported through NFS once, independently of any application. It is then added to one or more flake instances which mount it at a path of their choice.
7.1. Export a Local Path
flake-ctl firecracker volume export --path /some/local/path
Writes a flake-pilot managed entry for the given path to
/etc/exports, restricted to the private firecracker network
172.16.0.0/24. If the nfs-server systemd service is not
running yet it is started, otherwise the export table is reloaded so
the new export becomes effective right away.
The command expects an existing directory. As it changes a system
wide NFS configuration, the required privileged operations are
executed through sudo when needed. Exporting the same path again
keeps the existing entry unchanged.
7.2. Release a Local Path
flake-ctl firecracker volume release --path /some/local/path
Removes the flake-pilot managed NFS export entry for the given
path from /etc/exports and restarts the nfs-server service so
the updated export table becomes effective. Only entries previously
managed by flake-pilot are touched, an export created by other
means is left in place.
Note
Releasing a path does not check whether it is still in use by a flake. Remove it from every flake it was added to first, see below, before releasing the export.
7.3. Add a Volume to an Application
flake-ctl firecracker volume add \
--app $HOME/bin/claude --volume /some/local/path:/some/guest/path
Looks up the flake configuration of the application from its path and
writes an nfs= boot option to it in the form:
nfs=172.16.0.1:/some/local/path:/some/guest/path
The server part of the option is not configurable, it is the gateway
address of the private network the application is connected to,
172.16.0.1, read from the rd.route= boot option written by
flake-ctl firecracker network add. This is why the network setup
has to exist before a volume can be added.
The --volume option can be given more than once to add several
volumes in one call:
flake-ctl firecracker volume add --app $HOME/bin/claude \
--volume /some/local/path:/some/guest/path \
--volume /other/local/path:/other/guest/path
As every instance needs its own volume setup if it should differ from
the application, the command can be called with --instance as
well:
flake-ctl firecracker volume add --app $HOME/bin/claude \
--volume /some/local/path:/some/guest/path --instance @id1
The volume(s) of an instance take the place of the volumes configured
for the application itself, they are not merged. Calling the
application without the @id1 selector still mounts the volumes
configured globally, if any.
A volume is identified by its guest path: adding a volume with a guest path that is already configured replaces the entry, e.g to point it at a different local path or, after the path was exported again, a different server.
Note
The command only changes the flake configuration of the application, no privileged operations are required. The local path itself still has to be exported, see above, or the mount inside of the guest fails.
7.4. Remove a Volume From an Application
flake-ctl firecracker volume remove \
--app $HOME/bin/claude --volume /some/local/path:/some/guest/path
Reverts what volume add has performed: the matching entry is
deleted from the nfs= boot option, and the option itself is
deleted once no volume is left. --volume can be repeated the same
way as with add, and --instance removes the volume(s) of that
instance only. A volume is matched by its host and guest path, no
matter which server it is currently provided from.
Removing a volume does not release its NFS export nor does it change the network setup, both may still be needed by other flakes or instances. Release the export explicitly once it is no longer used by any application.
7.5. The Result in the Flake Configuration
The flake configuration for the registered claude app from
Claude AI as a Firecracker VM App can be found at:
vi ~/.config/flakes/claude.yaml
Adding a volume to the application and another one to its @id1
instance leads to the following settings, on top of the network setup
from Firecracker Networking:
vm:
runtime:
firecracker:
boot_args:
- ip=172.16.0.2::172.16.0.1:255.255.255.0::eth0:off
- rd.route=172.16.0.1/24::eth0
- nameserver=8.8.8.8
- nfs=172.16.0.1:/some/local/path:/some/guest/path
instance:
"@id1":
boot_args:
- ip=172.16.0.3::172.16.0.1:255.255.255.0::eth0:off
- nfs=172.16.0.1:/other/local/path:/other/guest/path
More than one volume of the same section is folded into a single
nfs= option as a comma separated list, which is the format the
init process of the guest, sci, reads the volumes from. It mounts
each of them with mount -t nfs before the application is started,
creating the guest path if it does not exist yet. A volume which
cannot be parsed, or which fails to mount, is skipped, the remaining
volumes are still mounted. For details refer to man 8 sci.
Note
As with the network instance section, the @ character is
reserved in YAML and the key has to be quoted. The plain name
without the @ prefix, e.g id1, is accepted as a key as
well.