User Tools

Site Tools


zededa:workshop:06_persistent_volumes_content_trees

This is an old revision of the document!


Persistent Volumes and Content Trees

Volume instances are the storage layer for edge applications in ZEDEDA Cloud. There are two types, both created as zedcloud_volume_instance resources in Terraform but serving very different purposes.

  • Persistent Volume (BLOCKSTORAGE) – blank block storage allocated on the edge node. Read-write. Data survives app restarts, app deletion, and node reboots. Used for stateful application data.
  • Content Tree (CONTENT_TREE) – a volume pre-populated from an existing image. Read-only by default. Used to deliver an OS image, dataset, or binary to the node before or alongside an app.

Both types are node-scoped objects – they are created on a specific edge node or cluster, not in the project at large. If you want the same volume on five nodes, you create five volume instances.

Volume Instance Types

Type value Purpose Access Mode Image required Typical use
VOLUME_INSTANCE_TYPE_BLOCKSTORAGE Blank block storage READWRITE No App data, databases, persistent state, Node-RED flows
VOLUME_INSTANCE_TYPE_CONTENT_TREE Image-backed read-only volume READONLY (default) Yes Pre-stage a VM image, distribute a dataset, deliver a base OS

Key Fields

Field Description
type VOLUME_INSTANCE_TYPE_BLOCKSTORAGE or VOLUME_INSTANCE_TYPE_CONTENT_TREE
accessmode VOLUME_INSTANCE_ACCESS_MODE_READWRITE or VOLUME_INSTANCE_ACCESS_MODE_READONLY
size_bytes Size of the volume in bytes. For BLOCKSTORAGE: the allocated size. For CONTENT_TREE: set to 0 (size comes from the image).
image Image name to back the volume. Required for CONTENT_TREE, not used for BLOCKSTORAGE.
cleartext false = volume is encrypted at rest using EVE-OS full-disk encryption. true = unencrypted. Always use false in production.
label Optional label for the volume. Used when referencing it in app bundle drive definitions.
device_id Assign to a specific standalone edge node (mutually exclusive with edge_node_cluster).
edge_node_cluster.id Assign to an EVE-k cluster (mutually exclusive with device_id).

Persistent Volume vs Standard Volume

This is an important distinction in ZEDEDA:

Standard Volume Persistent Volume
Owned by The app instance The edge node
Lifecycle Deleted when the app instance is deleted Survives app deletion
Purge & Update Available Not available (Purge is unchecked)
Shared across apps No Yes – multiple apps on the same node can attach it
Created via App bundle drive definition zedcloud_volume_instance resource (separately)

A standard volume is created implicitly when you deploy an app and define a drive in the app bundle. A persistent volume is created explicitly as its own resource, then referenced by the app.

Terraform Examples

Persistent Block Volume -- EVE-k Cluster

1 GB blank block volume on an EVE-k cluster, encrypted at rest, read-write. Typical use: Node-RED flow storage, database files, application state.

resource "zedcloud_volume_instance" "tf_demo_vol1_persist" {
  edge_node_cluster {
    id = zedcloud_edgenode_cluster.demo_edgenode_cluster_1.id
  }
  accessmode = "VOLUME_INSTANCE_ACCESS_MODE_READWRITE"
  cleartext  = false
  label      = "nodered-vol1-persist"
  name       = "nodered-vol1-persist"
  size_bytes = 1073741824
  title      = "nodered-vol1-persist"
  type       = "VOLUME_INSTANCE_TYPE_BLOCKSTORAGE"
}

Notes:

  • size_bytes = 1073741824 is exactly 1 GB (1024 * 1024 * 1024)
  • cleartext = false enables EVE-OS encryption at rest – the volume key is sealed to the TPM via measured boot attestation
  • edge_node_cluster targets the cluster instead of a specific node. ZEDEDA creates the volume on each node in the cluster.
  • label is used when referencing this volume in an app bundle drives block

Content Tree Volume -- EVE-k Cluster

A read-only volume backed by the Ubuntu 24.04 image, used to pre-stage the OS on the cluster before deploying VMs. This avoids download delays when app instances are created.

resource "zedcloud_volume_instance" "tf_demo_vol1_ub_ct" {
  edge_node_cluster {
    id = zedcloud_edgenode_cluster.demo_edgenode_cluster_1.id
  }
  accessmode = "VOLUME_INSTANCE_ACCESS_MODE_READONLY"
  cleartext  = false
  image      = zedcloud_image.demo_atl_ub_image_1.name
  label      = ""
  name       = "UBUNTU-24-CT"
  size_bytes = 0
  title      = "UBUNTU-24-CT"
  type       = "VOLUME_INSTANCE_TYPE_CONTENT_TREE"
}

Notes:

  • image references the image name (not ID) of a registered app image – in this case the Ubuntu 24.04 QCOW2 registered earlier
  • size_bytes = 0 – for content trees the size is determined by the image itself, not declared here
  • accessmode = READONLY is standard for content trees; the image data is not modified at runtime
  • label = “” – no label needed since the image name is the identifier
  • EVE-OS downloads the image from the datastore when this volume instance is created, caching it locally. Subsequent VMs using this image on the same node do not need to re-download it.

Persistent Block Volume -- Standalone Edge Node

The same 1 GB block volume but targeting a specific standalone node instead of a cluster. Use device_id instead of edge_node_cluster:

