AWS Partner Network (APN) Blog

Implementing macOS Build Agents into TeamCity Using Amazon EC2 Mac Instances

By Jon Schwenn, Enterprise Support Lead – AWS

With Amazon Elastic Compute Cloud (Amazon EC2) Mac instances, customers can run macOS workloads and benefit from the scale, elasticity, reliability, and experience of Amazon Web Services (AWS).

Amazon EC2 Mac instances allow customers to bootstrap macOS machines in the cloud and use these for building, testing, and deploying iOS applications with the security, scalability, and flexibility of the cloud.

Today, millions of developers rely on Apple’s industry-leading platforms and tools such as Xcode and Swift, and powerful frameworks like Core ML and Metal, to create apps for over a billion customers globally. Previously, customers did not have access to On-Demand instance macOS environments in the cloud.

TeamCity, developed by JetBrains, is a common CI/CD automation tool for developers. It offers the ability to use build agents, distribute CI/CD pipelines across machines, or schedule parts of a pipeline to a specific instance type or container.

In this post, you will learn how to add an EC2 Mac instance as a build agent to an existing TeamCity server. While this post shows how to use an EC2 Mac instance with TeamCity, it can be done with different CI/CD applications such as Jenkins or GitLab runners.

With over 6.1 billion smartphone users worldwide and continuous growth in new smartphone users, there’s an increasing demand for mobile applications that is reflected by the number of available apps in the Apple App Store. With this demand, companies are investing more heavily into mobile application development to drive user engagement.

This post helps mobile app developers to create using CI/CD pipelines within their AWS environment with EC2 Mac instances. EC2 Mac instances offer all of the benefits of AWS and removes the need to manage special build macOS machines in a separate environment.

Overview

The following diagram gives an overview of the architecture we are using in this post.

JetBrains-TeamCity-macOS-EC2-1

Figure 1 – EC2 Mac Instance TeamCity Agent in the same VPC as a TeamCity server using git for a code repository.

A prerequisite for this walkthrough is experience with TeamCity and a functioning TeamCity build server within an Amazon Virtual Private Cloud (VPC). Reference the Setting Up TeamCity for Amazon EC2 documentation to get started.

Our example will be structured in three parts:

  1. Create an EC2 Mac instance configured to build Xcode projects.
  2. Add the newly-created instance as a build agent to an existing TeamCity installation.
  3. Run an example pipeline with an Xcode project using the new Mac build agent.

Now that we’ve defined our steps, let’s get started.

Step 1: Create and Configure the Amazon EC2 Mac Instance

Allocate mac1 Dedicated Host

EC2 Mac instances must run on a Dedicated Host. A mac1 Dedicated Host can be allocated in the AWS Management Console or AWS Command Line Interface (CLI) by following the steps outlined in this documentation.

Note that the 24-hour minimum allocation duration begins once the Dedicated Host is allocated, not when you launch an instance.

We will create a mac1.metal EC2 instance on our new Dedicated Host with the following steps, which are covered at a high level in this documentation.

  1. Click the Launch instance button on the EC2 console and click the Select button that corresponds with the macOS Big Sur AMI.
  2. The only available instance type is the mac1.metal option. Click Next: Configure Instance Details to continue.
  3. Use the following configuration details:
    • Network: Select the VPC where your TeamCity installation resides.
    • Subnet: Select the subnet you used when allocating your Dedicated Host.
    • Host: Select your Dedicated Host.
    • Advanced Details: Add the following script to the User Data text box and then click Next: Add Storage:
#!/bin/zsh

# VOLUME EXPAND
echo "EXPANDING APFS VOLUME"
PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1)
APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8)
yes | diskutil repairDisk $PDISK
diskutil apfs resizeContainer $APFSCONT 0
echo "------------------------"
# You'll need to SSH in and 'sudo passwd ec2-user' to set
# a password for Screen Sharing
echo "ENABLING SCREEN SHARING"
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -restart -agent -privs -all
echo "------------------------"
# INSTALL JAVA
echo "INSTALL JAVA 8"
su ec2-user -c '/usr/local/bin/brew tap homebrew/cask-versions && brew install --cask corretto8'
  1. Increase the size of the Root volume to 256 GiB and change the Volume Type to “General Purpose SSD (gp3).” Click Next: Add Tags to continue.
  2. Adding tagging information is optional. Adding a value for a “Name” tag key will result with a display name in the EC2 console. Tagging your resources has many benefits including tracking costs and access control. Click Next: Configure Security Groups to continue.
  3. Select the existing security group of your TeamCity server or create a new security group. It’s important the security group allows access to your TeamCity server. Click Review and Launch to continue.
  4. Click Launch and a dialog box will appear where you can select an existing key pair or create a new key pair. This key pair is important to connect to mac1.metal instance via SSH.

When the mac1.metal instance boots up the first time, the ec2-macos-init tool runs the script you added to the user data in Step 3. This process will take a few minutes and will continue to run after you’re able to login to the EC2 Mac instance.

