VM clones, tags, and templates

Local tags, cloning, and how VM templates relate to Anka Build Cloud

Terms

TermMeaning
VMA macOS virtual machine on the host (anka list)
TagA named snapshot/version of a VM (vanilla, v2, and similar). Shown as name (tag) in anka list
TemplateA VM (or registry object) used as the basis for clones and CI images. In Build Cloud, templates live in the Registry

Clones share disk layers with the source only if the source has a tag. Create a local tag with anka push --local --tag {name} before cloning, or push to the Anka Registry with anka registry push.

Disk optimization (Anka 3)

In Anka 2, clones shared underlying image files automatically. In Anka 3, sharing requires a tag on the source before you clone. Use anka push --local or anka registry push to create that tag. Clones never modify the source VM state.

> anka push --help
usage: push [options] vmid [remote]

   Push a VM to the registry

arguments:
  vmid                     VM to push
  remote                   Sets an alternate registry (name or URL)

options:
  -t,--tag <val>           Set the tag name to push (mandatory)
  -v,--remote-vm <val>     Registry template to push the tag onto
  -d,--description <val>   Set textual description of the tag
  -f,--force               Forcefully push, regardless of a tag already existing
  -l,--local               Commit the template without pushing it to the Registry
  -s,--shallow             Include all the changes of an older tags
  -q,--quiet               Do not show progress
❯ anka list
+--------+--------------------------------------+----------------------+---------+
| name   | uuid                                 | creation_date        | status  |
+--------+--------------------------------------+----------------------+---------+
| 12.0.1 | 002b73b6-dc99-4d6b-8f68-6067a3a66d73 | Nov 19 08:02:33 2021 | stopped |
+--------+--------------------------------------+----------------------+---------+

❯ anka push --local --tag vanilla 12.0.1

❯ anka list
+------------------+--------------------------------------+----------------------+---------+
| name             | uuid                                 | creation_date        | status  |
+------------------+--------------------------------------+----------------------+---------+
| 12.0.1 (vanilla) | 002b73b6-dc99-4d6b-8f68-6067a3a66d73 | Nov 19 08:02:33 2021 | stopped |
+------------------+--------------------------------------+----------------------+---------+
Clones use little disk until started. On start, Anka adds a writable layer on top of shared layers; guest changes go there.

Switch between local tags:

> anka pull --help
usage: pull [options] vmid [remote]

   Pull a VM template from the registry

arguments:
  vmid                     VM to pull
  remote                   Sets an alternate registry (name or URL)

options:
  -t,--tag <val>           Pull the particular tag (latest if not specfied)
  -l,--local               Checkout (make it current) local tag
  --fetch-only             Download tag without checkout
  -s,--shrink              Delete other local tags to optimize disk usage
  --check-download-size    Get the tag size only
  -q,--quiet               Do not show progress

Cloning

Create a new VM from a source and its current state:

> anka clone --help
usage: clone [options] vmid [name...]

   Clone a VM

arguments:
  vmid                     VM to clone
  name                     New VM name(s)

options:
  -c,--copy                Create an independent copy
  -t,--tag <val>           Clone particular VM tag (should be available locally)
  1. Shallow clone: anka clone {source} {dest} — new name and UUID; shares layers if the source has a tag.
  2. Full clone: anka clone --copy {source} {dest} — merges layers into a standalone copy (often uses more disk; cannot share layers with other VMs).
❯ anka clone 12.0.1 12.0.1-xcode13
6070ee59-6c16-4c93-ba7a-122b66b1472a

VM templates

Once a VM has been tagged, it becomes a “VM Template”. The Tag can be thought of as a commit in a git repository. The commit will always be there, even if you were to later on remove the code you added to the repo/codebase in that specific commit. Therefore, the VM Template Tag and anything created from it will always be there, even if you were to later on remove the data from the VM and create a new tag. This is important to consider when using the Anka Build Cloud Registry.

Clones are not automatically tagged.
❯ anka list | grep test
| test (v1)                                 | ff06aa5b-0825-4f86-b5d0-c1cdb39fcedf | Jan 25 13:15:10 2022 | stopped |

❯ anka clone --tag v1 test test3                  
8a4e0033-29b4-4c29-8a0c-51fa53093d1c

❯ anka list | grep test         
| test3                                     | 8a4e0033-29b4-4c29-8a0c-51fa53093d1c | Feb 3 12:01:34 2022  | stopped |
| test (v1)                                 | ff06aa5b-0825-4f86-b5d0-c1cdb39fcedf | Jan 25 13:15:10 2022 | stopped |

In the above example, test3 is a shallow clone of test and has a new UUID. The underlying layers are shared with test and will be used when test3 is started.

Our Recommendation for Templates

If you’re managing multiple templates for multiple teams and projects, you want to share as many underlying layers in the hierarchy of VM Templates as possible. To do this, we typically recommend:

  1. Create a VM with macOS 13.0.1 and also name it that. The, push or locally tag it as vanilla.
  2. Start the 13.0.1 VM and add the dependencies that everyone would need (typically git and brew). Stop the VM and modify to add port forwarding. Push/locally tag this as brew+git+portforwarding22.
  3. Clone from 13.0.1 (with the brew+git+portforwarding22 tag) and create 13.0.1-xcode14.1. Start it and install Xcode. Stop it and push it with any tag name. I use v1 usually.
  4. Clone from 13.0.1-xcode14.1 and create 13.0.1-xcode14.1-{projectNameHere}-v1 which you’ll install all of that projects dependencies in and push with any tag name.

This allows everything to share the underlying layers that are the same (since they’re all cloned from 13.0.1) and optimize disk space. You can then just pull the last VM template in the hierarchy and create a new one when needed, telling the teams to point to the new one when ready.

If it helps, here is it visually:

13.0.1 (stopped)  | 
                  | -> clone -> 13.0.1-xcode14.1 (stopped) |
                  |                                        | -> clone -> 13.0.1-xcode14.1-project1-v1 (with fastlane-v1.X) (suspended)
                  |                                        | -> clone -> 13.0.1-xcode14.1-project2-v1 (with fastlane-v2.X) (suspended)
                  |                                        | -> clone -> 13.0.1-xcode14.1-project2-v2 (with fastlane-v2.X) (suspended)
                  |
                  | -> clone -> 13.0.1-xcode13.4.1 (stopped) -> clone -> 13.0.1-xcode13.4.1-project3-v1 (suspended)
ARM USERS: Suspending will currently stop the VM. It will show as suspended, regardless.
Important: When you tag a VM you cannot remove the data from the layers that make up the VM unless you do a full clone. When you go to shallow clone a VM/create a new tag, it may be beneficial to start from the tag/layers before you last made changes so that you don’t include the data/layers and disk usage with the new tag you’re creating.

Push templates to the registry: Registry VM Templates and Tags.