Come eseguire un runner self-hosted CircleCI su un Mac
CircleCI machine runner 3 si installa su macOS dal tap Homebrew di CircleCI e gira come LaunchAgent. Crea un namespace e una resource class, copia il token, mettilo nel config.yaml del runner e avvia il servizio. I job lo raggiungono con machine: true e resource_class: namespace/name.
Cosa ti serve prima
- Diritti di amministratore dell’organizzazione in CircleCI. Un amministratore deve accettare i termini dei runner in Org, poi Runners, prima che compaia il menu.
- Almeno un credito sull’account. CircleCI dice che i job dei runner non consumano crediti, ma archiviazione e traffico di rete sì.
- Un Mac Apple silicon con accesso amministratore, Homebrew e Xcode.
sha256sum, che CircleCI indica come prerequisito. Lo ottieni conbrew install coreutils.
1. Crea un namespace e una resource class
Nell’app web apri Runners e seleziona Create Resource Class. Ogni organizzazione ha un solo namespace. Se pubblichi orb, ce l’hai già. Dai alla resource class un nome come mac-mini-m6. Salva e copia il token. CircleCI lo mostra una sola volta.
La CLI fa la stessa cosa:
circleci namespace create <name> --org-id <your-organization-id> circleci runner resource-class create <namespace>/<resource-class> <description> --generate-token
2. Installa il runner con Homebrew
brew tap circleci-public/circleci brew trust circleci-public/circleci brew install circleci-runner
La riga centrale è nuova. Homebrew 7.0.7, la versione sul nostro Mac a ottobre 2026, si rifiuta di caricare pacchetti da un tap di terzi finché non lo dichiari fidato. La pagina di CircleCI non mostra ancora questo passo. Il runner arriva come cask di Homebrew.
macOS potrebbe mostrare un avviso: è stato aggiunto un elemento in background di Circle Internet Services. È normale. Homebrew scrive anche il plist del LaunchAgent in ~/Library/LaunchAgents/com.circleci.runner.plist.
3. Aggiungi il token a config.yaml
nano $HOME/Library/Preferences/com.circleci.runner/config.yaml
runner: name: "mac-mini-m6" working_directory: "/Users/$USER/Library/com.circleci.runner/workdir" cleanup_working_directory: true api: auth_token: "your-resource-class-token"
Con cleanup_working_directory attivo, ogni job parte da un checkout pulito. La DerivedData di Xcode sta per impostazione predefinita in ~/Library/Developer/Xcode/DerivedData, quindi le cache di build restano comunque. Se passi -derivedDataPath dentro la directory di lavoro, la pulizia la cancella dopo ogni job.
Proteggi il token
Il token della resource class permette a una macchina di prendere i job di quella classe. Chiunque lo legga può collegare una sua macchina e ricevere i tuoi job, con i tuoi secret. Rendi il file di configurazione accessibile solo al tuo utente, e ruota il token se viene divulgato.
chmod 600 $HOME/Library/Preferences/com.circleci.runner/config.yaml ls -l $HOME/Library/Preferences/com.circleci.runner/config.yaml
Lo stesso ragionamento vale per i job. Girano con l’utente macOS che ha avviato il runner, sullo stesso disco di tutto il resto. Collega a questa resource class solo progetti fidati.
4. Accetta la notarizzazione
Il binario arriva da internet, quindi macOS deve approvarlo. CircleCI documenta prima il controllo della firma, poi la rimozione dell’attributo di quarantena.
spctl -a -vvv -t install "$(brew --prefix)/bin/circleci-runner" sudo xattr -r -d com.apple.quarantine "$(brew --prefix)/bin/circleci-runner"
Il primo comando dovrebbe rispondere accepted, con source Notarized Developer ID.
5. Avvia il runner nel dominio GUI
Esegui questi comandi dal Terminale sul desktop del Mac. Il dominio GUI è la sessione desktop dell’utente connesso. È lì che vivono il simulatore e il portachiavi di login.
launchctl bootstrap gui/$(id -u) $HOME/Library/LaunchAgents/com.circleci.runner.plist launchctl enable gui/$(id -u)/com.circleci.runner launchctl kickstart -k gui/$(id -u)/com.circleci.runner launchctl print gui/$(id -u)/com.circleci.runner
CircleCI documenta anche un’opzione con il dominio utente per le sessioni headless. Sposta il plist in /Library/LaunchAgents. Su macOS 27 abbiamo visto un plist in quella cartella bloccare il login automatico a ogni avvio. Vedi login automatico su un Mac headless. Per il lavoro iOS consigliamo il dominio GUI con il login automatico.
6. Fallo sopravvivere a un riavvio
Un plist in ~/Library/LaunchAgents si carica quando il suo utente fa il login. Attiva il login automatico per questo account in Impostazioni di Sistema, in Utenti e gruppi. Disattiva lo stop con sudo pmset -a sleep 0. Riavvia una volta e controlla di nuovo launchctl print. I log sono in ~/Library/Logs/com.circleci.runner/runner.log.
7. Manda un job sul Mac
version: 2.1
jobs:
ios-tests:
machine: true
resource_class: your-namespace/mac-mini-m6
steps:
- checkout
- run:
name: Run tests
command: |
rm -rf build/TestResults.xcresult
xcodebuild test -project MyApp.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' -resultBundlePath build/TestResults.xcresult
- run:
name: Zip result bundle
when: always
command: ditto -c -k --keepParent build/TestResults.xcresult TestResults.xcresult.zip
- store_artifacts:
path: TestResults.xcresult.zip
workflows:
ios:
jobs:
- ios-testsLa documentazione di CircleCI indica due campi obbligatori per un job su runner: machine: true e la resource_class. Qui non c’è una chiave macos: xcode:, perché non scegli un’immagine. Il job usa la versione di Xcode selezionata sul Mac. Su un Mac MacRun è Xcode 26.6 con il runtime del simulatore iOS 26.5.
Errori comuni e soluzioni
Refusing to load cask ... from untrusted tap. Eseguibrew trust circleci-public/circleci, poi installa di nuovo.- macOS blocca il binario. Hai saltato il passo della notarizzazione. Esegui il comando
xattrqui sopra. - I job vanno in coda ma non partono mai. Controlla che la resource class in config.yml sia quella che hai creato, poi leggi
runner.log. - Il Docker layer caching non funziona. CircleCI lo indica come non supportato sui runner self-hosted.
xcodebuild: error: Existing file at -resultBundlePath. Cancella il vecchio bundle prima dello step di test. Ci è successo su Xcode 26.6.
Per fermare il runner usa launchctl bootout gui/$(id -u)/com.circleci.runner. Per rimuoverlo esegui brew uninstall --cask circleci-public/homebrew-circleci/circleci-runner.
Perché un Mac dedicato aiuta
Il vantaggio principale sono le cache calde. Nel nostro benchmark abbiamo compilato l’app iOS di Wikipedia con Xcode 26.6. Un job tipico dopo una piccola modifica ha richiesto 27 secondi su un M6 caldo. Ne ha richiesti 269 su un runner macos-26 nuovo ospitato da GitHub. Una build pulita ha richiesto 86 secondi contro 183.
Quando basta macOS in hosting di CircleCI
CircleCI ha i suoi executor Mac. La sua documentazione, letta a ottobre 2026, elenca m4pro.medium con 6 vCPU e 28 GB, e m4pro.large con 12 vCPU e 56 GB. Entrambi hanno più memoria del nostro M6 da 16 GB. Se la tua suite ha bisogno di tanta memoria, o fai build poche volte a settimana, resta sull’hosting. Lascia perdere MacRun anche se ti serve uno SLA, un IP statico o più regioni.
Vedi altri sistemi di CI per la parte MacRun della configurazione, oppure confronta i costi con i tuoi minuti.
Domande frequenti
Il runner self-hosted di CircleCI è gratis?
+
CircleCI dice che l’esecuzione sui runner non consuma crediti. Ti serve almeno un credito sull’account, perché archiviazione e traffico di rete possono comunque essere fatturati.
Dove si trova la configurazione del runner CircleCI su macOS?
+
In $HOME/Library/Preferences/com.circleci.runner/config.yaml. I log vanno in $HOME/Library/Logs/com.circleci.runner/runner.log.
Devo usare il dominio GUI o il dominio utente?
+
Per le build iOS, il dominio GUI con il login automatico. Gira dentro la sessione desktop di cui hanno bisogno il simulatore e il portachiavi di login.
Il Docker layer caching funziona su un runner self-hosted CircleCI?
+
No. CircleCI indica il Docker layer caching come non supportato sui runner self-hosted.