AWS EC2 Runner Investigation
This document explores the feasibility and trade-offs of migrating from the current mixed self-hosted runner setup to AWS EC2-based runners.
Current State
Runner Configuration
| Runner Type | Platform | Use Case | Availability |
|---|---|---|---|
| Self-hosted Windows | Windows 11 | Android builds, Gradle | Developer machine |
| Self-hosted macOS | macOS Sonoma | iOS builds, Xcode | Developer machine |
| GitHub-hosted | ubuntu-latest | Fallback, simple tasks | Always available |
Current Pain Points
-
Mixed Platform Complexity
- Different shell syntaxes (PowerShell vs Bash)
- Different path separators and encodings
- Workflow files need platform-specific conditionals
-
Availability Concerns
- Self-hosted runners depend on developer machines being online
- Builds fail silently when runners are offline
- No build capability during travel or machine maintenance
-
Cost Structure
- GitHub-hosted macOS runners: $0.08/minute (8x Linux pricing)
- Self-hosted: “Free” but ties up developer hardware
- Hidden cost: Developer productivity impact
-
Maintenance Burden
- Keeping Xcode, Android SDK, JDK versions in sync
- Runner software updates
- Disk space management
AWS EC2 Options
Linux Runners (Android/Gradle)
Instance Types:
| Instance | vCPU | Memory | Cost/hr (On-Demand) | Cost/hr (Spot) |
|---|---|---|---|---|
| c6i.xlarge | 4 | 8 GB | $0.17 | ~$0.05 |
| c6i.2xlarge | 8 | 16 GB | $0.34 | ~$0.10 |
| c7i.2xlarge | 8 | 16 GB | $0.36 | ~$0.11 |
Recommendation: c6i.2xlarge for faster Gradle builds
Estimated Monthly Cost:
- Assuming 100 builds/month × 10 min avg = 17 hours
- On-Demand: ~$6/month
- Spot: ~$2/month
macOS Runners (iOS/Xcode)
Instance Types:
| Instance | vCPU | Memory | Cost/hr | Min Allocation |
|---|---|---|---|---|
| mac2.metal | 12 | 32 GB | $1.083 | 24 hours |
| mac2-m2.metal | 8 | 24 GB | $0.65 | 24 hours |
| mac2-m2pro.metal | 12 | 32 GB | $0.77 | 24 hours |
Critical Constraint: AWS requires 24-hour minimum allocation for Mac instances.
Estimated Monthly Cost:
- Minimum: 468/month (mac2-m2.metal)
- Typical: 554/month (mac2-m2pro.metal)
Cost Comparison
| Scenario | Current Cost | EC2 Cost | Savings |
|---|---|---|---|
| Android only (Linux) | ~$0 (self-hosted) | ~$6/month | -$6 |
| iOS only (macOS) | ~$0 (self-hosted) | ~$500/month | -$500 |
| Full migration | ~$0 | ~$506/month | -$506 |
| Hybrid (EC2 Linux + self-hosted macOS) | ~$0 | ~$6/month | -$6 |
Architecture Options
Option 1: Full EC2 Migration
┌─────────────────────────────────────────────────────────┐
│ GitHub Actions │
└─────────────────────────┬───────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ EC2 Linux │ │ EC2 Linux │ │ EC2 macOS │
│ (Android) │ │ (Gradle) │ │ (iOS) │
└─────────────┘ └─────────────┘ └─────────────┘
Pros:
- 24/7 availability
- Consistent environment
- No developer machine dependency
Cons:
- ~$500+/month for macOS
- AWS account management overhead
- Network latency for large artifacts
Option 2: Hybrid (EC2 Linux + Self-Hosted macOS)
┌─────────────────────────────────────────────────────────┐
│ GitHub Actions │
└─────────────────────────┬───────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ EC2 Linux │ │ EC2 Linux │ │ Self-Hosted │
│ (Android) │ │ (Gradle) │ │ macOS (iOS) │
└─────────────┘ └─────────────┘ └─────────────┘
Pros:
- Low cost (~$6/month)
- Eliminates Windows complexity
- macOS still available when developer is active
Cons:
- iOS builds still depend on availability
- Mixed architecture remains (EC2 + self-hosted)
Option 3: Linux-Only with Cross-Compilation
┌─────────────────────────────────────────────────────────┐
│ GitHub Actions │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────┐
│ EC2 Linux │
│ (Android + KMP) │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Manual iOS Builds │
│ (Xcode Cloud/Local)│
└─────────────────────┘
Pros:
- Lowest cost (~$6/month)
- Simplest infrastructure
- Linux-only = consistent shell/encoding
Cons:
- No automated iOS builds
- KMP iOS artifacts require manual verification
- Breaks iOS CI/CD pipeline
Option 4: GitHub-Hosted Only
┌─────────────────────────────────────────────────────────┐
│ GitHub Actions │
└─────────────────────────┬───────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ ubuntu- │ │ ubuntu- │ │ macos- │
│ latest │ │ latest │ │ latest │
└─────────────┘ └─────────────┘ └─────────────┘
Estimated Cost:
- Linux: 8/month
- macOS: 40/month
- Total: ~$48/month
Pros:
- Zero infrastructure management
- Always available
- Pay-per-use pricing
Cons:
- macOS costs add up with frequent builds
- Less control over environment
- Slower cold-start times
Recommendation
Short Term: Option 2 (Hybrid)
-
Migrate Android/Gradle to EC2 Linux
- Eliminates Windows runner complexity
- Consistent Linux environment
- ~$6/month cost
-
Keep Self-Hosted macOS for iOS
- Avoid $500+/month macOS EC2 cost
- Accept availability limitations
- Use GitHub-hosted macos-latest as fallback for critical builds
Long Term: Re-evaluate
- If iOS build frequency increases: Consider Xcode Cloud or dedicated EC2 mac
- If costs are acceptable: Full GitHub-hosted for simplicity
- If team grows: EC2 mac becomes more cost-effective per-developer
Implementation Plan
Phase 1: EC2 Linux Setup
- Create EC2 instance (c6i.2xlarge)
- Install GitHub Actions runner
- Configure Android SDK, JDK, Gradle
- Test with Android build workflow
- Migrate Android CI to EC2 runner
Phase 2: Workflow Simplification
- Remove Windows-specific conditionals
- Standardize on Bash scripts
- Update runner selection logic
- Remove PowerShell workarounds
Phase 3: Monitoring & Optimization
- Track build times and costs
- Implement Spot instance failover
- Consider auto-scaling based on queue depth
- Evaluate cold-start vs always-on trade-offs
Cost Projection
| Month | EC2 Linux | Self-Hosted macOS | GitHub-Hosted Fallback | Total |
|---|---|---|---|---|
| 1 | $10 (setup) | $0 | $5 | $15 |
| 2-12 | $6/month | $0 | $2/month | $8/month |
| Year 1 | $76 | $0 | $27 | $103 |
Compare to full GitHub-hosted: ~$576/year
Savings: ~$473/year while improving reliability for Android builds.
Open Questions
- Spot Instance Reliability: How often do Spot instances get interrupted during builds?
- Runner Registration: Should we use ephemeral runners or persistent registration?
- Artifact Caching: Can we use S3 for Gradle/CocoaPods cache?
- Security: VPC configuration for GitHub Actions connectivity?