AWS EC2 Mac Instances With Terraform

Setting up latest Mac instances on AWS

Image for post
Image for post

General

This is another story to test out the latest release of EC2 instances to see how it can be deployed in a managed way. For this purpose I used AWS CLI and Terraform.

Seeing Mac instances in AWS Cloud was a positive surprise, more details can be found in the official announcement. From my perspective I will be using such machine as Gitlab build runners, however, it will take some time to get them nicely implemented on top of the EC2 Mac instances.

Configuration

Image for post
Image for post

Cracking on, I am making use of Ireland region to get this setup configured and I will be deploying Catalina machines :). Big Sur is not supported yet, probably because of M1 chips that Apple released last month but support to be expected in 2021.

Dedicated host

First, we need to create a Dedicated Host with following setup:

  • Instance type: mac1.metal
  • Instance family: mac1

Each dedicated host is associated with Availability zone. In the Ireland region we have three of them; eu-west-1a, eu-west-1b and eu-west-1c. At the time of writing eu-west-1a AZ has no capacity for new Mac dedicated hosts :).

The way to create it is using Console or CLI. I used CLI:

aws ec2 allocate-hosts \
--instance-type mac1.metal \
--availability-zone eu-west-1b --auto-placement on \
--quantity 1 --region eu-west-1

The reason I had to use cli is simply because Terraform doesn’t support dedicated hosts yet. The issue related to it can be found under https://github.com/hashicorp/terraform-provider-aws/issues/10752

The above command will create a dedicated host which will look as follows (important part to record is the host id):

Image for post
Image for post

You can see that there are 6 physical cores, 12 vCPUs and runs in the eu-west-1b AZ.

Our Host Id is h-002de77f93125e3c2, this is the ID we are going to use in our Terraform script when deploying Mac instance.

AMI for Mac instance

Just like any other EC2 instance, we need an AMI to spin up a Mac instance. To source one using Terraform, you can use the following:

data "aws_ami" "mac" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = [
"amzn-ec2-macos-10.15.7-*-*"
]
}
filter {
name = "owner-alias"
values = [
"amazon",
]
}
}

Very simple and elegant way of getting latest AMI for Catalina OSX.

VPC + EC2

Final step requires some networking setup. In my case, I simply spinned up an instance in public subnet of my VPC.

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.64.0"
name = "mac-instance-vpc" azs = var.availability_zones cidr = var.vpc_cidr
public_subnets = var.public_subnets_cidrs
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_security_group" "ssh" {
name_prefix = "mac-ssh-sg-"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_instance" "mac_instance_b" {
ami = data.aws_ami.mac.image_id
instance_type = "mac1.metal"
key_name = var.ssh_key_name
availability_zone = "eu-west-1b"
host_id = "h-002de77f93125e3c2"
subnet_id = module.vpc.public_subnets[1]
vpc_security_group_ids = [aws_security_group.ssh.id]
}

In the above you can see a VPC, Security group attached to EC2 instance. Security group in this case only allows SSH access on port 22. Instance will also be provisioned with public IP.

SSH

In order to SSH into Mac instance, you simply run the following:

ssh -i private_key.pem ec2-user@52.53.52.53
Image for post
Image for post

Additional bits

Creating Mac instances is not a painful process but a very long one. It takes ages to create one. Rebooting of Mac instance also takes countless minutes and you will see failing health checks on your instances. In such case, simply wait for the instance to settle.

Mac instances run macOS 10.14 (Mojave) and 10.15 (Catalina) and can be accessed via command line (SSH) or remote desktop (VNC). The AMIs (Amazon Machine Images) for EC2 Mac instances are EC2-optimized and include following packages: An ENA driver, the AWS Command Line Interface (CLI), the CloudWatch Agent, CloudFormation Helper Scripts, support for AWS Systems Manager, and the ec2-user account. Homebrew is also preinstalled on those instances.

You can use these instances to create build farms, render farms, and CI/CD farms that target all of the Apple environments that I mentioned earlier. You pay only for what you use, and you get to benefit from the elasticity, scalability, security, and reliability provided by EC2.

Known Issues and Solutions

docker installation

Issue

In order to automate the process of installing applications I want to make use of CLI only without using GUI. So I ran brew install --cask docker but that didn’t really work as expected. Then I tried open /Applications/docker.app which returned an error. Without Docker on those Mac instances it will be difficult to run any jobs. I posted this issue on stackoverflow https://stackoverflow.com/questions/65093499/how-to-install-and-run-docker-app-on-ec2-mac-instance

Solution

Installation of Docker.app requires a sequence of steps (subsequent next next options) and acknowledgements that has to be done via a GUI and unfortunately is not possible to perform via CLI. It is recommended to use GUI to launch applications in MacOS.

So setting up GUI is the only option…

  • Local forwarding to port 5900.
ssh -L 5900:localhost:5900 -i private_key.pem ec2-user@<Instance-Public-IP>

VNC data is unencrypted by default, therefore we are accessing the VNC server using an encrypted SSH tunnel.

  • Install the application using the following command
brew install --cask docker 
  • Switch to the root mode and set password for ec2-user
sudo su — 
passwd ec2-user <You’ll be prompted to enter your password twice> exit
  • Enable Mac OS screen sharing (VNC) SSH from Mac Instance
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -clientopts -setvnclegacy -vnclegacy yes -clientopts -setvncpw -restart -agent -privs -all 
  • VNC to the instance over the SSH tunnel by connecting to 127.0.0.1:5900 or localhost:5900 If your local machine is a MAC server you can execute the following command in your local machine terminal by opening a new terminal window (not inside the SSH session) or download a VNC client for the remote session
open ‘vnc://localhost:5900’
Please Note: The above SSH session should be running while you are in the remote session
  • Connect to your remote session of your MAC instance and install your docker application[1]:

Username : ec2-user

Password : 123456

open /Applications/Docker.app # works!

Conclusion

I love the fact that this feature has finally landed. But like with every AWS’s first release, I don’t believe this is a production ready product. Takes ages to do anything. User Metadata is impossible to debug as system logs are simply not reported (I waited for 3 hours). I think we still need to wait a few months for this implementation to optimised.

Otherwise, there were no setup issues. Terraform needs to catch up with certain features but other than that everything was cool and easy to deploy.

Written by

Lead Software/Infrastructure/Devops Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store