1. Mengapa GitLab Runner Self-Hosted di Mac?
GitLab menyediakan shared runner di Linux, tetapi membangun aplikasi iOS memerlukan macOS yang berjalan di perangkat keras Apple. Shared runner macOS milik GitLab sendiri terbatas dan mahal. Runner Mac Mini M4 self-hosted memberi Anda:
Paket gratis GitLab mencakup 400 menit CI/CD pada shared runner. Pada self-hosted, tidak ada batas.
Bangun pada chip M4 yang sama dengan yang dijalankan perangkat pengguna Anda. Tanpa overhead terjemahan Rosetta.
Instal versi Xcode, simulator, alat, dan dependensi apa pun yang Anda butuhkan.
Cache DerivedData, paket SPM, dan CocoaPods tetap ada di antara setiap eksekusi pipeline.
2. Instal GitLab Runner
SSH ke Mac Mini M4 Anda dan instal GitLab Runner menggunakan Homebrew:
# Connect to your Mac Mini M4
ssh admin@your-server-ip
# Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
# Install GitLab Runner
brew install gitlab-runner
# Verify installation
gitlab-runner --version
# Version: 17.7.0
# Git revision: ...
# Git branch: 17-7-stable
# GO version: go1.22.10
# Built: ...
# OS/Arch: darwin/arm64
Instal sebagai Layanan macOS
# Install the runner as a launchd service
# This ensures it starts automatically on boot
brew services start gitlab-runner
# Verify the service is running
brew services list | grep gitlab-runner
# gitlab-runner started admin ~/Library/LaunchAgents/homebrew.mxcl.gitlab-runner.plist
# Check runner status
gitlab-runner status
# gitlab-runner: Service is running
3. Daftarkan Runner
Buka proyek (atau grup) GitLab Anda dan navigasikan ke Settings > CI/CD > Runners > New project runner. Salin token registrasi.
Daftarkan dengan Alur Registrasi Runner Baru (GitLab 16+)
# Register the runner using the authentication token from GitLab UI
# (GitLab 16+ uses authentication tokens instead of registration tokens)
gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--token "YOUR_RUNNER_AUTHENTICATION_TOKEN" \
--executor "shell" \
--description "mac-mini-m4-runner" \
--tag-list "macos,apple-silicon,m4,ios,xcode"
Daftarkan dengan Token Registrasi Lama (GitLab 15 dan sebelumnya)
# For older GitLab instances using registration tokens
gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--registration-token "YOUR_REGISTRATION_TOKEN" \
--executor "shell" \
--description "mac-mini-m4-runner" \
--tag-list "macos,apple-silicon,m4,ios,xcode" \
--run-untagged="false"
Verifikasi Konfigurasi Runner
# View the runner config file
cat ~/.gitlab-runner/config.toml
# Expected output:
# concurrent = 2
# check_interval = 0
#
# [session_server]
# session_timeout = 1800
#
# [[runners]]
# name = "mac-mini-m4-runner"
# url = "https://gitlab.com/"
# token = "..."
# executor = "shell"
# [runners.cache]
# MaxUploadedArchiveSize = 0
# Adjust concurrency based on your hardware:
# Mac Mini M4 (16GB): concurrent = 2
# Mac Mini M4 Pro (24GB): concurrent = 3
# Mac Mini M4 Pro (48GB): concurrent = 4
Edit ~/.gitlab-runner/config.toml untuk menyesuaikan konkurensi:
# Edit the config
nano ~/.gitlab-runner/config.toml
# Set concurrent to match your hardware capacity
concurrent = 2
# Restart the runner to apply changes
gitlab-runner restart
Runner sekarang seharusnya muncul sebagai Online di proyek GitLab Anda pada Settings > CI/CD > Runners.
4. Buat .gitlab-ci.yml untuk iOS
Buat file .gitlab-ci.yml di root repositori Anda. Pipeline lengkap ini membangun, menguji, dan men-deploy aplikasi iOS Anda:
# .gitlab-ci.yml
stages:
- setup
- build
- test
- deploy
variables:
SCHEME: "MyApp"
WORKSPACE: "MyApp.xcworkspace"
DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2"
DERIVED_DATA: "${CI_PROJECT_DIR}/DerivedData"
# Only run on our Mac runner
default:
tags:
- macos
- m4
# ---- SETUP ----
setup:
stage: setup
script:
- sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
- xcodebuild -version
- swift --version
# Install CocoaPods if using Podfile
- |
if [ -f "Podfile" ]; then
pod install --repo-update
fi
cache:
key: pods-${CI_COMMIT_REF_SLUG}
paths:
- Pods/
- .spm-cache/
# ---- BUILD ----
build:
stage: build
needs: ["setup"]
script:
- |
xcodebuild build \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}" \
-clonedSourcePackagesDirPath ".spm-cache" \
CODE_SIGNING_ALLOWED=NO \
| xcbeautify
cache:
key: derived-data-${CI_COMMIT_REF_SLUG}
paths:
- DerivedData/
- .spm-cache/
artifacts:
paths:
- DerivedData/
expire_in: 1 hour
# ---- TEST ----
unit_tests:
stage: test
needs: ["build"]
script:
- |
xcodebuild test \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}" \
-resultBundlePath "TestResults.xcresult" \
-parallel-testing-enabled YES \
| xcbeautify
artifacts:
when: always
paths:
- TestResults.xcresult/
reports:
junit: TestResults.xcresult/report.junit
expire_in: 7 days
after_script:
- xcrun simctl shutdown all 2>/dev/null || true
# ---- DEPLOY ----
deploy_testflight:
stage: deploy
needs: ["unit_tests"]
only:
- main
script:
- |
# Install or update Fastlane
which fastlane || brew install fastlane
# Run Fastlane beta lane
fastlane beta
environment:
name: testflight
variables:
MATCH_PASSWORD: ${MATCH_PASSWORD}
APP_STORE_CONNECT_API_KEY_ID: ${APP_STORE_KEY_ID}
APP_STORE_CONNECT_API_ISSUER_ID: ${APP_STORE_ISSUER_ID}
APP_STORE_CONNECT_API_KEY_CONTENT: ${APP_STORE_KEY_CONTENT}
Tambahkan Variabel CI/CD di GitLab
Navigasikan ke Settings > CI/CD > Variables di proyek GitLab Anda dan tambahkan variabel-variabel ini sebagai "Masked" dan "Protected":
-
MATCH_PASSWORD- Kata sandi untuk enkripsi Fastlane Match -
APP_STORE_KEY_ID- ID Kunci API App Store Connect -
APP_STORE_ISSUER_ID- Issuer ID App Store Connect -
APP_STORE_KEY_CONTENT- Isi file kunci .p8
5. Optimalkan Performa
Konfigurasi Cache GitLab
GitLab Runner mendukung caching lokal untuk shell executor. Karena runner Anda persisten, cache lokal sangat efisien:
# In .gitlab-ci.yml, configure cache per branch:
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- DerivedData/
- .spm-cache/
- Pods/
policy: pull-push
# For test jobs that don't modify cache, use pull-only:
unit_tests:
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- DerivedData/
policy: pull
Gunakan Artifact untuk Data Antar-Stage
# Pass build artifacts between stages efficiently
build:
artifacts:
paths:
- DerivedData/Build/Products/
expire_in: 2 hours
# The test stage receives the built products without rebuilding
test:
needs: ["build"] # only download artifacts from the build job
script:
- xcodebuild test-without-building \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}"
Eksekusi Pengujian Paralel
# Split tests across parallel jobs using GitLab's parallel keyword
unit_tests:
stage: test
parallel: 2
script:
- |
# Use test plan partitioning or custom splitting
xcodebuild test \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}" \
-parallel-testing-enabled YES \
-maximum-parallel-testing-workers 4
Pembersihan Cache Terjadwal
# On the Mac Mini, set up a weekly cleanup cron job
crontab -e
# Add these lines:
# Clean DerivedData older than 7 days every Sunday at 3 AM
0 3 * * 0 find ~/builds/*/DerivedData -maxdepth 0 -mtime +7 -exec rm -rf {} + 2>/dev/null
# Clean old GitLab Runner builds older than 14 days
0 4 * * 0 find ~/builds -maxdepth 2 -mtime +14 -type d -exec rm -rf {} + 2>/dev/null
# Clean Homebrew cache monthly
0 5 1 * * /opt/homebrew/bin/brew cleanup --prune=30 2>/dev/null
6. Pemecahan Masalah
Runner menampilkan "offline" di GitLab
Periksa status layanan runner dan log-nya:
# Check service status
brew services list | grep gitlab-runner
# View logs
cat /usr/local/var/log/gitlab-runner.log
# Restart the service
brew services restart gitlab-runner
# Verify connectivity to GitLab
gitlab-runner verify
Error permission denied saat build
Runner mungkin memerlukan akses ke direktori developer Xcode:
# Ensure the runner user has Xcode access
sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
sudo xcodebuild -license accept
# If using simulators, ensure the user can access them
xcrun simctl list devices
Cache tidak dipulihkan
Pastikan cache key konsisten dan path-nya ada:
# Check cache directory permissions
ls -la ~/builds/
# The shell executor stores caches locally by default
# Verify the cache directory in config.toml:
cat ~/.gitlab-runner/config.toml
# Ensure [runners.cache] section has the right settings
# For local caching (most efficient for persistent runners):
# [runners.cache]
# Type = "" # empty = local cache
Build Xcode macet atau timeout
Ini sering disebabkan oleh prompt akses keychain atau masalah simulator:
# Unlock the keychain before builds
security unlock-keychain -p "YOUR_PASSWORD" ~/Library/Keychains/login.keychain-db
# Kill stuck simulators
xcrun simctl shutdown all
pkill -f "Simulator.app" 2>/dev/null || true
# Set a build timeout in .gitlab-ci.yml
build:
timeout: 30 minutes
7. FAQ
Bisakah saya menggunakan Docker executor di macOS?
Docker di macOS menjalankan container Linux dalam VM, yang tidak dapat mengakses API macOS, Xcode, atau simulator iOS. Untuk build iOS, Anda harus menggunakan shell executor. Docker cocok untuk Swift sisi server atau tugas berbasis Linux lainnya yang berjalan bersama runner Mac Anda.
Bagaimana cara mendaftarkan runner untuk grup GitLab?
Buka Settings > CI/CD > Runners > New group runner pada grup GitLab Anda. Gunakan token group runner alih-alih token proyek. Ini membuat runner tersedia untuk semua proyek dalam grup tersebut.
Haruskah saya menggunakan shell executor atau SSH executor?
Gunakan shell executor. Ia menjalankan perintah langsung di Mac, yang memberikan akses penuh ke Xcode, simulator, dan keychain. SSH executor ditujukan untuk mesin jarak jauh, yang tidak diperlukan ketika runner sudah berada di Mac.
Bisakah saya menjalankan runner GitLab dan GitHub Actions di Mac yang sama?
Ya. Kedua runner ringan dan dapat berdampingan di Mac Mini M4 yang sama. Cukup pastikan untuk memperhitungkan penggunaan sumber daya gabungan saat menetapkan tingkat konkurensi untuk masing-masing runner.
Bagaimana cara memperbarui GitLab Runner?
# Update via Homebrew
brew upgrade gitlab-runner
# Restart the service
brew services restart gitlab-runner
# Verify the new version
gitlab-runner --version
Mencari GitLab Runner yang dikelola sepenuhnya? Coba Cloud-Runner
Lewati proses pengaturan sepenuhnya. Cloud-Runner menyediakan GitLab Runner khusus yang telah dikonfigurasi sebelumnya pada perangkat keras Mac — tanpa instalasi atau pemeliharaan.