Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Drallas/7e4a6f6f36610eeb0bbb5d011c8ca0be to your computer and use it in GitHub Desktop.
Save Drallas/7e4a6f6f36610eeb0bbb5d011c8ca0be to your computer and use it in GitHub Desktop.

Mount Volumes into Proxmox VMs with Virtio-fs

Part of collection: Hyper-converged Homelab with Proxmox

Virtio-fs is a shared file system that lets virtual machines access a directory tree on the host. Unlike existing approaches, it is designed to offer local file system semantics and performance. The new virtiofsd-rs Rust daemon Proxmox 8 uses, is receiving the most attention for new feature development.

Performance is very good (while testing, almost the same as on the Proxmox host)

VM Migration is not possible yet, but it's being worked on!

Architecture

Screenshot 2023-09-27 at 17 47 52

Why?

Since I have a Proxmox High Available cluster with Ceph, I like to mount the Ceph File System, with CephFS Posix-compliant directories into my VM’s. I have been playing around with LXC container and Bind Mounts and even successfully setup Docker Swarm in LXC Containers. Unfortunately, this is not a recommended configuration and comes with some trade-offs and cumbersome configuration settings.

This Write-Up explains how to Create Erasure Coded CephFS Pools to store Volumes that than can be mounted into a VM via virtiofs.


Install virtiofsd

| This procedure has been tested with Ubuntu Server 22.04 and Debian 12!

Proxmox 8 Nodes, don’t have virtiofsd installed by default, so the first step is to install it.

apt install virtiofsd -y

# Check the version
/usr/lib/kvm/virtiofsd --version
virtiofsd backend 1.7.0

virtiofsd 1.7.0 has many issues (hangs after rebooting the vm, superblock errors etc...) version 1.7.2 and 1.8.0 seems to work much better, it can be found at virtio-fs releases page. But be carefull this package is not considered stable and not even in unstable Debian Package Tracker.


Add the hookscript to the vm

Still on the Proxmox host!

Get the Hookscript files files and copy them to /var/lib/vz/snippets, and make virtiofs_hook.pl executable.

Or use the get-hookscript.sh script to download the scripts files automatically to /var/lib/vz/snippets.

cd ~/
sudo sh -c "wget https://raw.githubusercontent.com/Drallas/Virtio-fs-Hookscript/main/get_hook_script.sh"
sudo chmod +x ~/get-hook%20script.sh
./get-hook%20script.sh

Modify the conf file

To set the VMID and the folders that a VM needs to mount, open the virtiofs_hook.conf file.

sudo nano /var/lib/vz/snippets/virtiofs_hook.conf

Set the Hookscript to an applicable VM

Set the hookscript to a VM.

qm set <vmid> --hookscript local:snippets/virtiofs_hook.pl

That's it, when it's added to the VM, the script does it magic on VM boot:

  • Adding the correct Args section to the virtiofsd args: -object memory-backend-memfd,id=mem,size=4096M,share=on -numa node........
  • Creating the sockets that are needed for the folders.
  • Cleanup on VM Shutdown

Start / Stop VM

The VM can now be started and the hookscript takes care of the virtiofsd part.

qm start <vmid>

Check

Check the processes virtiofsd ps aux | grep virtiofsd or systemctl | grep virtiofsd for the systemd services.

If all is good, it looks like this: Screenshot 2023-09-23 at 12 51 55


Mount inside VM

Linux kernel >5.4 inside the VM, supports Virtio-fs natively

Mounting is in the format: mount -t virtiofs <tag> <local-mount-point>

To find the tag

On the Proxmox host; Exucute qm config <vmid> --current and look for the tag=xxx-docker inside the args section args: -object memory-backend-memfd,id=mem,size=4096M,share=on -numa node,memdev=mem -chardev socket,id=char1,path=/run/virtiofsd/xxx-docker.sock -device vhost-user-fs-pci,chardev=char1,tag=<vmid>-<appname>

# Create a directory
sudo mkdir -p /srv/cephfs-mounts/<foldername>

# Mount the folder
sudo mount -t virtiofs mnt_pve_cephfs_multimedia /srv/cephfs-mounts/<foldername>

# Add them to /etc/fstab
sudo nano /etc/fstab

# Mounts for virtiofs
# The nofail option is used to prevent the system to hang if the mount fails!
<vmid>-<appname>  /srv/cephfs-mounts/<foldername>  virtiofs  defaults,nofail  0  0
 
