Panduan - CI/CD

Cara Menyiapkan GitHub Actions Self-Hosted Runner di Mac Mini M4

Panduan langkah demi langkah menyiapkan GitHub Actions self-hosted runner di Mac Mini M4 dedikasi. Build iOS lebih cepat, native Apple Silicon, dan hingga 10x lebih murah dibanding runner macOS yang di-host GitHub.

Baca 30 menit Diperbarui Maret 2026

1. Mengapa Menggunakan Self-Hosted Mac Runner?

Runner macOS yang di-host GitHub praktis tetapi mahal. Dengan $0.08 per menit, tim yang menjalankan 75 jam build per bulan membayar sekitar $360. Mac Mini M4 dedikasi dari MyRemoteMac berbiaya $85/bulan dengan menit build tanpa batas, memberi Anda hardware yang sama (atau lebih baik) dengan biaya jauh lebih murah.

Fitur Runner yang Di-host GitHub MyRemoteMac Self-Hosted
Biaya $0.08/menit (~$350/bln untuk 75 jam) $85/bln (menit tanpa batas)
Arsitektur Intel x86 (sebagian M1) Apple M4 (terbaru)
Kecepatan Build ~12 mnt (proyek menengah) ~4 mnt (proyek yang sama)
Cache Persisten Tidak (ephemeral) Ya (disk persisten)
Perangkat Lunak Kustom Terbatas Akses root penuh
Job Bersamaan 5 (gratis) / 20 (berbayar) Tanpa batas (hardware Anda)

Manfaat Utama: Karena runner bersifat persisten, DerivedData, cache SPM, dan CocoaPods dipertahankan di antara build. Ini saja dapat memangkas waktu build sebesar 50-70% dibanding runner ephemeral yang di-host GitHub yang selalu mulai dari nol setiap kali.

2. Prasyarat

Sebelum memulai, pastikan Anda memiliki hal-hal berikut:

  • Server Mac Mini M4 dari MyRemoteMac (mulai $85/bln)
  • Akun GitHub dengan akses admin ke repositori atau organisasi Anda
  • Akses SSH ke Mac Mini Anda (disediakan dengan langganan MyRemoteMac Anda)
  • Akun Apple Developer (untuk code signing dan provisioning profile)
  • Pemahaman dasar tentang YAML dan perintah terminal

3. Langkah 1: SSH ke Mac Mini Anda dan Instal Xcode

Pertama, hubungkan ke Mac Mini M4 Anda melalui SSH. Anda telah menerima kredensial saat menyiapkan server MyRemoteMac Anda.

Hubungkan melalui SSH

# Connect to your Mac Mini M4
ssh admin@your-server-ip

# Verify you're on Apple Silicon
uname -m
# Expected output: arm64

# Check macOS version
sw_vers
# ProductName:    macOS
# ProductVersion: 15.2
# BuildVersion:   24C101

Instal Xcode Command Line Tools

# Install Command Line Tools
xcode-select --install

# Accept the license agreement
sudo xcodebuild -license accept

# Verify installation
xcode-select -p
# /Library/Developer/CommandLineTools

Instal Xcode (Versi Lengkap)

Untuk build iOS, Anda memerlukan aplikasi Xcode lengkap. Cara tercepat menginstalnya di server headless adalah menggunakan xcodes:

# Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Add Homebrew to PATH
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

# Install xcodes CLI tool
brew install xcodes

# List available Xcode versions
xcodes list

# Install the latest stable Xcode
xcodes install 16.2

# Set it as the active Xcode
sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer

# Verify
xcodebuild -version
# Xcode 16.2
# Build version 16C5032a

Instal Simulator iOS

# Install the iOS 18 simulator runtime
xcodebuild -downloadPlatform iOS

# Verify simulator availability
xcrun simctl list runtimes
# == Runtimes ==
# iOS 18.2 (18.2 - 22C150) - com.apple.CoreSimulator.SimRuntime.iOS-18-2

4. Langkah 2: Instal GitHub Actions Runner

Sekarang mari unduh dan konfigurasikan agen GitHub Actions runner. Navigasikan ke repositori Anda di GitHub, buka Settings > Actions > Runners > New self-hosted runner, dan pilih macOS + ARM64.

Unduh dan Konfigurasikan

# Create a directory for the runner
mkdir -p ~/actions-runner && cd ~/actions-runner

