by Praveen Kumar Patidar
Lead Consultant at CMD Solutions

Background

The mobile and application development space has seen rapid growth in the last decade. Primarily on iOS and Android platforms – for example, Apple iOS hit 20 million developers registered back in 2018. With growing application development, organizations need scalable and secure environments to build and release applications in a consistent way. AWS is growing its mobile application offerings in parallel to keep pace, justifying its position in Gartner’s Magic Quadrant.

iOS applications are fully dependent on XCode that only supports macOS platforms, also using containers or virtual machines is nearly impossible because of XCode installation size (~32GB). The organizations using AWS Cloud primarily for application infrastructure depends on external services to build and release applications to the App Store and to automate CICD workflow automation – for example On-Prem Mac Mini agents, Mac Cloud, or expensive options like Mac Stadium.

To address the problem, AWS announces the general availability of macOS-based EC2 instances in late 2020. iOS development environments can now be deployed on AWS EC2, along with its multitude of service integrations with the rest of the AWS cloud, to build applications for Macs, iPads, Apple Watches, and iPhones.

The initial offering from AWS is providing Mac mini hardware powered by 3.2 GHz Intel eighth-generation (Coffee Lake) Core i7 processors. In Dec-2021, AWS also announced the support for the M1 processor built on Apple silicon Mac mini computers and powered by AWS Nitro System, providing 60% better price performance.

As Mac offering is fairly new, it’s difficult to find automated solutions to Launch Mac Instances using IaC frameworks such as Terraform or CloudFormation. The blog will cover key features and details about the offering. Along with that, it also covers the automation coding tips for various configurations and installations.

Use Cases and Benefits

There are a number of benefits & use cases for utilizing a Mac on AWS. These include;

  • AWS Compute and networking benefits e.g. high IOPS EBS, fast networking, SSM Integration, etc.

  • AWS Automation support, e.g. CloudFormation, and SSM Document.

  • Other AWS benefits e.g. IAM Access, Scalability, Encryption, Reliability, and integration with other AWS Services.

  • Organizations can utilize native AWS services to secure, backup, and provision Mac EC2 instances.

  • Automation of CICD build pipelines using Github or Gitlab Self Hosted Runner backed by Mac Runners.

  • Developers can now seamlessly automate the mobile application publish via Github\Gitlab automated pipelines backed by Mac EC2.

  • Installing Android Studio CLI on macOS will provide a single system to automate both Apple and Android application AWS’s official site Amazon EC2 Mac Instances.

AWS Offering

Here is information regarding out of the box offering by AWS for Mac EC2 Instances.

Instance type
The only instance type available for x86 and M1 is mac1.metal and mac2.metal respectively, meaning the vCPU, cores, and memory configuration is not flexible similar to other OS available in AWS. However, the volumes are backed by EBS making it possible to increase the storage as per requirements.

macOS AMI
AWS released public AMIs for iOS ranging from iOS version 10 to 12.1 including some CIS hardened AMIs unlike other AMIs, macOS AMIs are not released on a frequent basis. Thus customers need to maintain the patching either via In-Place update or via AWS SSM.
Note – that there can be a significant time difference between the macOS updates and corresponding AMI releases.

Dedicated Host
An AWS Dedicated Host needs to be provisioned to host the mac1.metal instance type. It will add significant cost to accounts as compared to other types of OS instances. A dedicated host once launched cannot be released before 24Hours. Also, it will take around an hour to release terminated instance capacity.

If running instances are using the full capacity of a dedicated host, then every stop\termination needs at least 1 hour of additional time to release the capacity of the instance to be used again. This results in challenges while automating the instance launch with IaC tools like terraform. Where you cannot simply replace the instance immediately.

e.g. if you are running 1 instance with 1 dedicated host capacity and using terraform for automation:

replace the instance:

Method 1: Stop current instance(manual) > Wait for dedicated host to release capacity (1hr) > launch terraform update

Method 2: Launch another dedicated host > Launch New Instance > Terminate current instance > Wait for dedicated host to release the capacity > Release the dedicated host

AWS AMI Pre-Built tools
AWS AMI for macOS comes with a few pre-built tools already installed.

  • Homebrew – To manage to install application components supported by brew. The brew cannot be run as root. In general, ec2-user can be used in AWS.

  • AWS CLI – To integrate with wider AWS service integration and automation using AWS services. E.g. downloading from s3, accessing AWS SSM parameters, etc.

  • AWS SSM Manager – The AMI comes with an SSM agent running on it. This means one can leverage SSM Session Manager, Patch manager out of the box.

  • Xcode Command Line Tools: Developers need to install Xcode Command Line Tools before they can develop software on a Mac.

Automation Tips

Let’s dive into the automation of instance build, including pre-built software and challenges.

Tip 1: OS Storage Extension

Unlike other instance OS families, the root volume of macOS doesn’t extend by default. Here are the steps to increase the size of an EBS volume of Mac EC2 instance.

PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1)
APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8)
yes | sudo diskutil repairDisk $PDISK
sudo diskutil apfs resizeContainer $APFSCONT 0

Tip 2: OS Upgrade

OS upgrades for minor and major versions may take time. Run below scripts in the background or use cron.

softwareupdate --install --all
su ec2-user -c '/usr/local/bin/brew update'
su ec2-user -c '/usr/local/bin/brew upgrade'

Note: Restarting the system may need manual effort as the dedicated host will not allow immediate start after stop.

Tip 3: Installing iOS Packages

Here are some tips to install .pkg and .dmg files.

Install .pkg files in macOS

curl -o /tmp/<PACKAGE_NAME>.pkg <URL OF PACKAGE> # Optional if download needed
installer -pkg /tmp/<PACKAGE_NAME>.pkg -target /
rm /tmp/<PACKAGE_NAME>.pkg # Clean if needed

Install .dmg files in macOS

curl -o /tmp/<DMG_NAME>.dmg <URL_FOR_FMG> # Optional if download needed
hdiutil attach /tmp/<DMG_NAME>.dmg -mountpoint "/Volumes/<DMG_NAME>_mount"
PACKAGE=$(ls -1 /Volumes/<DMG_NAME>_mount | grep .pkg | head -1)
installer -pkg "/Volumes/<DMG_NAME>_mount/$PACKAGE" -target /
hdiutil detach "/Volumes/<DMG_NAME>_mount"
rm /tmp//tmp/<DMG_NAME>.dmg # Clean if needed

Install brew based packages
The latest macOS doesn’t allow users to run brew using root. If brew running in EC2 user-data, the below commands can be used.

su ec2-user -c '/usr/local/bin/brew install <PACKAGE>'

Configure Service as Launch Daemon
Any custom service or scripts that need to be configured as start\stop or restart as service can be configured as LaunchDaemon service.

      1. Create an XML .plist file. e.g.  xyz.plist replace {PLACEHOLDER} values –
        Placeholder values :
        {SCRIPT_PATH} : Path of the scripts e.g. /opt/
        {LOG_PATH} : Path of the logs e.g. /var/log/

        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
        <plist version="1.0">
        <dict>
        <key>Label</key><string>boot.shutdown.script.name</string>
        <key>ProgramArguments</key>
        <array>
        <string>{SCRIPT_PATH}/xyz.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardOutPath</key>
        <string>{LOG_PATH}/xyz.log</string>
        <key>StandardErrorPath</key>
        <string>{LOG_PATH}/xyz.err</string>
        </dict>
        </plist>
      2. Create an XML .plist file. e.g.  SCRIPT_PATH/xyz.sh, using the template below:
        #!/bin/bash
        function shutdown(){
        echo "The process shutdown initiated"
        # INSERT HERE THE COMMAND YOU WANT EXECUTE AT SHUTDOWN
        exit 0
        }
        function startup(){
        echo "The process startup initiated"
        # INSERT HERE THE COMMAND YOU WANT EXECUTE AT STARTUP
        tail -f /dev/null & wait $!
        }
        trap shutdown SIGTERM
        trap shutdown SIGKILL
        startup;c
      3. Create an XML .plist file. e.g.  /Library/LaunchDaemon/xyz.playlist,
        Use the below commands to start and stop the service.
        The unload and load will also restart. The argument as true,  RunAtLoad in xyz.plist will enable the auto load and unload.
        # Start Service
        sudo launchctl load -w /Library/LaunchDaemons/boot-shutdown-script.plist
        # Stop Service
        sudo launchctl unload -w /Library/LaunchDaemons/boot-shutdown-script.plist
Tip 5: XCode Installation

Xcode includes everything developers need to create great applications for Mac, iPhone, iPad, Apple TV, and Apple Watch. To install Xcode automatically, the installer needs to be downloaded from the Apple developer portal. The developer portal is normally enabled with MFA and not possible to automate this. Once downloaded using the developer portal, use s3 to upload the Xcode installer to automate using user-data or AMI baking.
Xcode installs and unzip will take a long time as it’s 32GB in size once unzipped. The best way is to run the process in the background if running in user-data.

Tip 4: EC2 User-data Automation

At the moment the macOS user-data doesn’t support the cloud-init scripts. One can organize the template files or s3 bucket to upload the scripts to run as user-data.
The user-data is executed using ec2-macos-init launch daemon. More features for this to be validated.

Conclusion

The macOS platform is surely going to ease the pain of developers working on iOS by building automated workflows, on-demand environments for application development in the AWS Cloud. Organizations can now leverage AWS security and compliance for development environments for iOS applications and adding to that, the recent announcement of AWS to support M1 will add more price benefits to customers with additional efficiency in terms of performance and security. Also, hoping to Mac Studio support in coming future for more complex workloads.