Creating your first VM

Step by step on how to create your first VM
This guide, and the commands inside it, must be run as the non-root user on the system. Anka VMs run under a specific user environment. At the moment there is no way to open the Anka Viewer window, which is required for VM preparation, if the VM exists under the root user space.
It’s important to understand that the anka CLI, VM creation, modification, etc, is all done from your current user. You can use the Anka Build Cloud Registry to move VMs between users and even hosts.
Starting in Anka 3.1, manual installation of macOS is no longer required. Existing users can expect a similar experience as Intel VM creation.
Rosetta can be installed and used inside of the VM.

Prerequisites

  1. You’ve installed the Anka Virtualization package.
  2. The host you wish to use for running Anka VMs is using Apple processors and not Intel.
  3. The host you wish to use has Monterey (>= 12.0) installed.
  4. The host you wish to use has networking (requirement of Apple Virtualization.Framework) and access to the internet.

Create your first VM

You have two methods of creating your Anka VMs. We will describe both in this guide, but you only really need to choose one.

  1. With the anka create command (recommended).
  2. With the Anka.app UI.

Supported VM macOS versions

Anka VM Templates support the following macOS versions:

Version NumberVersion Name
13.xmacOS Ventura
12.xmacOS Monterey

Creating 13.x VMs on Monterey (12.x) requires that Xcode >= 14.0.1 is installed. This is a requirement from Apple at the moment.

There is also a rare problem where your Xcode is not fully set up and still creates problems, regardless of being on Ventura. Be sure to run the following:

sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
for PKG in $(/bin/ls /Applications/Xcode.app/Contents/Resources/Packages/*.pkg); do
    sudo /usr/sbin/installer -pkg "$PKG" -target /
done
Apple’s .app installer files are currently not supported on arm. Instead, you’ll need to obtain .ipsw files.

Using the Anka CLI

> anka create --help
usage: create [options] [name] [version]

   Creates a VM Template

arguments:
  name                     VM name
  version                  macOS version to install (use 'latest' to install the latest version)

options:
  -m,--ram-size <val>      Specify the VM RAM size (supported suffixes: T|G|M|K)
  -c,--cpu-count <val>     Specify the number of vCPU cores for the VM (3 or more is recommended)
  -d,--disk-size <val>     Specify the VM disk size (supported suffixes: T|G|M|K)
  --no-setup               Do not perform automated macOS setup
  -q,--quiet               Do not show progress
  -l,--list                List available macOS versions to install
❯ anka create -a latest 12.2.0-arm
Installing UniversalMac_12.1_21C52_Restore.ipsw...
######################################################################## 100.0%
00c44c30-174a-4266-8833-89d6975754bd
The ipsw will be downloaded into img_lib_dir. You can find the location of this directory with anka config img_lib_dir. These (and other temporary) files can be deleted with anka delete --cache.
  • We recommend naming your initial VM after the version of macOS.

  • Remember that VM templates are created under a specific user and will not be available to other users.

  • 2vCPUs is not enough and will cause instability inside of the VM. VCPUs are determined by taking the physical performance cores and multiplying by 2. This means you can set the CPU on creation for an M1 mini with 4 physical perf cores to anka create --cpu-count 4, and run two VMs per host (8vCPUs available). However, RAM, DISK, and CPU are all set from the defaults under the Anka configuration:

    ❯ anka config | grep default
    | default_disk                | 137438953472                                                                      |
    | default_nvcpu               | 4                                                                                 |
    | default_ram                 | 4294967296                                                                        |
    

With anka create, we will automatically set up macOS, create user: anka with password: admin, disable SIP, and enable VNC for you. This is different from the UI creation tool (see below), which still requires manual macOS installation.

IPSW vs .app installers

While we recommend you use anka create -a latest to automatically download the latest macOS version to install into the VM, you can bring your own IPSW file which is very similar to how Anka 2 works with .app installers.

There are multiple ways to obtain IPSW files. Apple provides these through their updates.cdn-apple.com site. You can usually find the official links to the version you want with your preferred search engine. Alternatively, you can use ipsw.me to identify and retrieve your desired IPSW file.


Using the Anka UI

  1. Click on Create new VM.
  2. LEAVE INSTALLER BLANK and click on Options to set any non-default values you want.
    Leaving the installer blank will automatically target the latest macOS version, pulling the IPSW file from the official Apple CDN (updates.cdn-apple.com). You can use your own IPSW file with the Anka CLI instead.
    installer with pkg
  3. Be patient while it’s creating.

Once the VM is created, you will see it on the sidebar – Hooray!

ui with vm in the sidebar list

Start the VM and finish the macOS install

> anka start --help
usage: start [options] vmid

   Start or resume a VM

arguments:
  vmid                     VM to start

options:
  -f,--force               Start VM with minimum checks
  -q,--quiet               Minimize output
  -v,--view                Open VM in an Anka window
  -u,--update-addons       Start in (auto)update mode

You can start the VM in Recovery Mode with ANKA_START_MODE=2:

ANKA_START_MODE=2 anka start 12.6
For our addons to install and enable autologin properly, you need to create the VM user as username: anka and password: admin. If you decide to use your own username and password, you will need to manually enable autologin for the user.
  1. You’ll need to start the VM with anka start -uv to launch the viewer.
anka view does not currently work post-start unless you started it with -v.
sudo anka view as a normal user is not possible yet. You’ll need to ensure that VNC is enabled to access VMs running under sudo.
  1. Once inside the Anka Viewer/VM, finish the macOS installation and be sure to install the addons package through the disk we mounted with -u.

mounted addons

  1. Reboot the VM.

Disable SIP in Recovery Mode (versions <= 3.0.1)

SIP is only enabled for VMs created in the Anka App’s UI. These instructions are irrelevant for VMs created with anka create.

With SIP enabled, there are two main issues you’ll find when running VMs:

  1. User or command executions can hang due to a “allowed to access” dialog in the VM’s UI. It requires VNC access and manual intervention to get around (no commands to disable this protection feature).
  2. Apple’s syspolicyd will notice applications and processes running for the first time and consume a lot of CPU and RAM trying to scan them.

In order to disable SIP, you need to first launch the VM in recovery mode.

recovery-mode

Then, you launch the Terminal application and execute csrutil disable. Once executed and after confirmation that the command worked, you can stop the VM. On next boot, SIP will be disabled.


Optimizing your VM

It’s recommended that you disable Spotlight and CoreDuetD inside of the VM to eliminate services that are known to need high CPU:

sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.coreduetd.osx.plist
sudo defaults write ~/.Spotlight-V100/VolumeConfiguration.plist Exclusions -array "/Volumes"
sudo defaults write ~/.Spotlight-V100/VolumeConfiguration.plist Exclusions -array "/Network"
sudo killall mds || true
sleep 60
sudo mdutil -a -i off /
sudo mdutil -a -i off
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.metadata.mds.plist || true
sudo rm -rf /.Spotlight-V100/*

Listing available VMs in the CLI

❯ anka list                        
+----------------------+--------------------------------------+---------------------+---------+
| name                 | uuid                                 | creation_date       | status  |
+----------------------+--------------------------------------+---------------------+---------+
| 12.2.0-arm (vanilla) | a6f24306-2af7-45ed-9d70-3a3c1ee7f03a | Jan 6 12:34:52 2022 | stopped |
+----------------------+--------------------------------------+---------------------+---------+
| test_vm1             | 565e47ce-a9f9-4ac8-81bc-645d48473de1 | Jan 6 12:34:52 2022 | stopped |
+----------------------+--------------------------------------+---------------------+---------+

❯ anka --machine-readable list | jq
{
  "status": "OK",
  "body": [
    {
      "name": "12.2.0-arm",
      "uuid": "a6f24306-2af7-45ed-9d70-3a3c1ee7f03a",
      "creation_date": "2022-01-06T12:34:52Z",
      "version": "vanilla",
      "status": "stopped"
    },
    {
      "name": "test_vm1",
      "uuid": "565e47ce-a9f9-4ac8-81bc-645d48473de1",
      "creation_date": "2022-01-06T12:34:52Z",
      "status": "stopped"
    }
  ]
}

❯ anka --machine-readable list --field name --field version | jq
{
  "status": "OK",
  "body": [
    {
      "name": "12.2.0-arm",
      "version": "vanilla"
    },
    {
      "name": "test_vm1"
    }
  ]
}

Deleting a VM

Using the Anka UI

edit menu delete

Using the Anka CLI

❯ anka delete test
are you sure you want to delete vm 77f33f4a-75c3-47aa-b3f6-b99e7cdac001 test [y/N]:

VM Clones

Disk Optimization

Customers coming from Anka 2 will know that when you clone an untagged VM, it will share the underlying VM image files between the two. However, this is not the case for Anka 3. As of right now, sharing of the underlying VM image files between a clone and its source requires first creating a tag for the source before you clone. You can do this with anka push --local, or just a regular anka push if you’ve got a running Anka Build Cloud Registry.

Don’t worry, clones will not have access to change the original source VM.
> anka push --help
usage: push [options] vmid [remote]

   Push a VM to the registry

arguments:
  vmid                     VM to push
  remote                   Sets an alternate registry

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 |
+------------------+--------------------------------------+----------------------+---------+

The above example shows the tag “vanilla” does not exist locally until we execute the anka push --local.

Cloned VMs will use a trivial amount of disk space until you start them. Once started, an empty image is created and connected on top of existing images and any changes to or in macOS are then added to it.

To switch between tags locally, you can use the anka pull --local --tag {targetTagname} {VMName} command:

> 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

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

You can easily create VM clones from a source VM and its current state using anka clone:

> 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)
❯ anka list
+--------+--------------------------------------+----------------------+---------+
| name   | uuid                                 | creation_date        | status  |
+--------+--------------------------------------+----------------------+---------+
| 12.0.1 | e65a072f-0d4f-450b-964d-2be8d0d32c13 | Nov 19 08:02:33 2021 | stopped |
+--------+--------------------------------------+----------------------+---------+


❯ anka clone 12.0.1 12.0.1-xcode13
6070ee59-6c16-4c93-ba7a-122b66b1472a

❯ anka list
+----------------+--------------------------------------+----------------------+---------+
| name           | uuid                                 | creation_date        | status  |
+----------------+--------------------------------------+----------------------+---------+
| 12.0.1         | e65a072f-0d4f-450b-964d-2be8d0d32c13 | Nov 19 08:02:33 2021 | stopped |
+----------------+--------------------------------------+----------------------+---------+
| 12.0.1-xcode13 | 6070ee59-6c16-4c93-ba7a-122b66b1472a | Nov 19 08:02:33 2021 | stopped |
+----------------+--------------------------------------+----------------------+---------+

VM Templates

Once a VM has been tagged, it becomes a “VM Template”. The VM template+tag’s state cannot be permanently modified unless you create a new tag, post-changes. This is very reminiscent of how git commit works. You can execute comands and modify the state of the VM after tagging it, but it will not save the changes to the existing template+tag. This is important to consider when using the Anka Build Cloud Registry since it will only push the state of the VM when the tag was created, not after.

In summary, when cloning a tagged VM you have two options:

  1. Clone from the current VM state, regardless of the state when it was tagged (anka clone {source} {clone}).
  2. Clone the state of a VM template/tag by targetting the tag by name (anka clone --tag {tagName} {source} {clone}), regardless of what has been done to it since tagging.
The clone is 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 |

What do we recommend?

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

  1. Create a VM with 13.0.1 and also name it that. The, push/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 this as a new tag called 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 (since they’re all cloned from 13.0.1) that are the same 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)

What’s next?