Need help setting 'storage.images_volume' on a Project level

I am trying to set “storage.images_volume” on a Project level so that a given project will have a dedicated volume to store all its images (of that Project). And then a dedicated storage to store the root disks of all the containers and vms (of that Project)

I believe I am able to get the later part right but it is the ‘storage.images_volume’ that I couldn’t figure out what I am doing wrong :frowning: Appreciate any help/advice.

Here is my setup:

I created a project name ‘Handson-lab-1’

# uname -a
Linux red-handsonbox 6.8.0-58-generic #60-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 14 18:29:48 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

# cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo

# incus --version
6.12

# incus project list -f compact
           NAME            IMAGES  PROFILES  STORAGE VOLUMES  STORAGE BUCKETS  NETWORKS  NETWORK ZONES       DESCRIPTION       USED BY
  Handson-lab-1 (current)  YES     YES       YES              YES              YES       YES            Project Handson-lab-1  2
  default                  YES     YES       YES              YES              YES       YES            Default Incus project  2

I have 3 ZFS pools (I have more but removing them just to focus on the issue)

# zpool list
NAME        SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
basepool   5.50G  6.49M  5.49G        -         -     6%     0%  1.00x    ONLINE  -
imgpool-1   154G   782K   154G        -         -     0%     0%  1.00x    ONLINE  -
zpool-1     316G   748K   316G        -         -     0%     0%  1.00x    ONLINE  -

I added both of them to incus storage

# incus storage list -f compact
    NAME     DRIVER                  DESCRIPTION                   USED BY   STATE
  basepool   zfs     passed to incus admin init                    1        CREATED
  images-1   zfs     Storage for images of Handson-lab-1           1        CREATED
  storage-1  zfs     Storage for Containers, VMs of Handson-lab-1  1        CREATED

‘storage-1’ is backed by ZFS zpool-1

# incus storage show storage-1
config:
  source: zpool-1
  volatile.initial_source: zpool-1
  zfs.pool_name: zpool-1
description: Storage for Containers, VMs of Handson-lab-1
name: storage-1
driver: zfs
used_by:
- /1.0/profiles/default?project=Handson-lab-1
status: Created
locations:
- none

‘images-1’ is backed by ZFS imgpool-1

# incus storage show images-1
config:
  source: imgpool-1
  volatile.initial_source: imgpool-1
  zfs.pool_name: imgpool-1
description: Storage for images of Handson-lab-1
name: images-1
driver: zfs
used_by:
- /1.0/storage-pools/images-1/volumes/custom/volume-1?project=Handson-lab-1
status: Created
locations:
- none

I have a volume named ‘volume-1’ on storage ‘images-1’

# incus storage volume list images-1 -f compact
   TYPE     NAME    DESCRIPTION  CONTENT-TYPE  USED BY
  custom  volume-1               filesystem    0

# incus storage volume show images-1 volume-1
config: {}
description: ""
name: volume-1
type: custom
used_by: []
location: none
content_type: filesystem
project: Handson-lab-1
created_at: 2025-04-27T17:03:40.277833097Z

My current configuration for the project Handson-lab-1 is as follows:

# incus project show Handson-lab-1
config:
  features.images: "true"
  features.networks: "true"
  features.networks.zones: "true"
  features.profiles: "true"
  features.storage.buckets: "true"
  features.storage.volumes: "true"
  restricted: "true"
  restricted.containers.lowlevel: allow
  restricted.containers.nesting: allow
  restricted.containers.privilege: allow
  restricted.devices.disk: managed
  restricted.devices.gpu: allow
  restricted.snapshots: allow
  restricted.virtual-machines.lowlevel: allow
description: Project Handson-lab-1
name: Handson-lab-1
used_by:
- /1.0/profiles/default?project=Handson-lab-1
- /1.0/storage-pools/images-1/volumes/custom/volume-1?project=Handson-lab-1

I believe I got the default profile for the project (Handson-lab-1) right so that the root disk for all containers and vms does go to ‘storage-1’ as I wanted to:

# incus profile show default
config:
  security.nesting: "true"
  security.privileged: "true"
description: Default Incus profile for project Handson-lab-1
devices:
  root:
    path: /
    pool: storage-1
    type: disk
name: default
used_by: []
project: Handson-lab-1

(Note: I know I don’t have the network setup in the default profile. That is intentional because I am planning on having a different profiles for networks. I will pass the network profiles while launching instances)

THIS IS WHERE I NEED HELP/ADVICE. WHY DOES IT FAIL ? I AM CLEARLY PASSING THE NAME OF THE PROJECT

# incus config set storage.images_volume images-1/volume-1 --project Handson-lab-1
Error: Failed validation of "storage.images_volume": Failed loading storage volume "images-1/volume-1" in "default" project: Storage volume not found

Why is it looking at the “default” project when I am specifically mentioning that the action has to be carried out on the project Handson-lab-1 ?

When I tried to modify the default profile (meant for the Project)

# incus profile show default
config:
  storage.images_volume: images-1/volume-1 --------------->> Added this line manually
  security.nesting: "true"
  security.privileged: "true"
description: Default Incus profile for project Handson-lab-1
devices:
  root:
    path: /
    pool: storage-1
    type: disk
name: default
used_by: []
project: Handson-lab-1

I am getting the error:

# incus profile edit default
Config parsing error: Unknown configuration key: storage.images_volume
Press enter to open the editor again or ctrl+c to abort change

