Panduan - CI/CD

Jenkins Mac Build Agent: Panduan Pengaturan Lengkap

Konfigurasi agen build Jenkins pada Mac Mini M4 khusus. Otomatiskan build Xcode, jalankan pengujian iOS, dan deploy ke TestFlight dengan kontrol penuh atas infrastruktur build Anda.

Baca 35 menit Diperbarui Maret 2026

1. Mengapa Mac Khusus untuk Jenkins?

Jenkins adalah platform CI/CD yang paling banyak digunakan, menjalankan lebih dari 50% pipeline build enterprise. Namun, membangun aplikasi iOS dengan Jenkins memerlukan macOS, dan macOS secara legal hanya dapat berjalan di perangkat keras Apple. Mac Mini M4 khusus memberi Anda:

Lingkungan Build yang Konsisten

Perangkat keras sama, OS sama, alat sama setiap build. Tidak ada build yang tidak stabil akibat pergeseran lingkungan.

Akses Root Penuh

Instal alat apa pun, konfigurasikan pengaturan sistem, kelola keychain untuk penandatanganan kode.

Performa Apple Silicon

Chip M4 memberikan build Xcode 2-3x lebih cepat dibandingkan Mac Mini Intel.

Cache Persisten

Cache DerivedData, CocoaPods, dan SPM tetap ada di antara setiap build.

2. Prasyarat

  • Sebuah Mac Mini M4 dari MyRemoteMac (mulai $85/bln)
  • Sebuah Jenkins controller (dapat berada di Linux, Docker, atau VM cloud mana pun)
  • Akses SSH ke Mac Mini Anda
  • Xcode terinstal di Mac Mini (lihat panduan GitHub Actions kami untuk langkah-langkah instalasi Xcode)

3. Langkah 1: Instal Java JDK di macOS

Agen Jenkins memerlukan Java Runtime Environment. Kami merekomendasikan penggunaan JDK 17 (LTS) atau JDK 21 (LTS) yang diinstal melalui Homebrew untuk kemudahan pengelolaan.

# Install Homebrew if not already present
/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 Java JDK 17 (recommended for Jenkins)
brew install openjdk@17

# Create the symlink for system Java wrappers
sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk \
  /Library/Java/JavaVirtualMachines/openjdk-17.jdk

# Add to PATH
echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zprofile
source ~/.zprofile

# Verify Java installation
java -version
# openjdk version "17.0.13" 2024-10-15
# OpenJDK Runtime Environment Homebrew (build 17.0.13+0)
# OpenJDK 64-Bit Server VM Homebrew (build 17.0.13+0, mixed mode, sharing)

4. Langkah 2: Konfigurasikan Agen Jenkins

Ada dua metode utama untuk menghubungkan agen Jenkins: JNLP (koneksi inbound dari agen ke controller) dan SSH (koneksi outbound dari controller ke agen). Kami membahas keduanya.

Metode A: Agen SSH (Direkomendasikan)

Ini adalah pendekatan yang paling andal. Jenkins terhubung ke Mac melalui SSH dan mengelola proses agen dari jarak jauh.

# On the Mac Mini: Create a dedicated Jenkins user
sudo dscl . -create /Users/jenkins
sudo dscl . -create /Users/jenkins UserShell /bin/zsh
sudo dscl . -create /Users/jenkins RealName "Jenkins Agent"
sudo dscl . -create /Users/jenkins UniqueID 550
sudo dscl . -create /Users/jenkins PrimaryGroupID 20
sudo dscl . -create /Users/jenkins NFSHomeDirectory /Users/jenkins
sudo mkdir -p /Users/jenkins
sudo chown jenkins:staff /Users/jenkins

# Set a password for the jenkins user
sudo dscl . -passwd /Users/jenkins "STRONG_PASSWORD_HERE"

# Create SSH directory and add the Jenkins controller's public key
sudo mkdir -p /Users/jenkins/.ssh
sudo sh -c 'echo "ssh-rsa YOUR_JENKINS_CONTROLLER_PUBLIC_KEY" > /Users/jenkins/.ssh/authorized_keys'
sudo chmod 700 /Users/jenkins/.ssh
sudo chmod 600 /Users/jenkins/.ssh/authorized_keys
sudo chown -R jenkins:staff /Users/jenkins/.ssh

# Create a workspace directory
sudo mkdir -p /Users/jenkins/workspace
sudo chown jenkins:staff /Users/jenkins/workspace

