Templates and Snapshots
Use Templates and snapshots to create similar VMs quickly.
TLDR; Use VmTemplate
This pattern is recommended for most users, as it is simple and handles caching for you. Read on if you want to understand more about how caching works under the hood and the other ways to create it.
import { freestyle, VmTemplate } from "freestyle-sandboxes";
const template = new VmTemplate({
additionalFiles: {
"/tmp/hello-world.txt": {
content: "Hello World!"
}
}
});
// first time slow
const { vm } = await freestyle.vms.create({
template,
});
// second time fast
const { vm: vm2 } = await freestyle.vms.create({
template,
});What is a snapshot?
A snapshot is a saved state of a VM, including it's memory, that can be used to create new VMs with. Once a snapshot is created, it cannot be changed and will be replicated across our network as needed. There are 2 ways you can create a snapshot.
Snapshot a VM
You can call snapshot() on a VM whether it's running, suspended, or stopped.
Usually you want to create snapshots from running or suspended vms so that they
can be resumed quickly, but this isn't a requirement. Snapshotting a stopped VM
is also perfectly valid.
import { freestyle } from "freestyle-sandboxes";
const { vm } = await freestyle.vms.create();
await vm.fs.writeTextFile("/tmp/hello-world.txt", "Hello World!");
const { snapshotId } = await vm.snapshot();Note that if your goal is just to make copies of the current VM, you should probably use
vm.fork()which will create a new VM from the current state without creating a snapshot. This is much faster up front, but concurrency is limited since we cannot replicate a running VM across multiple physical hosts.
Create a snapshot declaratively
To create a declarative snapshot, you can use the VmTemplate class. This class
is very similar to the parameters you would pass to freestyle.vms.create(),
but instead of creating a VM directly, it creates a snapshot that can be used to
create VMs later. In the background, freestyle is creating a VM, applying the
template parameters, snapshotting it, and then deleting the VM.
const template = new VmTemplate({
additionalFiles: {
"/tmp/hello-world.txt": {
content: "Hello World!"
}
}
});
const { snapshotId } = await freestyle.vms.snapshots.ensure({
template,
});Note that calling snapshot on the same template multiple times will return the same snapshot id. This is because freestyle caches snapshots based on the template's configuration.
Create a VM from a snapshot
Once you have a snapshot, you can create new VMs from it by passing the
snapshotId to freestyle.vms.create().
const { vm } = await freestyle.vms.create({
snapshotId,
});Skip snapshotting and just use templates
Instead of creating a template, creating a snapshot from it, and then passing
the snapshot id to the vm, you can pass the template directly to
freestyle.vms.create(). This will automatically create the snapshot in the
background for you and cache it based on the template parameters.
const { vm } = await freestyle.vms.create({
template,
});With additional configuration
When creating a VM from a snapshot or template, you can still pass additional
configuration options to freestyle.vms.create(). These options will be applied
on top of the snapshot/template configuration. This additional config can be
applied whether or not the snapshot includes memory state. It will not cause the
vm to be rebooted.
const { vm } = await freestyle.vms.create({
template,
// snapshotId, // or snapshotId
additionalFiles: {
"/tmp/goodbye-world.txt": {
content: "Goodbye World!"
}
}
});Snapshots in Templates
When creating a template, you can also specify a snapshotId that this template will be built on top of.
const template = new VmTemplate({
snapshotId,
additionalFiles: {
"/tmp/hello-world.txt": {
content: "Hello World!"
}
}
});Templates in Templates
You can also put templates in templates to build layers of cache.
const templateLayerOne = new VmTemplate({
additionalFiles: {
"/tmp/hello-world.txt": {
content: "Hello World!"
}
}
});
const templateLayerTwo = new VmTemplate({
template: templateLayerOne,
additionalFiles: {
"/tmp/goodbye-world.txt": {
content: "Goodbye World!"
}
}
});