Cara menambahkan Mac sebagai agen Jenkins untuk build iOS
Untuk menambahkan Mac ke Jenkins, buat permanent node yang terhubung ke controller. Di Mac, pasang Java 21 dan jalankan agent.jar dengan opsi -webSocket. Bungkus perintah itu dalam LaunchAgent dan nyalakan login otomatis, agar agen tersambung lagi setelah reboot. Lalu beri node itu label macos dan arahkan stage iOS Anda ke sana.
Yang Anda butuhkan lebih dulu
- Controller Jenkins yang bisa dijangkau Mac lewat HTTPS.
- Mac Apple silicon dengan akses admin, Homebrew, dan Xcode.
- Versi Java yang tepat. Kebijakan dukungan Java dari Jenkins, yang kami baca pada Oktober 2026, menyebut LTS 2.555.1 ke atas butuh Java 21 atau 25. Aturan itu juga berlaku untuk agen, bukan hanya controller.
- Sesi desktop di Mac untuk langkah terakhir, lewat screen sharing.
1. Pasang Java di Mac
brew install openjdk@21 /opt/homebrew/opt/openjdk@21/bin/java -version
Homebrew memasang JDK ini sebagai keg-only, jadi ia tidak ada di PATH Anda. Pakai path lengkap di atas di semua tempat. Dengan begitu agen juga tetap di Java 21 saat JDK yang lebih baru datang nanti.
2. Buat node di controller
- Buka Manage Jenkins, lalu Nodes, lalu New Node. Pilih Permanent Agent.
- Number of executors: 1. Dokumentasi Jenkins sendiri menyebut satu executor per node sebagai pengaturan paling aman. Build Xcode sudah memakai semua core.
- Remote root directory:
/Users/YOUR-USER/jenkins. - Labels:
macos xcode. - Usage: hanya jalankan job dengan label expression yang cocok dengan node ini. Ini mencegah job Linux masuk ke Mac Anda.
- Launch method: Launch agent by connecting it to the controller.
Simpan. Halaman node sekarang menampilkan perintah untuk menjalankan agen, nama agen, dan secret heksadesimal yang panjang. Secret itu terikat ke nama agen. Jika bocor, Jenkins meminta Anda tidak memakai nama itu lagi.
3. Unduh agent.jar dan uji secara manual
Jenkins menyediakan agent.jar yang cocok untuk controller Anda di /jnlpJars/agent.jar. Simpan secret di file dan teruskan dengan @, agar secret tidak pernah muncul di daftar proses.
mkdir -p ~/jenkins && cd ~/jenkins curl -sO https://jenkins.example.com/jnlpJars/agent.jar echo 'PASTE-THE-SECRET' > secret-file chmod 600 secret-file /opt/homebrew/opt/openjdk@21/bin/java -jar agent.jar \ -url https://jenkins.example.com/ \ -name mac-mini-1 \ -secret @secret-file \ -workDir "$HOME/jenkins" \ -webSocket
Halaman node seharusnya berubah menjadi connected. Tekan Control C untuk menghentikannya. Dengan -webSocket, agen membuat satu koneksi HTTPS. Tanpa opsi itu, agen juga butuh port TCP inbound terpisah di controller.
4. Jalankan agen dari LaunchAgent
launchd menyalakan agen saat login dan menyalakannya ulang jika berhenti. Jalankan ini dari Terminal di desktop Mac. Heredoc di bawah mengisi path folder home Anda.
mkdir -p ~/Library/LaunchAgents
cat > ~/Library/LaunchAgents/local.jenkins-agent.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>local.jenkins-agent</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/openjdk@21/bin/java</string>
<string>-jar</string><string>$HOME/jenkins/agent.jar</string>
<string>-url</string><string>https://jenkins.example.com/</string>
<string>-name</string><string>mac-mini-1</string>
<string>-secret</string><string>@$HOME/jenkins/secret-file</string>
<string>-workDir</string><string>$HOME/jenkins</string>
<string>-webSocket</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key><string>/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
<key>LANG</key><string>en_US.UTF-8</string>
</dict>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>ThrottleInterval</key><integer>30</integer>
<key>StandardOutPath</key><string>$HOME/jenkins/agent.log</string>
<key>StandardErrorPath</key><string>$HOME/jenkins/agent.log</string>
</dict>
</plist>
EOF
plutil -lint ~/Library/LaunchAgents/local.jenkins-agent.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/local.jenkins-agent.plist
launchctl print gui/$(id -u)/local.jenkins-agent | head -20Kami sudah mengecek plist ini dengan plutil -lint. Mengapa LaunchAgent dan bukan LaunchDaemon? Daemon berjalan di luar sesi login mana pun. Simulator dan login keychain hidup di dalam sesi login. GitLab dan Buildkite memberi alasan yang sama untuk agen Mac mereka.
Simpan plist di ~/Library/LaunchAgents. Di macOS 27, kami melihat plist di /Library/LaunchAgents merusak login otomatis di setiap boot. Detailnya ada di login otomatis di Mac headless.
5. Pastikan bertahan setelah reboot
Nyalakan login otomatis untuk akun agen di System Settings, bagian Users and Groups. Cegah Mac agar tidak tidur. Lalu reboot dan pantau halaman node.
sudo pmset -a sleep 0 sudo shutdown -r now # then, after it is back: tail -n 20 ~/jenkins/agent.log
6. Jenkinsfile dengan stage iOS
pipeline {
agent { label 'macos' }
options { timeout(time: 30, unit: 'MINUTES') }
stages {
stage('Test') {
steps {
sh 'xcodebuild -version'
sh 'rm -rf build/TestResults.xcresult'
sh "xcodebuild test -project MyApp.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' -resultBundlePath build/TestResults.xcresult"
}
}
}
post {
always {
sh 'ditto -c -k --keepParent build/TestResults.xcresult build/TestResults.xcresult.zip || true'
archiveArtifacts artifacts: 'build/TestResults.xcresult.zip', fingerprint: true
}
}
}Result bundle berupa folder, jadi kami men-zip-nya dengan ditto sebelum diarsipkan. Buka file zip itu di Mac mana pun, lalu klik dua kali bundle-nya untuk melihatnya di Xcode.
Dua versi Xcode di satu agen? Pilih satu per pipeline dengan DEVELOPER_DIR. Halaman manual xcode-select dari Apple menyebut variabel ini mengesampingkan pilihan sistem tanpa mengubahnya. Atur di blok environment, agar job lain di Mac itu tidak terpengaruh:
environment {
DEVELOPER_DIR = '/Applications/Xcode.app/Contents/Developer'
}Taruh blok itu di dalam pipeline, di sebelah agent. Mengubah pengaturan global dengan sudo xcode-select -s juga bisa, tapi itu mengubah semua job di mesin sekaligus.
Error umum dan cara memperbaikinya
- Agen tersambung, lalu hilang setelah reboot. Tidak ada yang login, jadi LaunchAgent tidak pernah mulai. Cek login otomatis.
launchctl bootstrapgagal dengan error domain lewat SSH. Jalankan dari Terminal di desktop. GitLab dan Buildkite mendokumentasikan error yang sama untuk LaunchAgent mereka.- Agen menolak mulai dan menyebut Java. Jenkins mengecek versi Java saat diluncurkan. Samakan dengan versi di kebijakan dukungannya.
xcodebuild: error: Existing file at -resultBundlePath. Workspace tetap ada di antara build. Hapus bundle lama lebih dulu, seperti di Jenkinsfile.
Mengapa Mac khusus membantu
Agen permanen menyimpan workspace dan DerivedData Xcode di antara build. Hasilnya adalah build inkremental. Dalam benchmark kami, kami memakai aplikasi iOS Wikipedia di Xcode 26.6, median dari 3 run. Perubahan kecil di-build ulang dalam 27 detik di M6 yang hangat. Runner macos-26 baru yang di-hosting GitHub butuh 269 detik untuk job yang sama.
Kapan Anda tidak membutuhkan ini
Jika Anda belum memakai Jenkins, jangan mulai hanya untuk satu aplikasi iOS. Layanan hosted dengan runner Mac lebih sedikit perawatannya. Dengan tarif GitHub $0.062 per menit macOS (dicek September 2026), Mac berharga tetap $139 balik modal setelah sekitar 2,242 menit sebulan. Di bawah itu, bayar per menit lebih murah. MacRun juga tidak cocok jika controller Anda hanya menerima agen dari IP tetap. Kami tidak punya IP statis.
Halaman sistem CI lain kami membahas Jenkins di Mac MacRun secara singkat. Panduan pipeline CI/CD iOS membahas apa yang perlu diisi di setiap stage.
Pertanyaan yang sering diajukan
Sebaiknya agen Mac Jenkins memakai SSH atau inbound launch?
+
Inbound cocok saat Mac bisa menjangkau controller, tapi controller tidak bisa menjangkau Mac. Dengan -webSocket, agen hanya butuh HTTPS ke controller.
Versi Java apa yang dibutuhkan agen Jenkins di macOS?
+
Keluarga versi yang sama dengan controller. Kebijakan dukungan Jenkins, yang kami baca pada Oktober 2026, mewajibkan Java 21 atau 25 mulai LTS 2.555.1.
Berapa executor yang sebaiknya dimiliki agen Mac?
+
Mulai dengan satu. Jenkins menyebut satu executor per node sebagai pengaturan paling aman, dan build Xcode sudah memakai semua core.
Mengapa agen Mac Jenkins saya tidak tersambung lagi setelah restart?
+
LaunchAgent baru berjalan setelah penggunanya login. Nyalakan login otomatis untuk akun itu dan simpan plist di ~/Library/LaunchAgents.