Xcode Server + Ansible: Scalable and Programmable iOS CI/CD Infrastructure

Published by Shashikant Jagtap on

One of the complaints about Xcode Server is it’s not scalable to be used as large-scale or enterprise level. However, if you have skills to understand and manage an infrastructure for iOS deployment then scalability can be easily achieved for small, medium or large iOS teams using the mixture of iOS and DevOps toolkit. We have achieved it in the past in my previous role at Photobox Group using the combination of tools Ansible  + Fastlane + TeamCity. You can read my blog post on Moonpig Engineering blog here to learn how we achieved this.

In this post, we will see how learning a little bit of DevOps tools like Ansible and Apple’s CI solution Xcode Server can help to manage large-scale iOS CI/CD infrastructure without any pain.

Background

Continuous Integration practices for iOS development aren’t great as compared to the web world because of some unique challenges specific to iOS Development. It’s essential to understand the entire iOS ecosystem to setup and manage CI/CD infrastructure for the team. Some Senior/Lead iOS developers or iOS Tech Architects/Lead are great at the understanding whole stack of Apple developer tools, technologies and infrastructure and implementing in their projects but most of the iOS developers in the industry at the moment are just iOS Developers, they are good at writing Swift or Objective-C to build UI for application inside the Xcode. However, when it comes to understanding the infrastructure, they literally suck. They don’t properly understand the underlying tools and technologies used by Xcode under the hood and that’s why they became totally incapable of setup or manage CI/CD practices for iOS apps. As an effect of these, they always have to depend on local Xcode or someone from DevOps team to manage all infrastructure stack for them or CI/CD is handled by highly expensive third-party services. It means developers are not full stack and do not understand their own tools and technologies. Unfortunately, the world of iOS development full of these kinds of amateurs and half-arsed developers. Continuous Integration won’t be successful without having skilled engineers in the team. In my previous post, I wrote about top 5 reasons for CI failures. Those are Wrong Selection of CI server, CI Amature Engineers, Lack of Infrastructure as Code, Poor Quality Build Servers and Lack of Support from the team.

iOS Infrastructure Automation Challenges

On top of iOS engineers inability to understand entire iOS ecosystem, there are some traditional challenges existed in automation of iOS ecosystem. Some of them imposed by Apple’s proprietary software and others are due to lack of tooling to automate iOS and macOS infrastructure. Some of the common challenges are

  • Lack of Configuration Management tool that can be used to automate Infrastructure. Chef, Ansible and Puppet are not designed to work with macOS servers.
  • Lack of official Package Management system to provision and automate software installation. We have to use third party solutions like HomeBrew
  • Lack of official dependency management tools. We have to Carthage or Cocoapods to manage dependencies. Swift Package Manager is not ready to use with iOS.
  • Lack of official build tool. We have to use tools like Fastlane to automate iOS development tasks.

As a result of these challenges, nobody wanted to spend the time to explore the clean and automated solution to setup iOS Infrastructure for smooth Continuous Delivery, which results in following situations.

  • Manual setup of CI Servers which take days of engineers to get things working on all build servers
  • Flaky build automation which produced inconsistent results
  • The software configuration on local and build machines are different
  • Continuous Integration is managed by the third-party provider and needs to contact them in case of build errors.
  • Team loose trust on CI start using the local machine for testing and release.

These symptoms are obstacles to the best application development practices. We can solve some of these issues by knowing a little bit of configuration management tools and proper continuous integration tools. Now, we will see how the combination of Xcode Server and Ansible can help to set up large-scale continuous integration and manage it effectively.

Xcode Server

Xcode Server is native Continuous Integration service developed by Apple. Xcode Server is one of the easiest ways to get started with Continuous Integration for iOS applications. It just needs Xcode installation and permission to Apple developer portal on macOS servers. If you use other solutions like Jenkins, TeamCity etc you will need to install other dependencies like Java and other related software which are nothing to do with iOS development. Apple still has old documentation for the Xcode Server at the time of writing this post but I wrote the setup instruction in my previous blog post here. So In order to set up Continuous Integration Server i.e CI we just need to install following on build machines.

  • Xcode
  • Xcode Command Line tools
  • macOS Default settings
  • Ruby and Homebrew (Optional)

