How to add a block volume to a template
Coming from another cloud?
▸AWS·EBS Attach Volume
This Quake AI feature maps to AWS’s EBS Attach Volume.
▸Google Cloud·Persistent Disk Attach
This Quake AI feature maps to Google Cloud’s Persistent Disk Attach.
How to add a block volume to a template
Attach a block volume to an instance that a template provisions, format it on first boot, and record the mount in /etc/fstab so the filesystem mounts after a reboot. This guide extends templates without persistent data disks, such as simple-vm.
These templates provide reference implementations:
- wordpress-mysql: mounts
/dev/sdbat/var/lib/mysqlfor MySQL data - self-managed-postgres: mounts
/dev/sdbat/var/lib/postgresqlfor PostgreSQL data - dev-environment: uses a block volume to back a shared NFS export
Prerequisites
- ConsoleLogged in to the Quake AI console
- CLIOpenStack CLI installed and authenticated (
clouds.yamloropenrcsourced) - TerraformOpenTofu installed with Quake AI provider configured
Windows: CLI examples use bash. Set up a Linux CLI environment on Windows before proceeding.
- You deployed a template from
iac/templates/and rantofu initin that directory - OpenTofu or Terraform installed with Quake AI credentials configured
- Enough block-storage quota for the new volume (
openstack limits show --absolute -c name -c value | grep volumes)
Reference pattern from existing templates#
The wordpress-mysql template declares a block volume, an attachment to the MySQL instance, and a cloud-init script that formats and mounts the disk:
resource "openstack_blockstorage_volume_v3" "mysql_data" {
name = "${local.name_prefix}-mysql-data"
size = var.db_volume_size
}
resource "openstack_compute_volume_attach_v2" "mysql_data" {
instance_id = openstack_compute_instance_v2.mysql.id
volume_id = openstack_blockstorage_volume_v3.mysql_data.id
}The mount logic lives in cloud-init/mysql.yaml:
#cloud-config
runcmd:
- |
set -e
DEV=/dev/sdb
for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F "$DEV"; fi
mkdir -p /var/lib/mysql
mount "$DEV" /var/lib/mysql
grep -q "$DEV" /etc/fstab || echo "$DEV /var/lib/mysql ext4 defaults,nofail 0 2" >> /etc/fstabOn Quake AI, the boot volume occupies the first SCSI device. The first attached data volume appears as /dev/sdb, which is the path used by the templates in this repository.
Add volume resources to your template#
The following example extends simple-vm. Adjust resource names and the mount path for your workload.
1. Declare variables#
Add to variables.tf:
variable "data_volume_size" {
description = "Size in GB for the attached data volume"
type = number
default = 20
}
variable "data_mount_path" {
description = "Filesystem path where the data volume is mounted"
type = string
default = "/mnt/data"
}2. Create the volume and attachment#
Add to main.tf (or a new storage.tf):
resource "openstack_blockstorage_volume_v3" "data" {
name = "${var.instance_name}-data"
size = var.data_volume_size
}
resource "openstack_compute_volume_attach_v2" "data" {
instance_id = openstack_compute_instance_v2.vm.id
volume_id = openstack_blockstorage_volume_v3.data.id
}Place the attachment after the instance resource so OpenTofu can resolve openstack_compute_instance_v2.vm.id.
3. Mount the volume on first boot#
Create cloud-init/data-volume.yaml:
#cloud-config
runcmd:
- |
set -e
DEV=/dev/sdb
MOUNT=${mount_path}
for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F "$DEV"; fi
mkdir -p "$MOUNT"
mount "$DEV" "$MOUNT"
grep -q "$DEV" /etc/fstab || echo "$DEV $MOUNT ext4 defaults,nofail 0 2" >> /etc/fstabWire it into the instance. If the instance has no existing user_data, add:
resource "openstack_compute_instance_v2" "vm" {
# ... existing arguments ...
user_data = templatefile("${path.module}/cloud-init/data-volume.yaml", {
mount_path = var.data_mount_path
})
}Plan and apply#
From the template directory:
tofu plan
tofu applyThe plan shows one new openstack_blockstorage_volume_v3 and one openstack_compute_volume_attach_v2. It also shows an instance replacement when you add user_data for the first time.
Verify the attachment and mount#
See also#
- Create and attach a block volume: step-by-step tutorial for volumes outside IaC
- wordpress-mysql template: production volume + MySQL mount pattern
- self-managed-postgres template: PostgreSQL data volume pattern
- dev-environment template: shared volume with NFS export
- How to customize a template's image and flavor: resize compute without adding storage
- Block storage how-to guides: create, extend, and snapshot volumes through the Console and CLI
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Last validated: 10.07.2026