# Download the latest runner package (ARM64)
curl -o actions-runner-osx-arm64-2.321.0.tar.gz -L \
  https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-osx-arm64-2.321.0.tar.gz

# Extract the package
tar xzf actions-runner-osx-arm64-2.321.0.tar.gz

# Configure the runner
# Replace YOUR_TOKEN with the token from GitHub Settings
./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO \
  --token YOUR_TOKEN \
  --name "mac-mini-m4-runner" \
  --labels "self-hosted,macOS,ARM64,M4" \
  --work "_work"

# Test the runner interactively first
./run.sh

Instal sebagai Layanan launchd Persisten

Menjalankan agen secara interaktif tidak masalah untuk pengujian, tetapi untuk produksi Anda memerlukannya agar mulai otomatis saat boot dan restart jika crash. GitHub menyediakan skrip instalasi layanan bawaan untuk macOS:

# Install as a launchd service
cd ~/actions-runner
sudo ./svc.sh install

# Start the service
sudo ./svc.sh start

# Check the service status
sudo ./svc.sh status
# Expected: "active (running)"

# View the launchd plist (for reference)
cat /Library/LaunchDaemons/actions.runner.*.plist

Layanan sekarang akan mulai otomatis saat boot dan restart jika proses mati. Anda dapat memverifikasi runner muncul sebagai "Idle" di halaman Settings > Actions > Runners repositori GitHub Anda.

Konfigurasikan Runner untuk Beberapa Repositori (Tingkat Organisasi)

# For an organization-level runner, use the organization URL:
./config.sh --url https://github.com/YOUR_ORG \
  --token YOUR_ORG_TOKEN \
  --name "mac-mini-m4-org-runner" \
  --labels "self-hosted,macOS,ARM64,M4" \
  --runnergroup "Default" \
  --work "_work"

# This allows ALL repositories in your organization to use this runner

5. Langkah 3: Buat Workflow Build iOS Anda

Buat file workflow di repositori Anda pada .github/workflows/ios-build.yml. Workflow ini akan berjalan di self-hosted runner Mac Mini M4 Anda.

name: iOS Build & Test

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64, M4]

    env:
      SCHEME: "MyApp"
      DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2"

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Select Xcode version
        run: |
          sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
          xcodebuild -version

      - name: Resolve Swift Package Dependencies
        run: |
          xcodebuild -resolvePackageDependencies \
            -scheme "$SCHEME" \
            -clonedSourcePackagesDirPath .spm-cache

      - name: Build the app
        run: |
          xcodebuild build \
            -scheme "$SCHEME" \
            -destination "$DESTINATION" \
            -clonedSourcePackagesDirPath .spm-cache \
            -derivedDataPath DerivedData \
            | xcbeautify

      - name: Run unit tests
        run: |
          xcodebuild test \
            -scheme "$SCHEME" \
            -destination "$DESTINATION" \
            -clonedSourcePackagesDirPath .spm-cache \
            -derivedDataPath DerivedData \
            -resultBundlePath TestResults.xcresult \
            | xcbeautify

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: TestResults.xcresult

Tambahkan Code Signing untuk Build Rilis

Untuk deployment TestFlight atau App Store, tambahkan langkah code signing. Simpan sertifikat dan provisioning profile Anda sebagai GitHub Secrets:

  deploy:
    needs: build
    runs-on: [self-hosted, macOS, ARM64, M4]
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install certificate and provisioning profile
        env:
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          # Create a temporary keychain
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
          security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH

          # Import certificate
          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
          echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
          security import $CERTIFICATE_PATH -P "$P12_PASSWORD" \
            -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
          security list-keychain -d user -s $KEYCHAIN_PATH

          # Install provisioning profile
          PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
          echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles

      - name: Build for distribution
        run: |
          xcodebuild archive \
            -scheme "MyApp" \
            -archivePath DerivedData/MyApp.xcarchive \
            -destination "generic/platform=iOS" \
            CODE_SIGN_STYLE=Manual

      - name: Export IPA
        run: |
          xcodebuild -exportArchive \
            -archivePath DerivedData/MyApp.xcarchive \
            -exportOptionsPlist ExportOptions.plist \
            -exportPath DerivedData/Export

      - name: Upload to TestFlight
        env:
          APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
        run: |
          xcrun altool --upload-app \
            -f DerivedData/Export/MyApp.ipa \
            -t ios \
            --apiKey $APP_STORE_CONNECT_API_KEY

6. Langkah 4: Optimalkan Performa