# Mount everything from fstab
sudo systemctl daemon-reload && sudo mount -a

# Verify
ls -lah /srv/cephfs-mounts/<vmid>-<appname>

Issues

  1. New Vm's tend to trow a 'superblock' error on first boot:
mount: /srv/cephfs-mounts/download: wrong fs type, bad option, bad superblock on mnt_pve_cephfs_multimedia, missing codepage or helper program, or other error.
       dmesg(1) may have more information after failed mount system call.

To solve this, I poweroff the vm sudo /sbin/shutdown -HP now and then start it again from the host with qm start <vmid>, everything should mount fine now.

  1. Adding an extra volume throws also a 'superblock' error.
qm stop <vmid>
sudo nano /etc/pve/qemu-server/<vmid>.conf
# Remove the Arg entry
`args: -object memory-backend-memfd,id=mem,size=4096M,share=on..
qm start <vmid>

Now the Volume's all have a superblock error; I poweroff the vm sudo /sbin/shutdown -HP now and then start it again from the host with qm start <vmid>, everything should mount fine again.


Cleanup

To remove Virtio-fs from a VM and from the host:

nano /etc/pve/qemu-server/xxx.conf

# Remove the following lines
hookscript: local:snippets/virtiofs-hook.pl
args: -object memory-backend-memfd,id=mem,size=4096M,share=on..

Disable each virtiofsd-xxx service, replace xxx with correct values or use (* wildcard) to remove them all at once.

systemctl disable virtiofsd-xxx
sudo systemctl reset-failed virtiofsd-xxx

This should be enough, but if the reference persist:

# Remove leftover sockets and services.
rm -rf /etc/systemd/system/virtiofsd-xxx
rm -rf /etc/systemd/system/xxx.scope.requires/
rmdir /sys/fs/cgroup/system.slice/'system-virtiofsd\xxx' 

If needed reboot the Host, to make sure all references are purged from the system state.


Links


Moved to: https://github.com/Drallas/Virtio-fs-Hookscript/blob/main/Script/get-hook%20script.sh
# get-hook script.sh retained to keep it's commit history!
# Moved to: https://github.com/Drallas/Virtio-fs-Hookscript/blob/main/Script/virtiofs-hook.pl
@scyto
Copy link

scyto commented Sep 23, 2023

This is awesome.

In this modality do you pin each vm to a host so that the VM doesn’t auto migrate - I.e letting swarm do its thing inside the VMs?

@Drallas
Copy link
Author

Drallas commented Sep 23, 2023

Thanks, hopefully it’s working out for you too.

And yes I’m using HA to pin them to on of my 4 host. Once I have setup volumes on shared storage, Swarm can do its thing, for now Containers that need Volumes are 📍ed.

Hopefully someday virtiofs supports migration too, and it can all roam free on the cluster. 🤑

@scyto
Copy link

scyto commented Sep 23, 2023

Hopefully someday virtiofs supports migration too, and it can all roam free on the cluster.

that would be good, also the 'use one of those old cephfs docker volume drivers` has the benefit that that could let the VM roam - but i am not sure i see the point of the services can roam around my swarm anyway.... i don't think in that model in a small home lab i need VM roaming when 1 node real node goes down.

@Drallas
Copy link
Author

Drallas commented Sep 23, 2023

For stuff that’s requires uptime and stability (DNS, Monitoring, Plex,…) I use LXCs and VMs (without Virtiofs for now). As long as the Services on 📍ed Docker Swarm Nodes roam I’m good.

But I do like to use real Docker Volumes over just mounting a folder, not sure yet how to do that with Virtiofs.

That’s why GlusterFS is still considered, I could put the bricks on the 90% unused empty system NVMe (512 Gb) in my Nodes. More than enough to store all my Docker persistent data. And with PBS I have good backups of them anyway, so no need to worry that much.

@scyto
Copy link

scyto commented Sep 23, 2023

agree with everything you said, given my #1 prio is migrating from hyper-v this is my current plan for the weekend... (its still lunch time here) this is the only thing where i have written the steps before I do it to make sure I reduce the risks of mistakes in the move,..... i have only done one 'production' LXC so far... i doubt i will do more as i am heavily invested in portainer....

image

@Drallas
Copy link
Author

Drallas commented Sep 24, 2023