Sekarang konfigurasikan agen di Jenkins:

  1. Buka Manage Jenkins > Nodes > New Node
  2. Atur namanya menjadi mac-mini-m4
  3. Atur Remote root directory menjadi /Users/jenkins/workspace
  4. Label: mac macos apple-silicon m4 ios
  5. Metode peluncuran: Launch agents via SSH
  6. Host: Alamat IP Mac Mini Anda
  7. Credentials: Tambahkan kunci privat SSH yang cocok dengan authorized_keys di Mac

Metode B: Agen JNLP (Inbound)

Gunakan metode ini ketika Jenkins controller tidak dapat menjangkau Mac secara langsung (mis., Mac berada di belakang firewall). Agen yang memulai koneksi.

# First, create the node in Jenkins UI:
# Manage Jenkins > Nodes > New Node
# Launch method: "Launch agent by connecting it to the controller"
# Note the secret token from the node configuration page

# On the Mac Mini, download the agent JAR:
mkdir -p ~/jenkins-agent && cd ~/jenkins-agent
curl -sO https://your-jenkins-url/jnlpJars/agent.jar

# Test the agent connection
java -jar agent.jar \
  -url https://your-jenkins-url \
  -secret YOUR_AGENT_SECRET \
  -name "mac-mini-m4" \
  -workDir "/Users/jenkins/workspace"

Jalankan Agen JNLP sebagai Layanan launchd

# Create the launchd plist file
cat > ~/Library/LaunchAgents/com.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>com.jenkins.agent</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/opt/openjdk@17/bin/java</string>
        <string>-jar</string>
        <string>/Users/jenkins/jenkins-agent/agent.jar</string>
        <string>-url</string>
        <string>https://your-jenkins-url</string>
        <string>-secret</string>
        <string>YOUR_AGENT_SECRET</string>
        <string>-name</string>
        <string>mac-mini-m4</string>
        <string>-workDir</string>
        <string>/Users/jenkins/workspace</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/jenkins/jenkins-agent/stdout.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/jenkins/jenkins-agent/stderr.log</string>
</dict>
</plist>
EOF

# Load the service
launchctl load ~/Library/LaunchAgents/com.jenkins.agent.plist

# Verify it's running
launchctl list | grep jenkins

5. Langkah 3: Buat Pipeline Build iOS

Buat sebuah Jenkinsfile di root repositori Anda. Pipeline deklaratif ini membangun, menguji, dan secara opsional mengarsipkan aplikasi iOS Anda.

pipeline {
    agent { label 'mac && m4' }

    environment {
        SCHEME       = 'MyApp'
        WORKSPACE    = 'MyApp.xcworkspace'
        DESTINATION  = 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2'
        DERIVED_DATA = "${WORKSPACE_DIR}/DerivedData"
    }

    options {
        timeout(time: 30, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install Dependencies') {
            steps {
                sh '''
                    # Select Xcode version
                    sudo xcode-select -s /Applications/Xcode-16.2.app/Contents/Developer
                    xcodebuild -version

                    # Install CocoaPods dependencies
                    if [ -f "Podfile" ]; then
                        pod install --repo-update
                    fi
                '''
            }
        }

        stage('Build') {
            steps {
                sh '''
                    xcodebuild build \
                        -workspace "${WORKSPACE}" \
                        -scheme "${SCHEME}" \
                        -destination "${DESTINATION}" \
                        -derivedDataPath "${DERIVED_DATA}" \
                        CODE_SIGNING_ALLOWED=NO \
                        | xcbeautify
                '''
            }
        }

        stage('Test') {
            steps {
                sh '''
                    xcodebuild test \
                        -workspace "${WORKSPACE}" \
                        -scheme "${SCHEME}" \
                        -destination "${DESTINATION}" \
                        -derivedDataPath "${DERIVED_DATA}" \
                        -resultBundlePath "TestResults.xcresult" \
                        -parallel-testing-enabled YES \
                        | xcbeautify
                '''
            }
            post {
                always {
                    archiveArtifacts artifacts: 'TestResults.xcresult/**', allowEmptyArchive: true
                }
            }
        }

        stage('Archive') {
            when {
                branch 'main'
            }
            steps {
                sh '''
                    xcodebuild archive \
                        -workspace "${WORKSPACE}" \
                        -scheme "${SCHEME}" \
                        -archivePath "${DERIVED_DATA}/MyApp.xcarchive" \
                        -destination "generic/platform=iOS" \
                        | xcbeautify
                '''
            }
        }
    }

    post {
        success {
            echo 'Build and tests passed!'
        }
        failure {
            echo 'Build or tests failed.'
        }
        cleanup {
            sh 'xcrun simctl shutdown all 2>/dev/null || true'
        }
    }
}

