====== EVE-OS / ZEDEDA Application Volumes ====== Covers: what a volume is, what has to be configured in the GUI vs Terraform, how to deploy an app with a volume, and how to grow a volume after deployment. Primary examples use an image-backed **HDD** drive; **HDD_EMPTY** is covered as a separate use case at the end. Sources: [[https://github.com/lf-edge/eve|lf-edge/eve]], [[https://registry.terraform.io/providers/zededa/zedcloud/latest|zededa/zedcloud Terraform provider docs]], ZEDEDA Help Center (Storage Overview, Manage an Edge Application Instance, ZCLI volume-instance docs). ===== 1. What a volume is ===== A **volume instance** is the storage object EVE-OS attaches to an app instance as a drive. It backs one of: * The app's rootfs / OS disk (built from a Content Tree / image) — drive type **HDD** * A blank data disk for app data — drive type **HDD_EMPTY** * A shared/persistent data volume that can outlive the app instance or be shared between app instances on the same node A volume can be: * **Implicit** — created automatically as part of an app instance's drive list (defined inline on the app manifest) * **Explicit** — created ahead of time as its own object (''zcli volume-instance create'') and then referenced by label when the app is deployed Underlying storage is a qcow2 file (ext4 persist) or a zvol (ZFS persist), depending on how the edge node's ''/persist'' partition was provisioned at install time — see the separate EVE-OS Partitioning / ZFS wiki page for that layer. Volumes live **inside** whichever persist backend the node has. ===== 2. Key fields ===== ^ Field ^ Where it shows up ^ What it does ^ | Drive Type (''drvtype'') | GUI Drives pane / TF ''drvtype'' | ''HDD'' = image-backed. ''CDROM'' = read-only image, optical semantics. ''NET'' = network-backed. ''HDD_EMPTY'' = blank disk of ''maxsize'' (covered in section 6). | | Max Size (''maxsize'' / ''maxsizebytes'') | GUI Drives pane "Max Size" / TF ''maxsize'' | Capacity ceiling for the drive. For ''HDD'', this must be >= the image size; any headroom above the image size is usable, growable space on that same disk. | | Preserve (''preserve'') | GUI Drives pane "Preserve" | Whether this drive's data survives a purge/refresh of the app instance, vs. being rebuilt from the source image. | | Allow Storage Resize (''allow_storage_resize'' / ''allowStorageResize'') | App instance level, GUI/zcli/TF | Must be enabled before an existing app instance's drive size can be increased. Default: false. | | Volume Label (''volumelabel'') | GUI Drives pane / TF | References a pre-created (explicit) volume instance instead of an inline drive definition. | | Mount Path (''mountpath'') | GUI Drives pane / TF | Path inside the app where the drive is mounted. Empty or ''/'' defines the rootfs. | ===== 3. What's required to configure — GUI vs Terraform ===== ==== GUI ==== * Volume instances can be created standalone: Edge Node > Storage > Volume Instances > Add, or created implicitly while adding a drive to an app instance. * On the app instance's **Drives pane**, define per drive: Drive Type, Image, Mount Path, Max Size, Preserve, Encrypted, and (for explicit volumes) Volume Label. * Editing Drives on an **existing** app instance triggers a **Purge & Update** — the app purges and comes back online. Data on that drive is wiped unless Preserve was set. ==== Terraform (zededa/zedcloud provider) ==== * Resource: ''zedcloud_application_instance'' (or ''zedcloud_deployment'' for policy-driven rollout). * Drive block fields: ''drvtype'', ''maxsize'', ''preserve'', ''mountpath'', ''imagename'' / ''imvolname'' / ''mvolname'', ''volumelabel''. * App-instance-level field: ''allow_storage_resize'' (bool, default false) — must be ''true'' to permit a later ''maxsize'' change to apply. * Standalone volume instances can also be managed as their own resource/data source (''zedcloud_volume_instance'' family) and referenced by label from the app instance. ==== ZCLI ==== * Explicit volume: ''zcli volume-instance create --volume-type= --project= (--edge-node= | --edge-node-cluster=) --size= --access-mode='' * Update: ''zcli volume-instance update [--title=...] [--description=...]'' * App-instance-level resize permission is passed the same way as the GUI/TF flag, camelCase in JSON: ''"allowStorageResize": true'' ===== 4. Step-by-step: Deploy an app with a volume (HDD) ===== This is the common case: a single image-backed drive that serves as both the app's rootfs and its data storage, sized larger than the image itself so there's room to grow later. ==== Via GUI ==== - Go to **Edge Applications > Marketplace**, select or create the edge app. - Deploy the app: **Edge Applications > Deploy**, pick the target edge node. - On the **Drives pane**, add the drive: - Drive Type: **HDD** - Image: select the app's image / content tree - Mount Path: ''/'' (or empty) to define the rootfs - Max Size: set this **above** the image's native size if you want growable headroom (e.g. image is 4 GB, set Max Size to 20 GB) - Preserve: enable if this disk's contents should survive a future purge - Complete networking/resources panes as normal and click **Deploy**. - Confirm in **Edge Node > App Instances** that the instance reaches ''RUNNING'' and the drive shows the expected size under app instance details. ==== Via Terraform ==== resource "zedcloud_application_instance" "example" { name = "my-app-instance" app_id = zedcloud_application.example.id device_id = data.zedcloud_edgenode.target.id project_id = data.zedcloud_project.example.id drives { drvtype = "HDD" imagename = "my-app-image" mountpath = "/" maxsize = "21474836480" # 20 GiB ceiling, even if the image itself is much smaller preserve = true } allow_storage_resize = true } - ''terraform plan'' / ''terraform apply''. - Verify state: ''terraform state show zedcloud_application_instance.example'' or check the GUI app instance detail page. ===== 5. Step-by-step: Grow a volume (HDD) ===== **Important:** this is not a live/hot resize. Editing a drive on an existing app instance triggers a Purge & Update — the app purges and restarts. Data on that drive is lost unless ''preserve'' is set on it. ==== Via GUI ==== - Confirm the drive you're growing has **Preserve** set (if you need to keep its data). - Go to **Edge Applications > App Instances**, select the instance, **Edit**. - If not already enabled, enable **Allow Storage Resize** at the app instance level. - On the Drives pane, raise the **Max Size** field for the HDD drive. - Save. The GUI will show a **Purge and update** notification — confirm it. - Wait for the app instance to purge and come back ''RUNNING''. - Log into the guest and grow the filesystem to use the new space (EVE resizes the backing volume, not the guest's partition/fs — see step below). ==== Via Terraform ==== resource "zedcloud_application_instance" "example" { # ...unchanged config... drives { drvtype = "HDD" imagename = "my-app-image" mountpath = "/" maxsize = "42949672960" # was 20 GiB, now 40 GiB preserve = true } allow_storage_resize = true # must be true BEFORE the maxsize change is allowed to apply } - ''terraform apply''. If ''allow_storage_resize'' was ''false'' on the last-applied state, apply that change first, then apply the ''maxsize'' change (or in the same apply if the provider allows it — verify against current provider version behavior before assuming ordering). - Confirm the app instance purges and comes back up. ==== Guest-side step (both paths) ==== EVE enlarges the backing volume (qcow2/zvol); it does **not** grow the guest's partition or filesystem automatically. After the app instance comes back up: * Linux ext4: ''growpart /dev/xxx N'' then ''resize2fs /dev/xxxN'' * Linux xfs: ''growpart'' then ''xfs_growfs '' * Windows: Disk Management > right-click volume > Extend Volume ===== 6. Other use case: HDD_EMPTY (blank data disk) ===== **HDD_EMPTY** is a second, complementary pattern rather than an alternative to the above: a completely blank disk, not backed by any image or content tree, used as a separate data drive alongside an ''HDD'' rootfs drive. * No image, no content tree, no hash to verify — EVE just allocates raw space up to ''maxsize''. * Arrives to the guest as a raw, unformatted block device. The guest OS (or first-boot cloud-init) has to partition and format it itself. * Typically mounted at a data path (e.g. ''/data'', ''/var/lib/mysql''), separate from ''/''. * Same ''preserve'', ''maxsize'', and ''allow_storage_resize'' mechanics apply — grown the same way as described in section 5, just as a second drive block rather than the rootfs drive. drives { drvtype = "HDD_EMPTY" maxsize = "10737418240" # 10 GiB blank data disk preserve = true mountpath = "/data" } Use this when you want the OS/app image to stay a fixed, replaceable artifact (rebuilt cleanly on every app update) while the data lives on its own drive that is never touched by an image update — as opposed to the ''HDD'' pattern in sections 4-5, where rootfs and data share one disk and the whole disk gets rebuilt from the image on update unless ''preserve'' is set. ===== 7. Open questions / to verify before relying on this in production ===== * Exact ordering requirement between setting ''allow_storage_resize=true'' and applying a ''maxsize'' change in a single Terraform apply — not confirmed from docs, test on a non-prod app instance first. * Whether any current EVE-OS version auto-grows the guest filesystem on boot after a resize (e.g., via cloud-init growpart module) — not confirmed; assume manual step is required unless verified for your specific image. * This applies to **app instance drives only**. It does not expand the underlying ''/persist'' storage pool (ext4 disk or ZFS pool) — see the separate Partitioning/ZFS page for that, which is a install-time/reinstall operation, not a controller-driven one.