In the user data, Amazon Corretto 8 for the TeamCity agent is installed. Lastly, it resizes the boot volume to the Amazon Elastic Block Store (Amazon EBS) size and starts the ARDAgent. This allows you to connect with a VNC Client to the instance. For more information on the volume resizing, the ARDAgent, or the ec2-macos-init, see our Amazon EC2 Mac instance documentation.

Before explaining how to add this instance as a build agent, Xcode must be installed on the instance. As the installation requires logging in to the Apple App Store, follow the instructions of Connect to your instance using Apple Remote Desktop.

Then, download and install Xcode manually from the Mac App Store. Make sure to open Xcode once to accept the Xcode and iOS SDK License Agreement. Agreeing to the CLI Agreement is also necessary.

Run this command and complete the acceptance:

sudo xcodebuild -license

Note that it’s crucial to reboot the instance after this step. A reboot within the OS will take less time than a stop and start of the instance.

At the end of this section, you should have an EC2 Mac instance which is set up to build iOS projects. Now, you can add this instance as a build agent to your TeamCity server.

Step 2: Add Your EC2 Mac Instance as a Build Agent to TeamCity

Please note that it’s required to perform these actions from a screen-sharing session and a terminal running in the desktop view. Some actions are not permissible through a remote SSH connection.

Log into the web console for TeamCity from your EC2 Mac instance and download the Minimal zip file distribution installer from the Agents tab. If there are agents already connected, the link for the installers is in the upper right corner on the current version of TeamCity. Move the zip file to the desired location and unzip the downloaded file.

Within the buildAgent folder there is a folder named conf. Copy the buildAgent.dist.properties file and name the copy buildAgent.properties. Open the new properties file and edit the serverURL and name variables to match your TeamCity server URL and what you want to name your build agent.

curl -o buildAgent.zip http://<IP of TeamCity Server>:8111/update/buildAgent.zip

unzip buildAgent.zip -d buildAgent

cd buildAgent/conf

cp buildAgent.dist.properties buildAgent.properties

Next, edit the serverURL and save the properties file.

TeamCity provides a LaunchAgent to launch the build agent software automatically on macOS. To enable the LaunchAgent, run the following commands in a terminal when located in the buildAgent folder. Note that this specific command needs to be ran from the desktop environment:

cd ../bin

./mac.launchd.sh load

After a few minutes, your EC2 Mac instance will appear as a build agent in TeamCity. The agent will appear under the Unauthorized tab. In that section, you can authorize the agent and assign it to an agent pool.

To complete the LaunchAgent installation, edit the buildAgent/bin/jetbrains.teamcity.BuildAgent.plist file to reflect the ec2-user user.

First, unload the launched plist file:

./mac.launchd.sh unload

Add the following key and value under the WorkingDirectory value:

<key>UserName</key>

<string>ec2-user</string>

Then, run the following commands after editing the plist file to complete the installation. Note that you should still be in the bin folder within buildAgent:

mkdir /Users/ec2-user/Library/LaunchAgents

cp jetbrains.teamcity.BuildAgent.plist /Users/ec2-user/Library/LaunchAgents

To allow the TeamCity agent to start automatically on boot, you’ll need to set the ec2-user to automatically log in. This is done with the Automatic login option under Login Options in the Users & Groups System Preferences pane.

Reboot your Mac from the VNC session or with a sudo reboot command in a terminal session. The TeamCity build agent software will automatically load when the EC2 Mac instance boots.

Step 3: Create an Xcode Runner and Create a Build

Now that the TeamCity build agent is installed and running on the Amazon EC2 Mac instance, you can create an Xcode Project Runner in the TeamCity server.

When the build steps are completed, the building and testing of your Xcode project will be processed on the EC2 Mac build agent registered in your TeamCity Server.

JetBrains-TeamCity-macOS-EC2-2

Figure 2 – New build step form in TeamCity set to use Xcode projects.

Cleanup

You cannot release the Dedicated Host until the allocation period exceeds the 24-hour minimum. Follow the steps below in the AWS console to avoid incurring unwanted cost:

  • Navigate to the Amazon EC2 dashboard.
  • In the navigation, choose Instances and select the previously created EC2 Mac instance.
  • From Instance state, choose Terminate Instance.
  • In the navigation, choose Dedicated Hosts and select the previously created Dedicated Host.
  • From Actions, choose Release host.

When you finish experimenting with your Mac instance, you can release the Dedicated Host. Before you release the Dedicated Host, you must stop or remove the Mac instance.

Conclusion

In this post, you learned how to bootstrap an Amazon EC2 Mac instance with the required tools to have act as a build agent for TeamCity.

Building an Amazon Machine Image (AMI) the first time you set up an EC2 Mac TeamCity build agent allows simple and seamless deployment of many more build agents using the same image. To read more about this, see the Amazon EC2 AMIs documentation.

To get started using EC2 Mac instances, check out the product page. For more information on the configuration and deployment of EC2 Mac instances, see the Amazon EC2 Mac instances documentation.