Provisioning on-demand macOS virtual machines with Jenkins and Anka Build for iOS CI

Guest Blog Post By Peter Wiesner, Senior Software Engineer @Skyscanner

Every year Apple releases a new version of Xcode. CI systems for iOS application development need to adopt it, so developers can take advantage of the new iOS features. CI systems using Anka Build have a head-start here. For folks not familiar with Anka Build, read more details here.

You only need to create a new tag for the current Anka macOS virtual machine with the new Xcode installed. Anka ships with features helping to automate this process.

In this blog post, I will show you how to do this. We will use the following solutions:

  • anka create to create the macOS virtual machine from a script
  • Jenkins pipeline to run the jobs on demand
  • anka run to execute batch commands on the virtual machines

About the prerequisites:

  • Jenkins with pipeline plugin installed
  • a mac with anka-create label connected to Jenkins. We will use this native node to create and provision the virtual machine
  • Anka Build package version 1.4 current release installed on the mac

Jenkins pipeline

Let’s create a Jenkins pipeline project with following script. The key tricks are:

  • use Jenkins parameters to provide configuration (Xcode version to install)
  • use a separate repo for the actual provisioning files
  • always save the state of the VM on pipeline failure so next iteration is faster
pipeline {

    agent none

    options {

        timeout(time: 240, unit: 'MINUTES')


    environment {

        // Provide credentials here (anka username/pwd, keychain passwords,
        for tool packages etc.)


parameters {

    //Provide mutable configuration for scripts (anka VM name, anka
    Xcode version)

string(name: 'ANKA_VM_NAME', defaultValue: 'anka_VM_node',
    description: 'Name of the Anka VM')


stages {

    stage("anka-create") {

        agent {

            node {

                // There is a native mac connected to Jenkins with this
                label 'anka-create'


        steps {



        post {

            always {

                // Create a vm that stores the state of the VM on exiting. When fixing
                this can speed up the process a lot

                sh ""

                if [\$(anka list | grep current_state_vm | wc - l) == 1]


                anka delete--yes current_state_vm


                anka stop\ $ANKA_VM_NAME

                anka clone - c\ $ANKA_VM_NAME current_state_vm

                if [\$(anka list | grep\ $ANKA_VM_NAME | wc - l) == 1]


                echo "Deleting Anka VM: \$ANKA_VM_NAME"

                anka delete--yes\ $ANKA_VM_NAME






def checkout_provisioning_scripts() {

    // It is useful to decouple the actual provisioning script from this
    pipeline script

    // Easy to do updates and helps reading the pipeline script

    // Clone the provisioning script from a GitHub repo

    timeout(15) {

        checkout([$class: 'GitSCM', branches: [
                [name: 'master']
            ], ,

            extensions: [
                [$class: 'CloneOption', depth: 1, noTags: false,
                    shallow: true, timeout: 30
            userRemoteConfigs: [
                [name: 'origin', refspec:
                    '+refs/heads/*:refs/remotes/origin/*', url: 'SSH_GIT_URL'


def create_task() {


    credentials.withAllCredentials {


        // Once we cloned the repository, print the environment variables
        to see
        if job parameters and variables are correctly passed to this task

        // comes from the repo

        sh ""


        sh. /



Creating the VM

The Jenkins pipeline calls out to a provision script. This is responsible to utilize anka for provisioning. The key tricks are:

  • collecting all necessary packages beforehand
  • allowing the script to use previously saved virtual machine as starting point (`anka create` can take up to 20 mins)

# Let's fail on error

set -e

# Retrieve macOS installer and necessary packages

# It's beneficial to store them on a NAS that can be connected to the mac

# We can start the process with previous state of vm if we would like to

# This saves a lot of time

if [ "$START_FROM_BEGINNING" -eq 0 ]


#Create VM from the Installer on NAS

ANKA_DEFAULT_USER=$USER_NAME anka --debug create --ram-size $VM_RAM
--cpu-count $VM_CPU --disk-size $VM_DISK --app "$PATH_TO_OS_INSTALLER"

anka modify $ANKA_VM_NAME add port-forwarding --host-port 0 --guest-port
22 --protocol tcp ssh


#Clone VM

anka clone current_state_vm $ANKA_VM_NAME


# Iterate on the setup/install scripts

for file in $files_to_execute


# Run script as root

anka run --env $ANKA_VM_NAME sudo -E bash $file

# Run script as created anka user

#anka run --env $ANKA_VM_NAME sudo -E -H -u $USER_NAME bash $file


# Stop the VM after we are done, start it up and suspend it, so CI can use
the super fast start-up feature of Anka VMs.

anka stop -f $ANKA_VM_NAME

anka run $ANKA_VM_NAME ls

anka suspend $ANKA_VM_NAME

# Save the new baseline virtual machine

anka registry -a $REGISTRY_IP_ADDRESS push $ANKA_VM_NAME -t $ANKA_TAG

Installing necessary tools

The actual provisioning happens in the `for loop`, where we use `anka run`. These scripts install the tools like Xcode, Xcode CLI, Ruby, git or any packages. The content and order of the scripts are company/case specific, but let me list some general tricks. Keep in mind, when running the `anka run` command, the current working directory will be mounted to the VM and the files can be accessed with a relative path (sweet!).

Installing certificates

$P12_PATH contains the path to the exported p12 files location.

echo $USER_PWD | sudo -S security import $P12_PATH -k
"/Library/Keychains/System.keychain" -P "$P12_PASSWORD" -A

Installing Xcode CLI

$XCODE_CLI_PATH contains the path to the Xcode Command Line Tools package location.

MOUNTDIR=$(echo `hdiutil mount $XCODE_CLI_PATH | tail -1 | awk '{$1=$2="";
print $0}'` | xargs -0 echo)

echo $USER_PWD | sudo -S installer -pkg "${MOUNTDIR}/"*.pkg -target /
hdiutil unmount "${MOUNTDIR}"

Installing Xcode

You need to install the xcode-install gem for this. $XCODE_APP_VERSION contains the version number of the Xcode you want to install (like 10.0) $XCODE_REMOTE_URL is an URL from where the Xcode xip can be downloaded (it is worth to download it and upload to a private remote server to have bigger download speed).

xcversion install $XCODE_APP_VERSION --url="$XCODE_REMOTE_URL" --verbose

Share this post

Unlocking Superior macOS VM Network Performance: Introducing Anka's new networking mode for Apple Silicon
Large and complex enterprises using Anka have many different demands, and we have worked to continue to develop innovative technology to meet these demands. Enterprise infrastructure hardware is often on the cutting edge, and they need advanced capabilities...
Read More
Anka Cloud Gitlab Executor
Veertu’s Anka and the new Anka Cloud Gitlab Executor Veertu’s Anka is a suite of software tools built on the macOS virtualization platform. It enables the execution of single or multi-use macOS virtual machines (VMs) in a manner similar to Docker....
Read More
Real-Time CVE Scanning of your macOS Build Systems
It’s common that an organization’s macOS build system will download thousands, sometimes tens of thousands of third-party dependencies every hour. When building and testing iOS applications, it typically downloads and installs third-party...
Read More
The ONLY Fully Automated Apple Silicon macOS VM Creation Solution
Starting in Anka 3.1 we announced that Anka is now able to fully automate the macOS installation processes, disabling SIP, and enabling VNC — all previously manual steps users had to perform inside o the VM. At the time of writing this article,...
Read More
Scripting macOS UI User Actions With Anka Click
Starting in Anka 3.2, we’ve introduced a solution for scripting macOS UI user actions. You may ask, “Why would I want to do that?”. Well, often macOS configuration and applications do not have a CLI allowing you to perform certain actions...
Read More
Real-time, continuous scan of file downloads on macOS for security vulnerabilities
Today, we are announcing the Beta availability of the Mac Scan solution. Mac Scan software runs on macOS systems (bare metal, virtual, EC2 Mac) and scans downloads in real time for security vulnerabilities. There are multiple scenarios why you would...
Read More
Screen Shot 2022-10-17 at 10.13
Anka 3.1- Fully automated VM macOS installation & The Behavior-Driven macOS UI Automation Framework
We are very happy to announce the General Availability of Anka 3.1 for Apple Silicon / ARM macs. In this release, we are taking our approach to iOS CI automation one step further by introducing a Behavior-Driven macOS UI Automation Framework in Anka,...
Read More
Migrating from Anka on Intel to Anka on M1 Mac for iOS CI
In this blog, we will cover the key topics for migrating from Anka on Intel to Anka on M1/M2 Macs. Anka is an IaaC solution from Veertu to set up an agile Container like CI for iOS CI using macOS VMs. Anka for Intel uses Apple’s Hypervisor.Framework virtualization...
Read More
World's first Security Vulnerability scanner for EC2 Mac AMIs
We are excited to announce the General Availability of the world’s first security vulnerability scanner for EC2 Mac AMIs. EC2 Mac AMI Scan scans Intel and Apple Silicon macOS EC2 AMIs, detects security vulnerabilities in third-party packages, dependencies,...
Read More
It's time to migrate your iOS CI from ESXi Virtual Mac Infrastructure to native macOS Virtualization
When VMWare ESXi started officially supporting Apple macOS Virtualization on Mac hardware in late 2012, it opened the doors for the possibility of iOS development to move to a Linux-like, agile, scalable CI infrastructure. Soon enough, many iOS enterprise...
Read More