I was all in on LXC; tteck’s Proxmox VE helper scripts, make it a breeze to bring them to life. But most stuff runs great in a Docker swarm.

Guess I will do an overview of my Homelab after I’m done with this migration cycle, I’d like to explain the why behind it all.

@dvino
Copy link

dvino commented Oct 31, 2023

It would probably be better to put the path configuration for VMs in a separate file.

Create config file /etc/pve/qemu-server/virtiofs_hook.conf

101: /mnt/pve/cephfs/<folder1>, /mnt/pve/cephfs/<folder2>
102: /mnt/pve/cephfs/<folder1>, /mnt/pve/cephfs/<folder2>, /mnt/pve/cephfs/<folder3>

Replace the following lines with these lines

my $conf_file = '/etc/pve/qemu-server/virtiofs_hook.conf';
my %associations;

open my $cfg, '<', $conf_file or die "Failed to open virtiofs_hook.conf";
while (my $line = <$cfg>) {
    chomp $line;
    my ($vm_id, $paths_str) = split /:/, $line;
    my @path = split /,/, $paths_str;
    $associations{$vm_id} = \@path;
}

close $cfg or warn "Close virtiofs_hook.conf failed: $!";

Just tested it on my Proxmox. It works fine

@Drallas
Copy link
Author

Drallas commented Oct 31, 2023

@dvino Yes I totally agree, need to update one of my Hosts Virtiofsd configs soon; I will use this then.

@dvino
Copy link

dvino commented Oct 31, 2023

And also need to replace the regular expression in this line.

my $share_id  = $_ =~ m!/([^/]+)$! ? $1 : ''; # only last folder from path

Because if there is a slash at the end of the folder path, it will cause an incorrect result.

I think this should work right

my $share_id = $_ =~ m/.*\/([^\/]+)/ ? $1 : '';  # only last folder from path

@Drallas
Copy link
Author

Drallas commented Nov 1, 2023

@dvino I moved the Hookscript to a Git Repo and incorporated your changes there and adjusted this file too.

Ran a test and it all works! Tnx.

@scottmeup
Copy link

Is it possible to run the hookscript on a guest that is setup with cloud-init?

I tried the method described above but with no luck: the guest does not recognize the tags.

It looks like the guest doesn't receive the correct args values.

proxmox$ sudo qm config 100 --current

...
args: -fw_cfg name=opt/com.coreos/config,file=/etc/pve/geco-pve/coreos/100.ign
...
hookscript: local:snippets/virtiofs_hook.pl
...

@Drallas
Copy link
Author

Drallas commented Mar 15, 2024

Is it possible to run the hookscript on a guest that is setup with cloud-init?

I tried the method described above but with no luck: the guest does not recognize the tags.

It looks like the guest doesn't receive the correct args values.

proxmox$ sudo qm config 100 --current

...
args: -fw_cfg name=opt/com.coreos/config,file=/etc/pve/geco-pve/coreos/100.ign
...
hookscript: local:snippets/virtiofs_hook.pl
...

No idea didn’t try this. Did you install virtiofs and is it working properly?

@scottmeup
Copy link

Yes, I followed your guide - very helpful btw - and have it running and tested working on another guest.

I'm still trying to track down what's happening exactly: I can see an instance of virtiofsd that matches the guest cloud-init machine but the tags don't come up in the output of qm config 100 --current, and when I try to mount the file system it gives:

$ sudo mount -t virtiofs 100-100 /mnt/virtio_independent
mount: /var/mnt/virtio_independent: wrong fs type, bad option, bad superblock on 100-100, missing codepage or helper program, or other error.

 

From the output it looks like something might be happening during pre-start?

In the end the args become set as in the last line of post-start.

 

pre-start

100 is starting, doing preparations.
Creating directory: /run/virtiofsd/
attempting to install unit virtiofsd-100-common...
DIRECTORY DOES EXIST!
attempting to install unit virtiofsd-100-100...
ERROR: /run/virtiofsd/ does not exist!
-object memory-backend-memfd,id=mem,size=2048M,share=on -numa node,memdev=mem -chardev socket,id=char0,path=/run/virtiofsd/100-common.sock -device vhost-user-fs-pci,chardev=char0,tag=100-common -chardev socket,id=char1,path=/run/virtiofsd/100-100.sock -device vhost-user-fs-pci,chardev=char1,tag=100-100
Appending virtiofs arguments to VM args.

 