We can manually install that software on each machine but it will time consuming if we have multiple macOS machines. We need to make sure that Xcode and other tool versions are consistent on all the servers. Now, we need to have configuration management to manage servers and software versions on those servers.

Provisioning Xcode Server with Ansible

There are various configuration management tools exist in the market like Chef, Puppet and Salt but Ansible is very easy to learn and use. Although Ansible is designed for Linux, there are enough modules that can be used with macOS as well. This is not Ansible tutorial but you need to read a bit of documentation to get started with Ansible here.

In order to provision Xcode Server, we need following things

  • Xcode .xip file downloaded from Apple Developer Portal
  • Ansible installed on remote macOS machine then Ansible will ssh into different macOS and install all available software.

Additionally, we can install other tools like Ruby, Homebrew using Ansible if needed.

Provisioning Xcode Installation

In order to install Xcode, we need to have .xip file downloaded from Apple Developer Portal and put it on the Ansible remote machine to copy over to ssh machines. There are various other things to be installed as part of the Xcode installation

  • Archive XIP file and move Xcode app to /Applications
  • Accept Licence agreement
  • Install Xcode Command Line tools and other mobile development packages
  • Enable developer tools and install additional components
  • Set Xcode Developer directory.

We can achieve all these tasks using Ansible.

Note that, The code above is the example of Ansible task,  we have to set up some variables to configure users and directories.

Provisioning Xcode Server

Now that, we can install Xcode as part of the task mentioned above. Next thing is to control the Xcode Server using Ansible. Xcode Server has command line tools xcscontrol  to manage the Xcode Server. We can start, stop reset, restart Xcode Server using this utility.  We can write Ansible task something like this:

With this simple configuration, we can easily manage Xcode Servers on multiple macOS servers.

Xcode Server: Ansible Role

I have created Ansible role for Xcode Server and published to Ansible Galaxy. You can find this role here

This role is very configurable and can be used for setting up multiple macOS servers as per your need. You can find detailed information on README file.

You can see all the variables used for this role and turn then ON/OFF or set as per your needs. You can optionally setup Ruby and Homebrew if needed.

How to use Xcode Server Ansible Role

Imagine, you have fresh Mac with fresh macOS installed. You can set up all your Xcode Server for CI by creating Playbook for this role. You can setup config variables as per your need. Assuming you have installed Ansible, we can download the role by running command

Now that, we have to create our own playbook for this role by setting variables, We can use default variables here. Now make a new directory called xcode_server   and create files directory and xcs_playbook.yml file.

Now pace your Xcode_9.x.xip  file inside the files directory and  insert following in the playbook file :

Change ansible_ssh_user  and xcode_server_user  with your username and Feel free to set variables as per your need. You can also specify your inventory to enable this playbook to run on multiple hosts. Now execute this playbook using the following command:

$ ansible-playbook xcs_playbook.yml

Watch your mac Mini servers getting setup with Xcode Server for iOS Continuous Integration.

When To Use Xcode Server and Ansible

There are situations when we want to run Ansible playbook on servers, some common situations are

  • New Xcode Versions to be installed
  • Reset the Rebuild CI environment after regular interval
  • Clean up environment to fix code signing issues
  • Reset server to save disk space

Ideally, we should run Ansible playbook regularly to check if anything changed.

Benefits

Some of the benefits of using configuration management tools with Xcode Server are

  • Consistent setup all across the servers
  • Infrastructure as a code
  • Destroy and Build CI servers whenever needed
  • Save manual hours of engineers setting up CI server machine
  • Eliminate cost of expensive third party CI services
  • No need to have dedicated DevOps resources to manage iOS CI/CD infrastructure
  • Understanding of iOS ecosystem and confidence to deal with any issues
  • No need to use third-party build automation tools like Fastlane as Xcode Server can handle almost everything needed for CI/CD

You might see several other benefits and increased confidence and trust on Continuous Integration

Conclusion

Using the combination of DevOps tools and Apple’s native CI/CD tools we can achieve scalable and programmable infrastructure for our iOS apps. Xcode Server and Ansible combination can work well together to achieve Continuous Delivery of iOS apps without any pain. Are you using any configuration management tools for iOS CI/CD infrastructure? What are your experiences with Xcode Server? please let me know what you think about this approach, any ideas suggestions would be great.