Run GitHub Actions Self-hosted macOS Runners on Apple M1 Mac

Part-2: Use M1 Mac to power your own iOS CI/CD pipelines

Soumya Mahunt
Better Programming

--

In part-1 of this series, we saw creating self-hosted Microsoft Azure’s DevOps agents using apple silicon machines.

For those who are using GitHub actions, in this post, we will walk through the process of using an M1-based machine for GitHub actions self-hosted runners.

Prepare for installation

First, you need to mirror the configuration of GitHub-hosted runners to avoid any future errors. For this, create a user account named runner and this account to the admin group:

After a reboot, your new user account will be ready. From now on, use this account to configure and run our self-hosted runner.

NOTE: you need to install pre-requisite tools like git if not done already and also install Rosetta 2 on your Apple M1 machine.

Set up and configure Runner

You can create a self-hosted runner at either repository level or organization level or enterprise level. To do so, navigate to the Settings tab at your required level. Select Actions from the sidebar navigation, next select the Runners option and click New self-hosted runner.

When you do, you’ll see a view with setup commands and example usage as shown above. From here, simply open a terminal, and run the commands in order. On running config.sh, you will be presented following dialogue in the terminal:

Here, choose your runner group and name or accept the default values. You can optionally provide additional labels for your runner, the usage of labels will be explained later. Then, you can customize the work folder or accept the default value _work.

Finally, you need to configure additional environment variables to ensure actions work properly on your self-hosted runner. The most important being ImageOS and XCODE_12_DEVELOPER_DIR/XCODE_11_DEVELOPER_DIR. For ImageOS you need to provide the OS name (macos here) and version in the format macos*version*, i.e. maos12. And for XCODE_*_DEVELOPER_DIR, provide the path to the Xcode developer directory for the applicable version /Applications/Xcode_12.5.1.app/Contents/Developer. You can add these variables in the .env file in the runner folder. If your actions require additional environment variables you can add them here as well.

With that, you can finally execute the run.sh script that will be available in your new runner directory.

Confirm success

Once you’ve completed the setup, you should see the output in the terminal that the runner is up and Listening for Jobs. You can then navigate in your browser to your GitHub repository, click the Settings tab, and then select Actions and then Runners again in the sidebar, where you should see your newly associated runner with a green dot and a status of Idle, as shown below.

Now to run actions on your self-hosted runner, you need to modify your workflow file jobs.<job_id>.runs-on property like this:

In the array for the self-hosted runner, you can provide additional labels that you have provided during configuration. After committing changes, you can enjoy improved performance with self-hosting.

Configure tool cache

Many setup actions download tools and store them in the tool cache folder at /Users/runner/hostedtoolcache. You can manage required tools with homebrew and use the following python script to link installed tools to your tool cache folder:

With GitHub actions, you can run this script before every job by providing the above script path toACTIONS_RUNNER_HOOK_JOB_STARTED environment variable in the .env file. By doing so, you can ensure your installed tools will always be available in the tool cache before any job.

Sudoers configuration

If your actions require root privileges, you can configure your sudoers file by typing sudo visudo. If your runner is only used for the private repositories (this is the default recommendation provided by GitHub due to the security of runners) you can add the following line in sudoers file:

runner ALL=(ALL) NOPASSWD: ALL

Alternatively, you can add restriction application level, so that these applications won’t require a password prompt. For example, setup-unity action requires root privileges for hdiutil, in that case, you can add hdiutil to no password prompt like this:

runner  ALL= NOPASSWD: /bin/hdiutil
# Or your additional applications with arguments:
runner ALL= NOPASSWD: /bin/hdiutil,/your_dir/your_bin your_args

All set?

Unfortunately no, although this is the basic setup required by most actions, some actions may require more additional tools to be pre-installed. Luckily, these actions specify these requirements in their documentation.

Feel free to point out if I missed anything and stay tuned for part-3 of this series, where I will talk about different steps you can take to optimize your pipeline for more performance.

--

--

Senior Software Engineer at MoEngage | System architecture enthusiast | Ex Tataneu