6. Langkah 4: Integrasikan Fastlane untuk Deployment

Fastlane menyederhanakan penandatanganan kode dan deployment TestFlight. Tambahkan stage deploy ke Jenkinsfile Anda:

# Install Fastlane on the Mac Mini (one-time setup)
brew install fastlane

# Or via Ruby:
gem install fastlane -NV

Tambahkan stage deploy ke Jenkinsfile Anda:

        stage('Deploy to TestFlight') {
            when {
                branch 'main'
            }
            environment {
                APP_STORE_CONNECT_API_KEY_ID     = credentials('app-store-key-id')
                APP_STORE_CONNECT_API_ISSUER_ID  = credentials('app-store-issuer-id')
                APP_STORE_CONNECT_API_KEY_CONTENT = credentials('app-store-key-content')
                MATCH_PASSWORD                   = credentials('match-password')
            }
            steps {
                sh '''
                    fastlane beta
                '''
            }
        }

Dan buat fastlane/Fastfile yang sesuai:

default_platform(:ios)

platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do
    setup_ci

    # Fetch code signing certificates via match
    match(type: "appstore", readonly: true)

    # Increment build number
    increment_build_number(
      build_number: ENV["BUILD_NUMBER"]
    )

    # Build the app
    build_app(
      workspace: "MyApp.xcworkspace",
      scheme: "MyApp",
      export_method: "app-store",
      derived_data_path: "DerivedData"
    )

    # Upload to TestFlight
    upload_to_testflight(
      skip_waiting_for_build_processing: true,
      api_key: app_store_connect_api_key(
        key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
        issuer_id: ENV["APP_STORE_CONNECT_API_ISSUER_ID"],
        key_content: ENV["APP_STORE_CONNECT_API_KEY_CONTENT"]
      )
    )
  end
end

7. Praktik Keamanan Terbaik

Gunakan pengguna Jenkins khusus

Jangan pernah menjalankan agen Jenkins sebagai root. Buat pengguna khusus dengan izin minimal.

Simpan secret di Jenkins Credentials

Jangan pernah menuliskan sertifikat, kunci API, atau kata sandi secara hardcode di Jenkinsfile. Gunakan plugin Jenkins Credentials.

Aktifkan hanya autentikasi berbasis kunci SSH

Nonaktifkan autentikasi kata sandi untuk SSH. Gunakan kunci Ed25519 atau RSA 4096-bit.

Gunakan Firewall macOS

Batasi koneksi masuk hanya ke IP Jenkins controller. MyRemoteMac menyediakan firewall terkelola dengan akses API.

Selalu perbarui macOS dan Xcode

Terapkan patch keamanan segera. Gunakan softwareupdate -l untuk memeriksa pembaruan.

8. FAQ

Bisakah saya menjalankan Jenkins controller di Mac yang sama?

Ya, tetapi kami merekomendasikan untuk memisahkannya. Jalankan controller di VM Linux atau container Docker, dan gunakan Mac secara eksklusif sebagai agen build. Ini menghindari perebutan sumber daya selama build berat.

Berapa banyak build bersamaan yang dapat ditangani Mac Mini M4?

Mac Mini M4 dengan RAM 16GB dapat dengan nyaman menangani 2 build Xcode bersamaan. Dengan 24GB, Anda dapat mendorong hingga 3. M4 Pro dengan 48GB menangani 4+ build bersamaan dengan mudah. Konfigurasikan "Number of executors" di pengaturan node Jenkins Anda sesuai kebutuhan.

Apakah saya memerlukan sesi GUI untuk simulator iOS?

Tidak. Simulator iOS bekerja dalam mode headless melalui SSH. Namun, jika Anda memerlukan GUI (mis., untuk tangkapan layar pengujian UI), gunakan VNC untuk masuk ke Mac dan pastikan sesi GUI aktif.

Bagaimana cara menangani penandatanganan kode di server headless?

Gunakan Fastlane Match untuk menyinkronkan sertifikat dari repo Git atau penyimpanan cloud. Sebagai alternatif, impor sertifikat ke keychain macOS dan buka kuncinya di pipeline Anda menggunakan security unlock-keychain.

Panduan Terkait

Siap Mendongkrak Build Jenkins Anda?

Dapatkan Mac Mini M4 khusus untuk pipeline Jenkins CI/CD Anda. Mulai dari $85/bulan.

Butuh detail lebih lanjut?

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

Buka dokumentasi →