post-start

100 started successfully.
Removing virtiofs arguments from VM args.
conf->args = -fw_cfg name=opt/com.coreos/config,file=/etc/pve/geco-pve/coreos/100.ign -object memory-backend-memfd,id=mem,size=2048M,share=on -numa node,memdev=mem -chardev socket,id=char0,path=/run/virtiofsd/100-common.sock -device vhost-user-fs-pci,chardev=char0,tag=100-common -chardev socket,id=char1,path=/run/virtiofsd/100-100.sock -device vhost-user-fs-pci,chardev=char1,tag=100-100
vfs_args = -object memory-backend-memfd,id=mem,size=2048M,share=on -numa node,memdev=mem -chardev socket,id=char0,path=/run/virtiofsd/100-common.sock -device vhost-user-fs-pci,chardev=char0,tag=100-common -chardev socket,id=char1,path=/run/virtiofsd/100-100.sock -device vhost-user-fs-pci,chardev=char1,tag=100-100
-fw_cfg name=opt/com.coreos/config,file=/etc/pve/geco-pve/coreos/100.ignconf->args = -fw_cfg name=opt/com.coreos/config,file=/etc/pve/geco-pve/coreos/100.ign

 

virtiofs_hook.conf

100: /mnt/sdb2/common, /mnt/sdb2/100
101: /mnt/sdb2/common, /mnt/sdb2/101
1000: /mnt/sdb2/common, /mnt/sdb2/1000

@Drallas
Copy link
Author

Drallas commented Mar 15, 2024

I always saw ‘superblock’ errors on the first boot; see the issue’s for details. Perhaps it helps!?

@cprhh
Copy link

cprhh commented Mar 31, 2024

Hi @Drallas
Thank you for the work with this guide. I tried to follow but got to a point where i do not understand what kind of problem i have.
Maybe you have a idea for me?

root@pve:/var/lib/vz/snippets# ls -la
total 20
drwxr-xr-x 2 root root 4096 Apr  1 00:01 .
drwxr-xr-x 6 root root 4096 Mar 31 17:04 ..
-rw-r--r-- 1 root root   23 Mar 31 23:34 virtiofs_hook.conf
-rwxr-xr-x 1 root root 4165 Apr  1 00:01 virtiofs_hook.pl

If a run qm like in your example i got "hookscript: script 'local:snippets/virtiofs-hook.pl' does not exist"


root@pve:/var/lib/vz/snippets# qm set 101 --hookscript local:snippets/virtiofs-hook.pl
400 Parameter verification failed.
hookscript: script 'local:snippets/virtiofs-hook.pl' does not exist

qm set <vmid> [OPTIONS]

Found the Problem now. You have a typo in your script. It should be:

qm set <vmid> --hookscript local:snippets/virtiofs_hook.pl
and not
qm set <vmid> --hookscript local:snippets/virtiofs-hook.pl

@Drallas
Copy link
Author

Drallas commented Apr 1, 2024

@cprhh Glad you found the issue yourself, thanks for pointing out the typo in the guide (sorry for that)..

@scyto
Copy link

scyto commented Apr 8, 2024

@Drallas i am little confused how your VMs have all these args? none of mine have any form -f -object args.... what am i missing?

On the Proxmox host; Exucute qm config <vmid> --current and look for the tag=xxx-docker inside the args section args: -object memory-backend-memfd,id=mem,size=4096M,share=on -numa node,memdev=mem -chardev socket,id=char1,path=/run/virtiofsd/xxx-docker.sock -device vhost-user-fs-pci,chardev=char1,tag=<vmid>-<appname>

@scyto
Copy link

scyto commented Apr 8, 2024

@Drallas on live migration, i note that all the changes documented here are now merged in all upstream repos.... i wonder how long before it makes its way down to proxmox.... https://gitlab.com/virtio-fs/virtiofsd/-/issues/136

@Drallas
Copy link
Author

Drallas commented Apr 9, 2024

@scyto Those values are set when the hookscript is added to the vm, no idea why it's different on yours system But you should have the tag=<vmid>-<appname> section?

I have not touched my cluster for a while, it's running smooth and I just use the services on top of it. It needs some maintenance soon, then i will also update them and check the live migration.

@scyto
Copy link

scyto commented Apr 10, 2024

oooh, thanks, i haven't implemented the scripts yet so no wonder i am confused / stupid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment