blob: 750fd08a3ae16dbe5d9cea3a030a892dfcb687f4 [file] [view]
# Darwin builders on AWS
Darwin builders on AWS run on [EC2 Mac
Instances](https://aws.amazon.com/ec2/instance-types/mac/), which are dedicated
Mac Mini hosts. These dedicated hosts must be allocated for at least 24 hours at
a time. They can be reimaged at any time while allocated, but the reimaging
process takes around an hour. Thus, for faster refresh time on hermetic
builders, we run buildlets as MacOS guests inside of QEMU on the dedicated
hosts.
## Creating a dedicated host
Note that if you simply need more instances, an AMI with the final state is
saved on the AWS account.
To bring up a new host:
1. In the EC2 console, go to "Dedicated Hosts" -> "Allocate Dedicated Host".
2. Configure host type, zone. Instance family `mac1` is amd64; `mac2` is arm64.
3. Enable "Instance auto-placement", which allows any instance to run on this
host.
4. Once the host is allocated and available, go to the "Instances" page and
click "Launch an instance".
5. Select a macOS AMI. If starting fresh, select the latest macOS version from
"Quick Start". If simply adding more instances, a fully set-up AMI is saved
in "My AMIs".
6. Select a "Key pair" for SSH access. `ec2-go-builders` for official builders,
a custom key for testing. You will need the private key to login.
7. Configure a 200GB disk.
8. If creating from a fully set-up AMI, uncheck "Allow SSH Traffic".
9. Under "Advanced", select "Tenancy" -> "Dedicated host".
10. Other settings can remain at default. Launch instance.
If creating from a fully set-up AMI, you are done!
SSH with the key pair using the "Public IPv4 DNS" address from the "Instances"
page. This won't appear until the instance is booted.
```sh
$ export KEY_PATH=~/.ssh/ec2-go-builders.pem
$ ssh -i $KEY_PATH ec2-user@$INSTANCE
```
[See the AWS
docs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-vnc)
for setting up remote desktop access. Note that not all VNC client work with
Apple's server. [Remmina](https://remmina.org/) works.
The OS will only use 100GB of the disk by default. You must [increase the volume
size](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-increase-volume)
to utilize the full disk. This can be done while the disk is in use.
Continue below to create a new guest image, or [skip ahead](#guest-creation) to
use a pre-created image.
## Creating a new guest image
Steps to create a new QEMU macOS guest image:
1. Build (`make dist`) or
[download](https://github.com/thenickdude/KVM-Opencore/releases) a copy of
the OpenCore bootloader from
https://github.com/thenickdude/KVM-Opencore.
1. Grab the `.iso.gz` file, `gunzip` it, and rename to `opencore.img` (it
is a raw disk image, not actually an `iso`).
2. Create a macOS recovery disk image:
1. Clone https://github.com/kholia/OSX-KVM.
2. `cd scripts/monterey && make Monterey-recovery.dmg`
3. Download the UTM QEMU fork and extract to `~/sysroot-macos-x86_64`.
1. Available as `Sysroot-macos-x86_64` in
https://github.com/utmapp/UTM/actions?query=event%3Arelease builds.
4. Create a disk image to install macOS to.
1. `DYLD_LIBRARY_PATH="$HOME/sysroot-macos-x86_64/lib"
"$HOME/sysroot-macos-x86_64/bin/qemu-img" create -f qcow2
macos-monterey.qcow2 128G`
5. Determine the magic Apple OSK value.
1. Either [read it directly from the machine](https://www.nicksherlock.com/2021/10/installing-macos-12-monterey-on-proxmox-7/#:~:text=Fetch%20the%20OSK%20authentication%20key), or [find it in some code](https://github.com/kholia/OSX-KVM/blob/master/OpenCore-Boot-macOS.sh#L45).
6. Copy the shell scripts from this directory to `$HOME`.
6. Use `$HOME/start-installer.sh macos-monterey.qcow2 opencore.img
Monetery-recovery.dmg $OSK_VALUE` to launch the macOS installer in QEMU.
NOTE: If networking isn't working on older versions of macOS, swap the
networking flag in `qemu.sh`.
This starts QEMU with the display on a VNC server at `localhost:5901`. Use SSH
port forwarding to forward this to your local machine:
```
$ ssh -i $KEY_PATH -L 5901:localhost:5901 -N ec2-user@$INSTANCE
```
Then use a VNC client to connect to `localhost:5901`.
1. Once connected, select "macOS Base Image" from the bootloader to launch the
installer.
2. In the installer, open the Disk Utility, find the ~128GB QEMU hard disk,
click "Erase", name it "macOS", and leave other options at the default
settings.
3. When formatting is complete, close Disk Utililty, and select "Reinstall
macOs Monterey".
4. Click through the installer. The VM will reboot a few times. When it does,
select "macOS Installer" from the bootloader to continue installation.
Installation is complete when "macOS Installer" is replaced with "MacOS".
5. Select "macOS" and go through the macOS setup as described in the [generic
setup notes](../setup-notes.md).
Once macOS is fully installed, we will install OpenCore on the primary disk and
configure it to autoboot to macOS.
1. In the guest, find the OpenCore and primary disks with `diskutil list`.
* The OpenCore disk contains only one parition, of type "EFI". e.g., it may
be /dev/disk0, EFI partition /dev/disk0s1.
* The primary disk contains two paritions, one of type "EFI", one of type
"Apple_APFS". e.g., it may be /dev/disk2, EFI partition /dev/disk2s1.
2. Copy the OpenCore EFI partition over the primary disk EFI partition.
* `sudo dd if=/dev/disk0s1 of=/dev/disk2s1`
3. Mount the primary disk EFI partition to edit the configuration.
* `sudo mkdir /Volumes/EFI`
* `sudo mount -t msdos /dev/disk2s1 /Volumes/EFI`
4. Open `/Volumes/EFI/EFI/OC/config.plist`.
* Change the Misc -> Boot -> Timeout option from `0` to `1` to set the
bootloader to automatically boot macOS with a 1s delay.
* In the `7C436110-AB2A-4BBB-A880-FE41995C9F82`, section, add `-v` to the
`boot-args` string value. This applies the `nvram` option mentioned in
[the setup notes](../setup-notes.md).
5. Shutdown the VM and boot it again with `start-mutable.sh`.
```sh
$ $HOME/start-mutable.sh macos-monterey.qcow2 $OSK_VALUE
```
Now complete the remainder of the [machine setup](../setup-notes.md). For SSH
access, the guest should be reachable at 192.168.64.2 or 192.168.64.3 from the
host machine.
Copy complete images to `s3://go-builder-data/darwin/` for use on other
builders.
## Set up automated guest creation {#guest-creation}
1. Download the latest image from `s3://go-builder-data/darwin/` and save it to
`$HOME/macos.qcow2`.
2. Download the UTM QEMU fork and extract to `~/sysroot-macos-x86_64`.
1. Available as `Sysroot-macos-x86_64` in
https://github.com/utmapp/UTM/actions?query=event%3Arelease builds.
3. Copy `bootptab` to `/etc/bootptab`.
4. Restart the system DHCP server to pick up the new `bootptab`: `sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/bootps.plist; sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist`.
4. Build `golang.org/x/build/cmd/runqemubuildlet` and copy it to `$HOME`.
5. Create `$HOME/loop1.sh`:
```sh
#!/bin/bash
while true; do
echo "Running QEMU..."
sudo $HOME/runqemubuildlet -guest-os=darwin -macos-version=${MACOS_VERSION?} -osk=${OSK_VALUE?} -guest-index=1 -buildlet-healthz-url="http://192.168.64.101:8080/healthz"
done
```
4. Create `$HOME/loop2.sh`:
```sh
#!/bin/bash
while true; do
echo "Running QEMU..."
sudo $HOME/runqemubuildlet -guest-os=darwin -macos-version=${MACOS_VERSION?} -osk=${OSK_VALUE?} -guest-index=2 -buildlet-healthz-url="http://192.168.64.102:8080/healthz"
done
```
Replace `${OSK_VALUE?} with the OSK value described in the previous section.
5. Setup Automator:
1. Open Automator
2. File > New > Application
3. Add "Run shell script"
4. `open -a Terminal.app $HOME/loop1.sh`
5. Save to desktop twice as `run-builder1`
2. File > New > Application
3. Add "Run shell script"
4. `open -a Terminal.app $HOME/loop2.sh`
5. Save to desktop twice as `run-builder2`
Note that loop1.sh and loop2.sh guests will have a display at VNC port 5901 and
5902, respectively.
6. Setup login:
1. Users & Groups > ec2-user > Login Items > add run-builder1
2. Users & Groups > ec2-user > Login Items > add run-builder2
3. Users & Groups > Login Options > auto-login ec2-user
4. Desktop & Screensaver > uncheck show screensaver
Once image is set up and working, stop the instance and create an AMI copy of
the instance. On the EC2 "Instances" page, select the instance, and click
"Actions" -> "Image and templates" -> "Create Image".
Either create a new instance from this image with no SSH access, or edit the
instance networking inbound rules to remove SSH access.
## References
* [EC2 Mac Instances USer
Guide](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html):
Contains most of the useful how-tos on working with Mac instances.
* [Remmina](https://remmina.org/): VNC client that works with Apple's [VNC
server](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-vnc)
(not all clients work).
* [QEMU MacOS install
guide](https://www.nicksherlock.com/2021/10/installing-macos-12-monterey-on-proxmox-7/):
Guide with similar instructions for MacOS in QEMU.