Mac पर सेल्फ-होस्टेड GitLab Runners क्यों?
GitLab, Linux पर शेयर्ड runners प्रदान करता है, लेकिन iOS ऐप्स बनाने के लिए Apple हार्डवेयर पर चलने वाले macOS की आवश्यकता होती है। GitLab के अपने macOS शेयर्ड runners सीमित और महंगे हैं। एक सेल्फ-होस्टेड Mac Mini M4 runner आपको देता है:
-
असीमित CI/CD मिनट
GitLab के फ्री टियर में शेयर्ड runners पर 400 CI/CD मिनट शामिल हैं। सेल्फ-होस्टेड पर, कोई सीमा नहीं है।
-
नेटिव Apple Silicon
उसी M4 चिप पर बिल्ड करें जिस पर आपके उपयोगकर्ताओं के डिवाइस चलते हैं। कोई Rosetta ट्रांसलेशन ओवरहेड नहीं।
-
पूर्ण एनवायरनमेंट नियंत्रण
अपनी आवश्यकता के अनुसार कोई भी Xcode वर्शन, सिम्युलेटर, टूल्स और डिपेंडेंसीज़ इंस्टॉल करें।
-
स्थायी कैश
DerivedData, SPM पैकेज और CocoaPods कैश पाइपलाइन रन के बीच बने रहते हैं।
GitLab Runner इंस्टॉल करें
अपने समर्पित Mac mini M4 बिल्ड सर्वर में SSH करें और Homebrew का उपयोग करके GitLab Runner, साथ ही पढ़ने योग्य बिल्ड लॉग के लिए xcbeautify, इंस्टॉल करें:
# 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, plus xcbeautify for the pipeline's build logs
brew install gitlab-runner xcbeautify
# Verify installation (prints the version and OS/Arch: darwin/arm64)
gitlab-runner --version
macOS सर्विस के रूप में इंस्टॉल करें
# Run the runner as a launchd service. It is a LaunchAgent: it starts when
# your user session starts, so on a headless Mac enable automatic login for
# this user (System Settings > Users & Groups) to bring it back after a reboot
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
Runner रजिस्टर करें
अपने GitLab प्रोजेक्ट (या ग्रुप) पर जाएं और Settings > CI/CD > Runners > New project runner पर नेविगेट करें। Tags में macos और m4 दर्ज करें (नीचे दी गई पाइपलाइन इन्हीं टैग को लक्षित करती है), runner बनाएं, फिर उसका ऑथेंटिकेशन टोकन कॉपी करें। ऑथेंटिकेशन टोकन के साथ, टैग और runner के अन्य विकल्प यहीं GitLab में सेट होते हैं, register कमांड में नहीं।
नए Runner रजिस्ट्रेशन फ्लो के साथ रजिस्टर करें (GitLab 16+)
# Register the runner using the authentication token from GitLab UI
# (GitLab 16+ uses authentication tokens instead of registration tokens).
# Tags, untagged jobs and locking come from the runner you created in GitLab:
# do not pass --tag-list or --run-untagged with an authentication token
gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--token "YOUR_RUNNER_AUTHENTICATION_TOKEN" \
--executor "shell" \
--description "mac-mini-m4-runner"
# Confirm the runner can reach GitLab
gitlab-runner verify
लेगेसी रजिस्ट्रेशन टोकन के साथ रजिस्टर करें (GitLab 15 और उससे पहले)
# 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"
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
समवर्तीता (concurrency) समायोजित करने के लिए ~/.gitlab-runner/config.toml संपादित करें:
# Edit the config
nano ~/.gitlab-runner/config.toml
# Set concurrent to match your hardware capacity
concurrent = 2
# Restart the service to apply changes
brew services restart gitlab-runner
अब runner आपके GitLab प्रोजेक्ट में Settings > CI/CD > Runners के अंतर्गत Online के रूप में दिखना चाहिए।
iOS के लिए .gitlab-ci.yml बनाएं
अपने रिपॉजिटरी रूट में एक .gitlab-ci.yml फ़ाइल बनाएं। यह संपूर्ण पाइपलाइन आपके iOS ऐप को बनाती, टेस्ट करती और डिप्लॉय करती है:
# .gitlab-ci.yml
stages:
- build
- test
- deploy
variables:
SCHEME: "MyApp"
WORKSPACE: "MyApp.xcworkspace"
# Any device listed by: xcrun simctl list devices available
DESTINATION: "platform=iOS Simulator,name=iPhone 17,OS=latest"
# Pick the Xcode for every job without sudo (path from: xcodes installed)
DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
# Only run on our Mac runner
default:
tags:
- macos
- m4
before_script:
# The runner cleans the checkout (git clean -ffdx) before each job, so keep
# DerivedData outside it: one warm folder per project and concurrent job slot
- export DERIVED_DATA="${CI_BUILDS_DIR}/DerivedData/${CI_PROJECT_PATH_SLUG}-${CI_CONCURRENT_PROJECT_ID}"
- xcodebuild -version
# Pods/ is removed with the rest of the checkout's untracked files: reinstall it
- |
if [ -f "Podfile" ]; then
pod install
fi
# ---- BUILD ----
build:
stage: build
script:
- |
xcodebuild build \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}" \
CODE_SIGNING_ALLOWED=NO \
| xcbeautify
# ---- 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 --report junit --report-path build/reports
artifacts:
when: always
paths:
- TestResults.xcresult/
reports:
junit: build/reports/junit.xml
expire_in: 7 days
after_script:
- xcrun simctl shutdown all 2>/dev/null || true
# ---- DEPLOY ----
deploy_testflight:
stage: deploy
needs: ["unit_tests"]
rules:
- if: $CI_COMMIT_BRANCH == "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}
# Names read by fastlane's app_store_connect_api_key action (call it in your lane)
APP_STORE_CONNECT_API_KEY_KEY_ID: ${APP_STORE_KEY_ID}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${APP_STORE_ISSUER_ID}
APP_STORE_CONNECT_API_KEY_KEY: ${APP_STORE_KEY_CONTENT}
GitLab में CI/CD वेरिएबल्स जोड़ें
अपने GitLab प्रोजेक्ट में Settings > CI/CD > Variables पर नेविगेट करें और इन वेरिएबल्स को "Masked" और "Protected" के रूप में जोड़ें:
MATCH_PASSWORD: Fastlane Match एन्क्रिप्शन के लिए पासवर्डAPP_STORE_KEY_ID: App Store Connect API Key IDAPP_STORE_ISSUER_ID: App Store Connect Issuer IDAPP_STORE_KEY_CONTENT: .p8 key फ़ाइल की सामग्री
प्रदर्शन ऑप्टिमाइज़ करें
GitLab कैश कॉन्फ़िगरेशन
स्थायी Mac पर सबसे तेज़ कैश वह है जिसे GitLab को हिलाना न पड़े: ऊपर की पाइपलाइन DerivedData को checkout के बाहर रखती है, इसलिए यह जॉब्स के बीच वार्म रहता है। shell executor के साथ GitLab का अपना कैश हर जॉब में ज़िप और अनज़िप होता है, इसलिए इसे Pods/ जैसे छोटे फ़ोल्डरों के लिए रखें:
# DerivedData already stays on disk outside the checkout (DERIVED_DATA above).
# Use GitLab's cache for small folders, keyed on the lockfile:
build:
cache:
key:
files:
- Podfile.lock
paths:
- Pods/
policy: pull-push
# For test jobs that don't modify the cache, use pull-only:
unit_tests:
cache:
key:
files:
- Podfile.lock
paths:
- Pods/
policy: pull
इंटर-स्टेज डेटा के लिए आर्टिफैक्ट्स का उपयोग करें
# Useful when the build and test jobs can run on different Macs.
# build-for-testing compiles the app and its test bundles once; artifacts must
# sit inside the project folder, so this job builds there
build:
script:
- |
xcodebuild build-for-testing \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath build/DerivedData \
| xcbeautify
artifacts:
paths:
- build/DerivedData/Build/Products/
expire_in: 2 hours
# The test stage receives the built products and runs them without rebuilding
unit_tests:
needs: ["build"] # downloads the build job's artifacts
script:
- |
xcodebuild test-without-building \
-xctestrun build/DerivedData/Build/Products/*.xctestrun \
-destination "${DESTINATION}" \
| xcbeautify
समानांतर टेस्ट निष्पादन
# On one Mac, let xcodebuild split the test classes across simulator clones.
# (GitLab's parallel: keyword only helps if each copy runs a different part of
# the suite, using CI_NODE_INDEX and CI_NODE_TOTAL; otherwise it repeats it.)
unit_tests:
stage: test
script:
- |
xcodebuild test \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME}" \
-destination "${DESTINATION}" \
-derivedDataPath "${DERIVED_DATA}" \
-parallel-testing-enabled YES \
-maximum-parallel-testing-workers 4 \
| xcbeautify
अनुसूचित कैश क्लीनअप
# On the Mac Mini, set up a weekly cleanup cron job
crontab -e
# Add these lines:
# Every Sunday at 3 AM, remove DerivedData folders not used for 7 days
# (the pipeline keeps them in ~/builds/DerivedData, one per project and slot)
0 3 * * 0 find ~/builds/DerivedData -mindepth 1 -maxdepth 1 -type d -mtime +7 -exec rm -rf {} + 2>/dev/null
# Checkouts in ~/builds are reused by the next job (git fetch): no need to delete them
# Clean Homebrew cache monthly
0 5 1 * * /opt/homebrew/bin/brew cleanup --prune=30 2>/dev/null
समस्या निवारण
GitLab में runner "offline" दिखाता है
runner एक LaunchAgent के रूप में चलता है, इसलिए यह आपके user सत्र के साथ शुरू होता है: रीबूट के बाद यह तब तक ऑफ़लाइन रहता है जब तक वह user लॉगिन न करे। हेडलेस Mac पर, इस user के लिए Automatic login सक्षम करें (System Settings > Users & Groups; FileVault चालू रहते उपलब्ध नहीं)। फिर runner सर्विस की स्थिति और लॉग जांचें:
# Check service status
brew services list | grep gitlab-runner
# View logs
cat /opt/homebrew/var/log/gitlab-runner.log
# Restart the service
brew services restart gitlab-runner
# Verify connectivity to GitLab
gitlab-runner verify
बिल्ड के दौरान परमिशन डिनाइड त्रुटियां
runner को Xcode डेवलपर डायरेक्टरी तक पहुंच की आवश्यकता हो सकती है:
# Ensure the runner user has Xcode access (run once, in your SSH session)
sudo xcode-select -s /Applications/Xcode-27.0.0.app/Contents/Developer
sudo xcodebuild -license accept
# If using simulators, ensure the user can access them
xcrun simctl list devices
कैश पुनर्स्थापित नहीं हो रहा
सुनिश्चित करें कि कैश कीज़ सुसंगत हैं और पाथ मौजूद हैं:
# 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
Xcode बिल्ड अटक जाता है या टाइम आउट हो जाता है
यह अक्सर कीचेन एक्सेस प्रॉम्प्ट या सिम्युलेटर समस्याओं के कारण होता है:
# 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
सामान्य प्रश्न
क्या मैं macOS पर Docker executor का उपयोग कर सकता हूं?
मैं GitLab ग्रुप के लिए runner कैसे रजिस्टर करूं?
क्या मुझे shell executor का उपयोग करना चाहिए या SSH executor का?
क्या मैं एक ही Mac पर GitLab और GitHub Actions दोनों runners चला सकता हूं?
मैं GitLab Runner को कैसे अपडेट करूं?
# Update via Homebrew
brew upgrade gitlab-runner
# Restart the service
brew services restart gitlab-runner
# Verify the new version
gitlab-runner --version