Salah satu keunggulan terbesar dari self-hosted runner adalah caching persisten. Berikut optimasi utama untuk memaksimalkan Mac Mini M4 Anda.

Aktifkan Caching DerivedData

Karena runner bersifat persisten, DerivedData dipertahankan di antara build. Gunakan path DerivedData yang konsisten:

# In your workflow, always use:
-derivedDataPath DerivedData

# On the runner, periodically clean old DerivedData to save space:
# Add a cron job to clean builds older than 7 days
echo "0 3 * * 0 find ~/actions-runner/_work/*/DerivedData -maxdepth 0 -mtime +7 -exec rm -rf {} +" \
  | crontab -

Cache Paket SPM

# Use clonedSourcePackagesDirPath to keep SPM packages on disk
xcodebuild build \
  -scheme "MyApp" \
  -clonedSourcePackagesDirPath ~/spm-cache \
  -derivedDataPath DerivedData

# This avoids re-downloading packages on every build

Eksekusi Pengujian Paralel

# Run tests in parallel across multiple simulators
xcodebuild test \
  -scheme "MyApp" \
  -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2" \
  -destination "platform=iOS Simulator,name=iPhone 15,OS=17.5" \
  -parallel-testing-enabled YES \
  -maximum-parallel-testing-workers 4 \
  -derivedDataPath DerivedData \
  | xcbeautify

Instal xcbeautify untuk Log yang Lebih Baik

# xcbeautify formats Xcode output for CI environments
brew install xcbeautify

# Use it by piping xcodebuild output:
xcodebuild build -scheme "MyApp" | xcbeautify

7. Pemecahan Masalah Umum

Runner muncul sebagai "Offline" di GitHub

Ini biasanya berarti layanan launchd tidak berjalan. Periksa status dan log layanan:

# Check service status
sudo ./svc.sh status

# View logs
cat ~/actions-runner/_diag/Runner_*.log | tail -50

# Restart the service
sudo ./svc.sh stop
sudo ./svc.sh start

Code signing gagal dengan "No signing certificate"

Layanan launchd berjalan di bawah konteks pengguna yang berbeda. Pastikan keychain dapat diakses:

# Ensure the login keychain is unlocked for the runner user
security unlock-keychain -p "YOUR_PASSWORD" ~/Library/Keychains/login.keychain-db

# Or use a dedicated keychain in your workflow (recommended)
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain

Simulator gagal boot

Simulator terkadang macet. Reset di antara build:

# Shutdown all running simulators
xcrun simctl shutdown all

# Erase all simulator data (nuclear option)
xcrun simctl erase all

# Boot a specific simulator
xcrun simctl boot "iPhone 16 Pro"

Ruang disk menipis

Build Xcode menghasilkan banyak data. Siapkan pembersihan otomatis:

# Clean old DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData/*

# Remove old simulator runtimes
xcrun simctl runtime delete all

# Clean Homebrew cache
brew cleanup --prune=7

# Remove old Xcode archives
rm -rf ~/Library/Developer/Xcode/Archives/*

8. Analisis Biaya

Berikut perbandingan biaya yang detail untuk berbagai ukuran tim dan volume build:

Ukuran Tim Build/Bulan Biaya yang Di-host GitHub Biaya MyRemoteMac Penghematan Bulanan
Dev Solo 100 build (rata-rata 10 mnt) $80/bln $85/bln $5/bln
Tim Kecil (5) 500 build (rata-rata 10 mnt) $400/bln $85/bln $325/bln
Tim Menengah (15) 1500 build (rata-rata 10 mnt) $1,200/bln $229/bln (M4 Pro) $971/bln
Enterprise (50+) 5000+ build $4,000+/bln $458/bln (2x M4 Pro) $3,542+/bln

Kesimpulan: Untuk tim yang menjalankan lebih dari ~100 build per bulan, Mac Mini M4 self-hosted langsung membayar dirinya sendiri. Dan karena build lebih cepat pada hardware persisten dengan cache yang sudah terisi, tim Anda juga menghemat waktu pengembang.

Panduan Terkait

Siap Mempercepat Build iOS Anda?

Deploy Mac Mini M4 dedikasi sebagai GitHub Actions runner Anda. Mulai dari $85/bulan.

Butuh detail lebih lanjut?

Jelajahi dokumentasi lengkap untuk panduan langkah demi langkah, referensi konfigurasi, dan pemecahan masalah.

Buka dokumentasi →