Virtual Machine
The vm resource defines a virtual machine that runs as part of your lab sandbox environment. VMs provide full operating system compute for labs that need system services, OS-level configuration, extra disks, or workloads that do not fit a container-only design.
Use Cases
Section titled “Use Cases”As a lab author, you can use VMs to create richer sandbox environments:
- Full Operating Systems: Run workloads that need a complete Linux environment instead of a single container process
- System Configuration Labs: Teach package installation, service management, networking, or disk setup
- Nested Runtime Labs: Provide VM images that include Docker, Kubernetes, or other platform tooling
- Stateful Services: Attach additional disks for databases, data directories, or other storage-heavy exercises
Use a VM when the lab experience depends on OS behavior. Use a container when a lighter process-isolated runtime is enough.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "vm" "ubuntu" { image { name = "ubuntu:24.04" }}Full Syntax
Section titled “Full Syntax”resource "network" "main" { subnet = "10.50.0.0/24"}
resource "vm" "ubuntu" { config { arch = "x86_64" }
image { name = "ubuntu:24.04" username = "registry-user" password = variable.registry_token }
resources { cpu = 2 memory = 2048 }
environment = { GREETING = "hello" }
dns = ["1.1.1.1"] startup_script = <<-EOF #!/bin/sh apt-get update apt-get install -y nginx EOF
network { id = resource.network.main.meta.id ip_address = "10.50.0.10" aliases = ["web"] }
disk { destination = "/data" size = 20 }
volume { source = "./shared" destination = "/mnt/shared" read_only = true }
port { local = "8080" host = "8080" protocol = "tcp" open_in_browser = "/" }
port_range { range = "3000-3010" enable_host = true protocol = "tcp" }
health_check { timeout = "30s"
tcp { address = "localhost:8080" } }}Resource Structure
Section titled “Resource Structure”vm├─ config│ └─ arch├─ image (required)│ └─ name, username, password├─ resources│ └─ cpu, memory├─ environment├─ dns[]├─ startup_script├─ networking│ └─ network[] (repeatable)│ └─ id, ip_address, name, aliases, mac_address├─ storage│ ├─ disk[] (repeatable)│ │ └─ destination, size│ └─ volume[] (repeatable)│ └─ source, destination, type, read_only├─ port exposure│ ├─ port[] (repeatable)│ │ └─ local, host, protocol, open_in_browser│ └─ port_range[] (repeatable)│ └─ range, enable_host, protocol└─ monitoring └─ health_check ├─ timeout ├─ http[] (address, method, body, headers, success_codes) ├─ tcp[] (address) └─ exec[] (command, script, exit_code)Fields
Section titled “Fields”| Field | Required | Type | Description |
|---|---|---|---|
config | block | VM architecture configuration | |
image | ✓ | block | VM image configuration |
resources | block | CPU and memory allocation | |
environment | map(string) | Environment variables passed to the VM agent, startup script, and exec health checks | |
dns | list(string) | DNS server IP addresses used by the VM | |
startup_ | string | Script to run after the VM boots and the agent is reachable | |
network | block | Network attachments (repeatable) | |
disk | block | Additional VM disks (repeatable) | |
volume | block | Host directory shares attached to the VM (repeatable) | |
port | block | Port mappings (repeatable) | |
port_ | block | Port range mappings (repeatable) | |
health_ | block | VM health check |
Config Configuration
Section titled “Config Configuration”vm -> config
Configures VM runtime details.
| Field | Required | Type | Description |
|---|---|---|---|
arch | string | CPU architecture. Defaults to “x86_64”. Supported values are “x86_64” and “aarch64”. |
Image Configuration
Section titled “Image Configuration”vm -> image
Configures the VM image to boot.
| Field | Required | Type | Description |
|---|---|---|---|
name | ✓ | string | VM image name with optional tag |
username | string | Registry username for private images | |
password | string | Registry password or token for private images |
Resource Constraints
Section titled “Resource Constraints”vm -> resources
Configures CPU and memory allocation for the VM.
| Field | Required | Type | Description |
|---|---|---|---|
cpu | number | Number of virtual CPUs. Defaults to 1. | |
memory | number | Memory in MB. Defaults to 512. |
Network Configuration
Section titled “Network Configuration”vm -> network
Defines network attachments for the VM. This block can be repeated to attach the VM to multiple sandbox networks.
| Field | Required | Type | Description |
|---|---|---|---|
id | ✓ | reference to network | Reference to the ID of a network resource |
ip_ | string | Static IP address. Auto-assigned if not specified. | |
name | string | Optional name for this VM network attachment | |
aliases | list(string) | DNS aliases for the VM on the selected network | |
mac_ | string | MAC address for the VM network interface |
The first network attachment is used for the VM default route and DNS configuration. Attach the VM to a network when you need terminal access, startup scripts, exec health checks, service tabs, or communication with other sandbox resources.
Disk Configuration
Section titled “Disk Configuration”vm -> disk
Configures additional disks that are attached to the VM and mounted at boot. This block can be repeated to attach multiple disks.
| Field | Required | Type | Description |
|---|---|---|---|
destination | ✓ | string | Absolute path inside the VM where the disk is mounted |
size | ✓ | number | Disk size in GB |
Disk destinations must be absolute paths, must be unique, and cannot use reserved system paths such as /, /proc, /sys, /dev, /run, or /opt/instruqt.
Volume Configuration
Section titled “Volume Configuration”vm -> volume
Configures a host directory share attached to the VM. VM volumes are attached as guest-visible shares; mount or consume them from the guest according to your VM image and startup configuration.
| Field | Required | Type | Description |
|---|---|---|---|
source | ✓ | string | Host path or directory to share |
destination | ✓ | string | Intended path inside the VM |
type | string | Volume type | |
read_ | bool | Attach the share read-only. Defaults to false. |
Port Configuration
Section titled “Port Configuration”vm -> port
Defines port mappings between the VM and the host. This block can be repeated to expose multiple ports.
| Field | Required | Type | Description |
|---|---|---|---|
local | ✓ | string | Port the service listens on inside the VM |
host | string | Host port to bind. If omitted, Instruqt assigns a free host port. | |
protocol | string | Protocol: “tcp” or “udp”. Defaults to “tcp”. | |
open_ | string | Path to open in browser when a host port is defined |
Port Range Configuration
Section titled “Port Range Configuration”vm -> port_range
Defines port range mappings for exposing multiple consecutive ports. This block can be repeated for multiple port ranges.
| Field | Required | Type | Description |
|---|---|---|---|
range | ✓ | string | Port range, for example “3000-3010” |
enable_ | bool | Enable host port mapping. Defaults to false. | |
protocol | string | Protocol: “tcp” or “udp”. Defaults to “tcp”. |
Health Monitoring
Section titled “Health Monitoring”vm -> health_check
Configures health checks to monitor VM readiness and availability.
| Field | Required | Type | Description |
|---|---|---|---|
timeout | string | Health check timeout. Defaults to ”30s”. | |
http | block | HTTP health check (repeatable) | |
tcp | block | TCP health check (repeatable) | |
exec | block | Execute command health check (repeatable) |
HTTP Health Check
Section titled “HTTP Health Check”vm -> health_check -> http
| Field | Required | Type | Description |
|---|---|---|---|
address | ✓ | string | HTTP endpoint URL |
method | string | HTTP method. Defaults to “GET”. | |
body | string | Request body | |
headers | map(list(string)) | HTTP headers | |
success_ | list(number) | Expected success codes. Defaults to [200]. |
TCP Health Check
Section titled “TCP Health Check”vm -> health_check -> tcp
| Field | Required | Type | Description |
|---|---|---|---|
address | ✓ | string | TCP address to check |
Exec Health Check
Section titled “Exec Health Check”vm -> health_check -> exec
| Field | Required | Type | Description |
|---|---|---|---|
command | list(string) | Command to execute | |
script | string | Script to execute | |
exit_ | number | Expected exit code. Defaults to 0. |
Computed Attributes
Section titled “Computed Attributes”These attributes are set by the system after the VM is created:
| Field | Type | Description |
|---|---|---|
network[].assigned_address |
string | IP address assigned by the system |
port[].host |
string | Host port assigned by the system when omitted |
Default Values
Section titled “Default Values”The following defaults are applied during processing:
| Field | Default Value |
|---|---|
config.arch |
"x86_64" |
resources.cpu |
1 |
resources.memory |
512 |
health_check.timeout |
"30s" |
port.protocol |
"tcp" |
port_range.enable_host |
false |
port_range.protocol |
"tcp" |
Validation Rules
Section titled “Validation Rules”image.nameis required- If the
resourcesblock is set,cpuandmemorymust be greater than 0 - Disk
sizemust be greater than 0 - Disk
destinationmust be an absolute path, must be unique, and cannot use reserved system paths - Duplicate
network.idattachments are rejected - Port and port range values must parse as valid port numbers
- Startup scripts and exec health checks require the VM agent to be reachable, so the VM should be attached to a network
Examples
Section titled “Examples”Basic VM
Section titled “Basic VM”resource "vm" "ubuntu" { image { name = "ubuntu:24.04" }}VM with Network and Terminal Access
Section titled “VM with Network and Terminal Access”resource "network" "main" { subnet = "10.50.0.0/24"}
resource "vm" "devbox" { image { name = "ubuntu:24.04" }
resources { cpu = 2 memory = 2048 }
network { id = resource.network.main.meta.id ip_address = "10.50.0.10" }
startup_script = <<-EOF #!/bin/sh apt-get update apt-get install -y curl jq EOF}
resource "terminal" "devbox" { target = resource.vm.devbox shell = "/bin/bash"}VM with Disk and Service Tab
Section titled “VM with Disk and Service Tab”resource "network" "main" { subnet = "10.50.0.0/24"}
resource "vm" "web" { image { name = "ubuntu:24.04" }
disk { destination = "/var/lib/app" size = 20 }
port { local = "8080" host = "8080" }
network { id = resource.network.main.meta.id }
health_check { http { address = "http://localhost:8080/health" } }}
resource "service" "web" { target = resource.vm.web port = 8080}Best Practices
Section titled “Best Practices”- Choose the right compute type: Use VMs for full OS behavior and containers for lightweight application runtimes
- Attach a network for interactive labs: Terminal access, service tabs, startup scripts, and exec health checks depend on VM reachability
- Size resources deliberately: VMs need enough CPU and memory for the guest operating system and your lab workload
- Use explicit image tags: Pin images to stable versions for repeatable lab runs
- Make startup scripts idempotent: Startup scripts should handle reruns and partially completed setup safely
- Use disks for durable paths: Mount additional disks at application data paths and avoid reserved system paths
- Expose only needed ports: Map the smallest set of ports required for the learner experience