Skip to content

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.

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.

resource "vm" "ubuntu" {
image {
name = "ubuntu:24.04"
}
}
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"
}
}
}
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)
FieldRequiredTypeDescription
configblockVM architecture configuration
imageblockVM image configuration
resourcesblockCPU and memory allocation
environmentmap(string)Environment variables passed to the VM agent, startup script, and exec health checks
dnslist(string)DNS server IP addresses used by the VM
startup_scriptstringScript to run after the VM boots and the agent is reachable
networkblockNetwork attachments (repeatable)
diskblockAdditional VM disks (repeatable)
volumeblockHost directory shares attached to the VM (repeatable)
portblockPort mappings (repeatable)
port_rangeblockPort range mappings (repeatable)
health_checkblockVM health check

vm -> config

Configures VM runtime details.

FieldRequiredTypeDescription
archstringCPU architecture. Defaults to “x86_64”. Supported values are “x86_64” and “aarch64”.

vm -> image

Configures the VM image to boot.

FieldRequiredTypeDescription
namestringVM image name with optional tag
usernamestringRegistry username for private images
passwordstringRegistry password or token for private images

vm -> resources

Configures CPU and memory allocation for the VM.

FieldRequiredTypeDescription
cpunumberNumber of virtual CPUs. Defaults to 1.
memorynumberMemory in MB. Defaults to 512.

vm -> network

Defines network attachments for the VM. This block can be repeated to attach the VM to multiple sandbox networks.

FieldRequiredTypeDescription
idreference to networkReference to the ID of a network resource
ip_addressstringStatic IP address. Auto-assigned if not specified.
namestringOptional name for this VM network attachment
aliaseslist(string)DNS aliases for the VM on the selected network
mac_addressstringMAC 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.

vm -> disk

Configures additional disks that are attached to the VM and mounted at boot. This block can be repeated to attach multiple disks.

FieldRequiredTypeDescription
destinationstringAbsolute path inside the VM where the disk is mounted
sizenumberDisk 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.

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.

FieldRequiredTypeDescription
sourcestringHost path or directory to share
destinationstringIntended path inside the VM
typestringVolume type
read_onlyboolAttach the share read-only. Defaults to false.

vm -> port

Defines port mappings between the VM and the host. This block can be repeated to expose multiple ports.

FieldRequiredTypeDescription
localstringPort the service listens on inside the VM
hoststringHost port to bind. If omitted, Instruqt assigns a free host port.
protocolstringProtocol: “tcp” or “udp”. Defaults to “tcp”.
open_in_browserstringPath to open in browser when a host port is defined

vm -> port_range

Defines port range mappings for exposing multiple consecutive ports. This block can be repeated for multiple port ranges.

FieldRequiredTypeDescription
rangestringPort range, for example “3000-3010”
enable_hostboolEnable host port mapping. Defaults to false.
protocolstringProtocol: “tcp” or “udp”. Defaults to “tcp”.

vm -> health_check

Configures health checks to monitor VM readiness and availability.

FieldRequiredTypeDescription
timeoutstringHealth check timeout. Defaults to ”30s”.
httpblockHTTP health check (repeatable)
tcpblockTCP health check (repeatable)
execblockExecute command health check (repeatable)

vm -> health_check -> http

FieldRequiredTypeDescription
addressstringHTTP endpoint URL
methodstringHTTP method. Defaults to “GET”.
bodystringRequest body
headersmap(list(string))HTTP headers
success_codeslist(number)Expected success codes. Defaults to [200].

vm -> health_check -> tcp

FieldRequiredTypeDescription
addressstringTCP address to check

vm -> health_check -> exec

FieldRequiredTypeDescription
commandlist(string)Command to execute
scriptstringScript to execute
exit_codenumberExpected exit code. Defaults to 0.

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

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"
  • image.name is required
  • If the resources block is set, cpu and memory must be greater than 0
  • Disk size must be greater than 0
  • Disk destination must be an absolute path, must be unique, and cannot use reserved system paths
  • Duplicate network.id attachments 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
resource "vm" "ubuntu" {
image {
name = "ubuntu:24.04"
}
}
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"
}
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
}
  1. Choose the right compute type: Use VMs for full OS behavior and containers for lightweight application runtimes
  2. Attach a network for interactive labs: Terminal access, service tabs, startup scripts, and exec health checks depend on VM reachability
  3. Size resources deliberately: VMs need enough CPU and memory for the guest operating system and your lab workload
  4. Use explicit image tags: Pin images to stable versions for repeatable lab runs
  5. Make startup scripts idempotent: Startup scripts should handle reruns and partially completed setup safely
  6. Use disks for durable paths: Mount additional disks at application data paths and avoid reserved system paths
  7. Expose only needed ports: Map the smallest set of ports required for the learner experience