I tried this one too:

# incus project set Handson-lab-1 storage.images_volume=images-1/volume-1
Error: Invalid project configuration key "storage.images_volume"

My question is - Where exactly should I define “storage.images_volume” on a Project level ?

Any advice would help. Thanks!

Image and backup storage is a system-wide thing, not per-project.
Those configuration options are therefore system-wide settings.

Thank you !!

Looks like my thinking/approach is wrong :slight_smile: I was hoping to create a multi-tenant system. Each tenant is basically a project. Each project will have 2 dedicated storage pools (1 x dedicated volume to store images and 1 x dedicated for storing root disks).

I am still wondering what would be a better appoach to create storage isolation among projects ?

  • Have separate storage pool(s) per project
  • create separate (storage) profile(s) per project
  • consume (storage) profiles accordingly base on the project being used

The unpacked images will always live on the same pools that are using them for instances, so that part is already covered in your case.

The storage.images_volume is for where to store the image tarballs.
That’s global as multiple projects may have the exact same image, either because they copied it from each other, or from the same external image server or because they imported the same image by hand.

Thanks again. I got carried away with my own design, without understanding important concepts. This is what I was working towards (attached diagram). Now that I know I was wrong, I will reuse those pools that are on different partitions of the 1TB NVMe SSD, repurpose them as additional storage volume per project. This is not a live project. So no damage done :slight_smile: All trying to understand how to build multi-tenancy.

Just an update. I managed to re-purpose different partitions to different zfs pools and brought them into incus. Finally assigned a dedicated volume to storage.images_volume.

root@red-handsonbox:~# lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    1 460.3G  0 disk
├─sda1        8:1    1     1M  0 part
└─sda2        8:2    1 460.3G  0 part /
nvme0n1     259:0    0   1.9T  0 disk
├─nvme0n1p1 259:1    0   317G  0 part
├─nvme0n1p2 259:2    0   317G  0 part
├─nvme0n1p3 259:3    0   317G  0 part
├─nvme0n1p4 259:4    0   317G  0 part
├─nvme0n1p5 259:5    0   317G  0 part
├─nvme0n1p6 259:6    0   317G  0 part
└─nvme0n1p7 259:7    0   5.7G  0 part
nvme1n1     259:8    0 931.5G  0 disk
├─nvme1n1p1 259:9    0   155G  0 part
├─nvme1n1p2 259:10   0   155G  0 part
├─nvme1n1p3 259:11   0   155G  0 part
├─nvme1n1p4 259:12   0   155G  0 part
├─nvme1n1p5 259:13   0   155G  0 part
├─nvme1n1p6 259:14   0   155G  0 part
└─nvme1n1p7 259:15   0   1.5G  0 part

root@red-handsonbox:~# zpool list
NAME          SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
basepool     5.50G  5.62M  5.49G        -         -     2%     0%  1.00x    ONLINE  -
disks-pool    308G   694K   308G        -         -     0%     0%  1.00x    ONLINE  -
images-pool   462G   797K   462G        -         -     0%     0%  1.00x    ONLINE  -
iso-pool      154G   702K   154G        -         -     0%     0%  1.00x    ONLINE  -
zpool-1       316G   916K   316G        -         -     0%     0%  1.00x    ONLINE  -
zpool-2       316G   636K   316G        -         -     0%     0%  1.00x    ONLINE  -
zpool-3       316G   646K   316G        -         -     0%     0%  1.00x    ONLINE  -
zpool-4       316G   634K   316G        -         -     0%     0%  1.00x    ONLINE  -
zpool-5       316G   632K   316G        -         -     0%     0%  1.00x    ONLINE  -
zpool-6       316G   634K   316G        -         -     0%     0%  1.00x    ONLINE  -

root@red-handsonbox:~# incus storage list -f compact
      NAME       DRIVER                  DESCRIPTION                   USED BY   STATE
  basepool       zfs     passed to incus admin init                    1        CREATED
  shared-disks   zfs     shared disks accross Projects                 0        CREATED
  shared-images  zfs     shared images accross Projects                1        CREATED
  shared-iso     zfs     shared ISOs accross Projects                  0        CREATED
  storage-1      zfs     Storage for Containers, VMs of Handson-lab-1  1        CREATED
  storage-2      zfs     Storage for Containers, VMs of Handson-lab-2  0        CREATED
  storage-3      zfs     Storage for Containers, VMs of Handson-lab-3  0        CREATED
  storage-4      zfs     Storage for Containers, VMs of Handson-lab-4  0        CREATED
  storage-5      zfs     Storage for Containers, VMs of Handson-lab-5  0        CREATED
  storage-6      zfs     Storage for Containers, VMs of Handson-lab-6  0        CREATED
root@red-handsonbox:~# incus config show
config:
  core.https_address: :8443
  storage.images_volume: shared-images/global-volume
root@red-handsonbox:~# incus storage volume list shared-images
+--------+---------------+---------------------------------------------------------------+--------------+---------+
|  TYPE  |     NAME      |                          DESCRIPTION                          | CONTENT-TYPE | USED BY |
+--------+---------------+---------------------------------------------------------------+--------------+---------+
| custom | global-volume | Global Volume to store all images, shared across all projects | filesystem   | 0       |
+--------+---------------+---------------------------------------------------------------+--------------+---------+