Play with Anka: Try to build a dock-like iOS CI environment


Containerization is convenient for service deploying and environment isolating. Docker is a popular one, for Linux. Docker also has a Mac version, but it only provides a Linux container environment, not macOS, which cannot be used for iOS project building. (Dock for mac just run a Linux virtual machine on mac, and use docker in it.)

For a simple point of view, containerization is just a disposable lighted-weighted virtual machine(VM). Traditional VM on mac like Parallel Desktop is not designed for this. Then Anka comes to me. Anka is from Veertu, which origins from lighted-weighted VM for macOS based on a native framework. Anka is officially positioned as a “macOS cloud for iOS CI and Devops”. It’s slightly different from what I want, a docker-like tool, which I can create system images and run disposable instances. (I’m also a beginner for docker)

This official document is not very clear. Here’s a simple Introduction.

Introduction to Anka

Anka Build

The first tool you will come across is Anka Build. It provides the core VM functionality and command line tool to create, run, manage VMs, like the ‘docker’ command for docker.

You can create your first VM with this command: (before that you should download the system installing app in App Store)

anka create --ram-size 4G --cpu-count 2 --disk-size 60G --app /Applications/Install\ macOS\ Mojave.app VM_NAME

then, run command in the VM named VM_NAME:

anka run VM_NAME whoami

this command will print anka, the default user for VM. This is the most docker-like part. The first time run anka run for a certain VM will take a while to start because under the hood is just a normal VM, which will take time to boot. The VM will keep running in the background, so the run command will execute instantly for the later times. You can use start / stop / suspend to manipulate the VM instance manually.

Anka run will automatically mount the current path into the VM, so it’s very convenient to feed the data. (You can specify a -n to disable it.)

As it just a normal VM, you can use anka view VM_NAME to open the GUI desktop of the VM.

Anka Registry

Anka Registry is just like a git server for git, which you can push your VM to the server, and others can pull. Before doing that, you should prepare the server. As anka is a new tool, you should create your own anka registry server. Typically, you should have a server machine, and just run the docker image of anka server. The detailed step is list in doc here, you should follow that carefully. (The Anka Registry and Anka Controller are 2 things, but installed by the script together.)

Add the registry server just like git repo add:

anka registry add MY_SERVER http://XX.XXX.XXX.XXX

Now you have the VM on your local machine, and use anka push VM_NAME to push to the server.

But wait! Where’s the commit step? It seems that anka has no standalone method to create an image, or say commit. Commit is done while pushing.

anka registry push VM_NAME [tag] -d [description]

If VM_NAME is the branch, the tag/description is just the commit title/description. You can use the anka registry list to list the remote VMs, but it only shows the VM names and the latest tag. The history is hidden. (In Anka Controller part, you can view the history on the server through a web page.)

If you push the VM with suspending state, it will save the state too. This means, when pulling down the VM from server, you’ll get a VM with suspending state. This state can boot up in a few seconds, which can speed up the first anka run. This is called INSTANT BOOT officially.

Just like git, anka will do incremental push and pull. If you open the VM and do some modifications, like install the Xcode, then stop the VM, you can push this state as another version of this VM. Behind this, anka seems to treat an image as a modification fo another image, and saves in separate files (~/Library/Application Support/Veertu/Anka). Even though, as it’s just a traditional VM, the uploading size is still too big. The bare system is about 15GB, additional 10+ GB for Xcode, and suspend state may take hundreds MB. Considering it’ll only be pulled once, it’s acceptable, but not delightful.

Anka Controller

There’s still another part of anka: the Anka Controller. It’s the supervisor of anka cloud. It accepts commands from RESTful API, deploys the image from Registry to the Node (read machine) and run VM with input script. It also provides a ready-to-use Jenkins plugin to fast integration. Anka controller also provides a dashboard web page. This url describes the detail functionalities.

Get a Disposable Environment

The anka tool didn’t provide explicit guidance for creating a disposable environment, like running an instance for a docker image. All we dealing with are about traditional VM (except the anka run). There’s no concept of image for users. It has git-like management, but no git reset.

Finally, I find the ‘anka clone’ command, which can meet our requirement, in a not-so-direct way.

First, prepare your VM and push it to the registry, it works as an image. Then pull the VM on the real machine on which it will run. Clone it with anka clone VM_NAME new_name, which will be finished instantly as it’s only a shadow. Run your job with anka run new_name then delete the new VM when it finished.

Performance Test

I compiled the ‘ComponentKit’ pod with xcodebuild on my hackintosh (9900K (8 cores 16 threads) 32G RAM)

VM:8core 16thread 16G RAM:  79s 67s 70s, avg 72 
Native: 53s 54s 54s, avg 54s

Run 2 builds simultaneously. For VM, just start 2 VMs simultaneously.
VM:8core 8thread 16G RAM:  130s 127s 128s, avg 128
Native: 117s 99s 84s 87s, avg 96s

Both 2 test result in 33% slower for VM.

Discussion

The result seems frustrated. Except for the stability, the constant problem we face about iOS CI is the slow building. We bought the expensive but not-deserved Mac Pro for compiling one or two years ago as there’s no better machine. Every job takes dozens of minutes is a normal thing, and the engineer can only wait to continue their job sometimes. 33% slow is kinda unacceptable.

There are other problems. A gradual evolutional way is what I needed: run only one VM once on a real machine. A fixed VM config may limit the performance, e.g. set a 2 core cpu for VM on an 8 core cpu machine. Although you can modify the VM before running the command with the host machine’s environment like this,

anka modify VM_NAME set cpu 8
anka modify VM_NAME set ram 16G

but it requires the VM to be stopped, then you lose the instant boot. Other small problems exist like the VM is corrupt when doesn’t be shut down safely.

Further, anka is kind of pricey. The official site didn’t mention the price of business license. But someone in twitter said it cost hundreds of dollars per cpu core per year. It is even more expensive than the host hardware.

In conclusion, anka tries to provide dock-like management for macOS environment. It meets our basic needs, but doesn’t finish it very well because of the traditional VM technology background. I may drop this solution as the performance loss and high price.