Skip to content

Commit c8726fe

Browse files
docs: add documentation and mark asexperimental
1 parent e74da9a commit c8726fe

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

docs/configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ In case the setup does not work as intended, trace the events through this seque
282282

283283
## Experimental features
284284

285+
### macOS Runners
286+
287+
This feature is in early stage and should be considered experimental. The module supports macOS-based GitHub Actions self-hosted runners on AWS EC2 Mac instances (`mac1.metal`, `mac2.metal`, `mac2-m2.metal`). macOS runners require dedicated hosts due to Apple's licensing requirements and have longer boot times (6–20 minutes). Set `runner_os = "osx"` and `use_dedicated_host = true` to enable. See the full [macOS Runners documentation](mac-runners.md) for details.
288+
285289
### Termination watcher
286290

287291
This feature is in early stage and therefore disabled by default. To enable the watcher, set `instance_termination_watcher.enable = true`.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--8<-- "examples/dedicated-mac-hosts/README.md"

docs/examples/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ Examples are located in the [examples](https://github.com/github-aws-runners/ter
99
- _[Prebuilt Images](prebuilt.md)_: Example usages of deploying runners with a custom prebuilt image.
1010
- _[Windows](windows.md)_: Example usage of creating a runner using Windows as the OS.
1111
- _[Termination watcher](termination-watcher.md)_: Example usages of termination watcher.
12+
- _[Dedicated Mac Hosts](dedicated-mac-hosts.md)_: Example usage of setting up dedicated hosts for macOS runners.
1213
- _[Externally managed SSM secrets](external-managed-ssm-secrets.md)_: Example usage of externally managed SSM secrets for the GitHub App credentials.

docs/mac-runners.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# macOS Runners (Experimental)
2+
3+
!!! warning
4+
This feature is in early stage and should be considered experimental. macOS runners on AWS have unique constraints compared to Linux and Windows runners. Please review all sections below before deploying.
5+
6+
## Overview
7+
8+
The module supports provisioning macOS-based GitHub Actions self-hosted runners on AWS using [Amazon EC2 Mac instances](https://aws.amazon.com/ec2/instance-types/mac/). macOS runners use the `osx` value for the `runner_os` variable and require **dedicated hosts** due to Apple's macOS licensing requirements.
9+
10+
Key differences from Linux/Windows runners:
11+
12+
- **Dedicated hosts required.** EC2 Mac instances must run on dedicated hosts. Each dedicated host can run **only one Mac VM at a time** (1:1 ratio). The module uses `RunInstances` directly instead of the `CreateFleet` API when `use_dedicated_host` is enabled.
13+
- **Longer boot times.** macOS instances can take 6–20 minutes to launch, significantly longer than Linux (~1 min) or Windows (~5 min). The default `minimum_running_time_in_minutes` for `osx` is set to 20 minutes to prevent premature scale-down.
14+
- **~50 minute host recycle time.** After an EC2 Mac instance is terminated, AWS performs install cleanup and software upgrades on the dedicated host before it becomes available again. This process takes approximately **50 minutes**, during which the host cannot launch a new instance.
15+
- **ARM64 (Apple Silicon) and x64 (Intel) support.** Both `mac1.metal` (Intel), `mac2.metal` (M1), and `mac2-m2.metal` (M2) instance types are supported. Set `runner_architecture` accordingly (`x64` or `arm64`).
16+
- **Only ephemeral mode is recommended.** Due to the long host allocation time and dedicated host cost model, we recommend using ephemeral runners.
17+
18+
## Scaling caveats
19+
20+
Running macOS runners at scale introduces challenges that do not exist with Linux or Windows runners:
21+
22+
1. **1:1 host-to-VM ratio.** Unlike Linux where many instances share underlying hardware, each Mac VM requires its own dedicated host. To run N concurrent macOS jobs, you need at least N dedicated hosts.
23+
2. **Host recycle delay.** After a Mac instance is terminated, the dedicated host enters a ~50 minute cleanup cycle (scrubbing, software updates). During this window the host is unavailable. For bursty workloads, you need additional hosts to absorb demand while others recycle.
24+
3. **Capacity planning.** As a rule of thumb, if you expect N peak concurrent macOS jobs and each job takes T minutes, account for the extra ~50 minutes of host downtime per cycle when sizing your host pool.
25+
26+
## Prerequisites
27+
28+
Before deploying macOS runners, you must set up dedicated host infrastructure. There are two approaches:
29+
30+
### Option A: Single dedicated host
31+
32+
The simplest setup — allocate a single dedicated host and reference it directly. This works for low-scale or testing scenarios, but you must update the Terraform configuration whenever you replace the host.
33+
34+
1. **Dedicated Host** — Allocate an EC2 dedicated host for your Mac instance type in the target availability zone.
35+
36+
### Option B: Host resource group (recommended for scale)
37+
38+
A host resource group allows you to associate **multiple dedicated hosts within an availability zone** into a logical group. When launching a Mac instance, AWS randomly selects an available host from the group. This means you can add, release, or replace individual dedicated hosts **without changing Terraform state or module inputs** — you only reference the group ARN, not individual host ARNs.
39+
40+
This approach requires three resources:
41+
42+
1. **Dedicated Hosts** — Allocate one or more EC2 dedicated hosts for Mac instance types in your target availability zones.
43+
2. **Host Resource Group** — Create an AWS Resource Groups group of type `AWS::EC2::HostManagement` and add your dedicated hosts as members.
44+
3. **License Configuration** — Create an AWS License Manager license configuration for Mac dedicated hosts (counting type: `Socket`). Associate it with the macOS AMI and the host resource group. The license configuration ARN is passed to the module via the `license_specifications` input.
45+
46+
The [dedicated-mac-hosts example](examples/dedicated-mac-hosts.md) provides a ready-to-use Terraform configuration for all three resources.
47+
48+
## Configuration
49+
50+
### Basic setup
51+
52+
```hcl
53+
module "runners" {
54+
source = "github-aws-runners/github-runners/aws"
55+
56+
# macOS-specific settings
57+
runner_os = "osx"
58+
runner_architecture = "arm64" # or "x64" for Intel Mac instances
59+
instance_types = ["mac2.metal"]
60+
61+
# Dedicated host settings (required for macOS)
62+
use_dedicated_host = true
63+
placement = {
64+
host_resource_group_arn = "<arn-of-your-host-resource-group>"
65+
}
66+
license_specifications = ["<arn-of-your-license-configuration>"]
67+
68+
# Recommended: ephemeral mode with a pool
69+
enable_ephemeral_runners = true
70+
delay_webhook_event = 0
71+
enable_job_queued_check = true
72+
73+
# ...other common settings...
74+
}
75+
```
76+
77+
### AMI selection
78+
79+
By default, the module selects an Amazon EC2 macOS Sequoia (macOS 15) AMI:
80+
81+
- **ARM64:** `amzn-ec2-macos-15.*-arm64`
82+
- **x64:** `amzn-ec2-macos-15.*`
83+
84+
You can override the AMI using filters or an SSM parameter:
85+
86+
```hcl
87+
# Custom AMI filter
88+
ami = {
89+
filter = {
90+
name = ["amzn-ec2-macos-14.*-arm64"]
91+
state = ["available"]
92+
}
93+
owners = ["amazon"]
94+
}
95+
96+
# Or via SSM parameter
97+
ami = {
98+
id_ssm_parameter_arn = "arn:aws:ssm:region:account:parameter/path/to/mac/ami"
99+
}
100+
```
101+
102+
### Multi-runner setup
103+
104+
When using the multi-runner module, you can add a macOS runner configuration alongside Linux and Windows runners:
105+
106+
```hcl
107+
multi_runner_config = {
108+
"mac-arm64" = {
109+
runner_config = {
110+
runner_os = "osx"
111+
runner_architecture = "arm64"
112+
instance_types = ["mac2.metal"]
113+
use_dedicated_host = true
114+
placement = {
115+
host_resource_group_arn = "<arn-of-your-host-resource-group>"
116+
}
117+
license_specifications = ["<arn-of-your-license-configuration>"]
118+
runner_extra_labels = ["osx", "arm64"]
119+
}
120+
matcherConfig = {
121+
labelMatchers = [["self-hosted", "osx", "arm64"]]
122+
exactMatch = false
123+
}
124+
}
125+
}
126+
```
127+
128+
## Instance launch behavior
129+
130+
Because EC2 Fleet (`CreateFleet`) does not support launching instances onto dedicated hosts for `mac*.metal` instance types, the scale-up lambda automatically falls back to using `RunInstances` when `use_dedicated_host` is `true`. This is handled transparently — no additional configuration is needed.
131+
132+
## User data and scripts
133+
134+
The module uses macOS-specific templates for provisioning:
135+
136+
| Script | Description |
137+
| --- | --- |
138+
| `user-data-osx.sh` | Boot script for macOS instances. Uses `ec2-user` and supports Homebrew. |
139+
| `install-runner-osx.sh` | Downloads and installs the GitHub Actions runner agent to `/opt/actions-runner`. |
140+
| `start-runner-osx.sh` | Registers the runner with GitHub and handles ephemeral cleanup. |
141+
142+
Custom pre/post install scripts and job hooks (`hook_job_started`, `hook_job_completed`) work the same as on Linux.
143+
144+
## Scale-down considerations
145+
146+
macOS instances have a default minimum running time of **20 minutes** (vs. 5 for Linux, 15 for Windows) to account for the longer boot cycle. Adjust `minimum_running_time_in_minutes` if needed, but setting it too low risks terminating instances before they can execute a job.
147+
148+
Additionally, remember that after an instance is terminated, the dedicated host enters a **~50 minute cleanup cycle** before it can launch a new instance. Aggressive scale-down can leave you with no available hosts during this window.
149+
150+
```hcl
151+
# Override the minimum running time (not recommended to go below 20 for macOS)
152+
minimum_running_time_in_minutes = 25
153+
```
154+
155+
## Cost considerations
156+
157+
!!! note
158+
macOS dedicated hosts have a **minimum allocation period of 24 hours**. You are billed for the dedicated host for the full 24-hour period, regardless of instance usage. Plan your host allocation accordingly.
159+
160+
- **Dedicated host costs**: Billed per-host, per-hour with a 24-hour minimum. Each host supports only one Mac VM at a time. See [EC2 Dedicated Hosts Pricing](https://aws.amazon.com/ec2/dedicated-hosts/pricing/).
161+
- **Instance costs**: Mac instances are billed on-demand only (no spot pricing available for Mac instances).
162+
- **Over-provisioning for recycle time**: Because hosts are unavailable for ~50 minutes after instance termination, you may need more dedicated hosts than your peak concurrency to avoid queuing. Factor this into your cost model.
163+
- **Pool sizing**: Keep pool sizes minimal to control costs, but large enough to avoid cold-start delays.
164+
165+
## Known limitations
166+
167+
- **No spot instance support.** EC2 Mac instances do not support the spot lifecycle. Runners always use on-demand pricing.
168+
- **1:1 host-to-VM ratio.** Each dedicated host can run only one Mac instance at a time.
169+
- **~50 minute host recycle time.** After instance termination, AWS performs cleanup and software upgrades on the dedicated host. The host is unavailable for approximately 50 minutes during this process.
170+
- **24-hour minimum host allocation.** Dedicated hosts cannot be released within 24 hours of allocation.
171+
- **Limited instance types.** Only `mac1.metal` (Intel x86), `mac2.metal` (M1 ARM64), and `mac2-m2.metal` (M2 ARM64) are available. Instance type availability varies by region.
172+
- **Longer startup.** Boot times of 6–20 minutes mean jobs will queue longer when no warm runners are available.
173+
- **No SSM Session Manager.** Unlike Linux instances, connecting via AWS Session Manager may not be available depending on your AMI.
174+
- **GHES not tested.** macOS runner support has not been validated against GitHub Enterprise Server.
175+
176+
## Debugging
177+
178+
- Check `/var/log/user-data.log` on the macOS instance for boot script output.
179+
- CloudWatch log streams under `<environment>/runners` will contain runner agent logs if CloudWatch logging is enabled.
180+
- Verify your dedicated host has available capacity in the EC2 console under **Dedicated Hosts**.
181+
- Ensure the host resource group ARN and license configuration ARN match what is configured in Terraform.
182+
- If runners fail to register, verify the GitHub App has the correct permissions and the SSM token path is accessible.
183+
184+
## Example
185+
186+
A complete example for setting up the dedicated host infrastructure is available at:
187+
188+
- [Dedicated Mac Hosts example](examples/dedicated-mac-hosts.md)

0 commit comments

Comments
 (0)