resource "zedcloud_volume_instance" "tf_demo_vol1_persist_nocl" {
  device_id  = zedcloud_edgenode.demo_en_advantech_1.id
  accessmode = "VOLUME_INSTANCE_ACCESS_MODE_READWRITE"
  cleartext  = false
  label      = "nodered-vol1-persist-nocl"
  name       = "nodered-vol1-persist-nocl"
  size_bytes = 1073741824
  title      = "nodered-vol1-persist"
  type       = "VOLUME_INSTANCE_TYPE_BLOCKSTORAGE"
}

The only structural difference is device_id vs edge_node_cluster.id. Everything else is identical. device_id and edge_node_cluster are mutually exclusive – you cannot specify both.

Size Reference

Size Bytes
512 MB 536870912
1 GB 1073741824
5 GB 5368709120
10 GB 10737418240
20 GB 21474836480
50 GB 53687091200

ZEDUI Walkthrough

Volume instances can be created standalone in ZEDUI or as part of the app deployment wizard.

  1. Navigate to Library > Volume Instances
  2. Click +
  3. Select the target Edge Node or Edge Node Cluster
  4. Select Type: Block Storage or Content Tree
  5. For Content Tree: select the Image
  6. Set Size (for Block Storage) or leave at 0 (Content Tree)
  7. Set Access Mode: Read-Write or Read-Only
  8. Set Encryption: on (recommended)
  9. Click Add

As part of App Deployment

When creating an App Bundle under Edge Apps, the Drives section lets you define volumes inline. These become standard (non-persistent) volumes tied to the app instance lifecycle unless you uncheck Purge.

To make a drive persistent: uncheck Purge in the Drives section. Note that Purge & Update will then be unavailable for that drive.

ZCLI

# Persistent block volume on a standalone node
zcli volume-instance create nodered-vol1-persist-nocl \
  --volume-type=BLOCKSTORAGE \
  --project=demo-project \
  --edge-node=demo-en-advantech-1 \
  --size=1073741824 \
  --access-mode=READWRITE \
  --title="nodered-vol1-persist"
# Content tree on a cluster
zcli volume-instance create UBUNTU-24-CT \
  --volume-type=CONTENT_TREE \
  --project=demo-project \
  --edge-node-cluster=demo-edgenode-cluster-1 \
  --image=TF-ATL-UBUNTU-24-IMAGE \
  --size=0 \
  --access-mode=READONLY \
  --title="UBUNTU-24-CT"
# Show volume instances on a specific node
zcli volume-instance show \
  --project=demo-project \
  --edge-node=demo-en-advantech-1

API

# Persistent block volume
POST /v1/volumes
{
  "name": "nodered-vol1-persist-nocl",
  "type": "VOLUME_INSTANCE_TYPE_BLOCKSTORAGE",
  "accessMode": "VOLUME_INSTANCE_ACCESS_MODE_READWRITE",
  "sizeBytes": 1073741824,
  "clearText": false,
  "deviceId": "<device_id>",
  "projectId": "<project_id>"
}
# Content tree
POST /v1/volumes
{
  "name": "UBUNTU-24-CT",
  "type": "VOLUME_INSTANCE_TYPE_CONTENT_TREE",
  "accessMode": "VOLUME_INSTANCE_ACCESS_MODE_READONLY",
  "sizeBytes": 0,
  "clearText": false,
  "image": "TF-ATL-UBUNTU-24-IMAGE",
  "deviceId": "<cluster_id>",
  "projectId": "<project_id>"
}

What Happens on the Edge Node

Block Storage (BLOCKSTORAGE)

  1. EVE-OS receives the volume instance config at next heartbeat
  2. EVE-OS allocates the requested size from the node's data partition storage pool
  3. A raw block device or ext4 filesystem is created depending on how the app references it
  4. When an app instance references this volume in its drive definition, EVE-OS bind-mounts or block-attaches it into the VM or container at the specified mount path
  5. Data written by the app is stored on the node's local storage and is NOT automatically synced to the cloud
  6. The volume persists if the app is stopped, restarted, updated, or deleted – it is owned by the node, not the app

Content Tree (CONTENT_TREE)

  1. EVE-OS receives the volume instance config referencing the image
  2. EVE-OS downloads the image from the registered datastore (same path as an app image download)
  3. The image is stored in EVE-OS's local volume pool
  4. When an app instance references this volume, EVE-OS presents the image data as a read-only block device or mount point
  5. For QCOW2 images used as VM drives, EVE-OS creates a copy-on-write overlay so the app's writes go to a separate layer while the base image remains unchanged and reusable

Encryption

When cleartext = false, the volume is encrypted at rest using EVE-OS's full-disk encryption:

  • The encryption key is generated per-volume on the node
  • The key is sealed to the TPM using the measured boot PCR values
  • If the node fails attestation (PCR values change – indicating possible tampering), the key cannot be unsealed and the volume is inaccessible
  • This means tampered or reflashed nodes cannot read encrypted volume data

Always use cleartext = false for production workloads that store sensitive data.

Common Patterns

Pattern Type Example
App data persistence BLOCKSTORAGE Node-RED flows, InfluxDB data, SQLite DB
Pre-stage VM image CONTENT_TREE Ubuntu 24.04 cached on node before app deployment
Shared data between apps BLOCKSTORAGE (READWRITE) Sensor data written by one app, read by another
Configuration delivery CONTENT_TREE (READONLY) Static config files packaged as a custom image
Log offload staging BLOCKSTORAGE App writes logs to volume; separate log shipper reads them
zededa/workshop/06_persistent_volumes_content_trees.1780248110.txt.gz · Last modified: (external edit)