Mac पर सेल्फ-होस्टेड CircleCI रनर क्यों उपयोग करें?
CircleCI क्लाउड-आधारित macOS एक्ज़ीक्यूशन वातावरण प्रदान करता है, लेकिन ये महत्वपूर्ण लागतों और सीमाओं के साथ आते हैं। CircleCI macOS जॉब्स का बिल क्रेडिट में बनाता है: m4pro.medium रिसोर्स क्लास प्रति मिनट 200 क्रेडिट (लगभग $0.12) और m4pro.large 400 क्रेडिट (लगभग $0.24) खपत करती है, अक्टूबर 2026 तक। अक्सर iOS बिल्ड चलाने वाली टीमों के लिए, यह जल्दी ही प्रति माह $300-$500 या उससे अधिक तक पहुँच सकता है।
MyRemoteMac के एक समर्पित Mac Mini M4 पर एक सेल्फ-होस्टेड रनर प्रति-मिनट बिलिंग को पूरी तरह समाप्त कर देता है। आपको स्थायी स्टोरेज, वार्म कैश, और पूर्ण रूट एक्सेस वाली एक समर्पित Apple Silicon मशीन एक फ्लैट मासिक शुल्क पर मिलती है, जो $85/माह से शुरू होता है। यहाँ एक विस्तृत तुलना है:
| विशेषता | MyRemoteMac सेल्फ-होस्टेड | CircleCI क्लाउड macOS |
|---|---|---|
| लागत मॉडल | $85/माह फ्लैट (असीमित मिनट) | m4pro.medium पर 200 क्रेडिट/मिनट (~$0.12/मिनट) |
| आर्किटेक्चर | 1:1 आवंटित भौतिक Apple M4 Mac | M4 Pro वर्चुअल मशीन (6 vCPU, 28 GB) |
| बिल्ड गति | ~5 मिनट (समान प्रोजेक्ट) | ~14 मिनट (मध्यम iOS प्रोजेक्ट) |
| कैश परसिस्टेंस | डिस्क पर स्थायी (तत्काल) | एफ़ेमरल (हर जॉब में रिस्टोर करना ज़रूरी) |
| कतार प्रतीक्षा समय | 0 सेकंड (समर्पित हार्डवेयर) | 30 सेकंड - 5 मिनट (प्लान के अनुसार भिन्न) |
| गोपनीयता / डेटा नियंत्रण | समर्पित मशीन, पूर्ण नियंत्रण | साझा इन्फ्रास्ट्रक्चर |
| कस्टम सॉफ़्टवेयर | पूर्ण रूट एक्सेस, कोई भी सॉफ़्टवेयर | केवल पूर्व-इंस्टॉल की गई इमेज |
My Remote Mac की कीमतें USD में, कर अतिरिक्त।
मुख्य लाभ: एक स्थायी सेल्फ-होस्टेड रनर के साथ, DerivedData, Swift Package Manager कैश, और CocoaPods बिल्ड के बीच संरक्षित रहते हैं। अकेले यही बिल्ड समय को CircleCI के एफ़ेमरल क्लाउड macOS वातावरणों की तुलना में 50-70% तक कम कर सकता है, जो हर बार शून्य से शुरू होते हैं। M4 चिप के श्रेष्ठ सिंगल-थ्रेडेड प्रदर्शन के साथ मिलकर, आपके iOS बिल्ड नाटकीय रूप से तेज़ होंगे।
पूर्वापेक्षाएँ
शुरू करने से पहले, सुनिश्चित करें कि आपके पास निम्नलिखित हैं:
- My Remote Mac से एक समर्पित Mac mini M4 बिल्ड सर्वर ($85/माह से, USD, कर अतिरिक्त)
- एक CircleCI संगठन जिसमें आप एडमिन हों (सेल्फ-होस्टेड रनर हर प्लान में उपलब्ध हैं, Free सहित, जिसमें अक्टूबर 2026 तक 5 सेल्फ-होस्टेड टास्क एक साथ चल सकते हैं)
- आपके Mac Mini तक SSH एक्सेस (आपकी MyRemoteMac सदस्यता के साथ प्रदान किया गया)
- एक Apple Developer खाता (कोड साइनिंग और प्रोविज़निंग प्रोफ़ाइल के लिए)
- YAML, CircleCI कॉन्फ़िगरेशन, और टर्मिनल कमांड से बुनियादी परिचय
चरण 1: अपने Mac Mini में SSH करें और डिपेंडेंसी इंस्टॉल करें
सबसे पहले, SSH के ज़रिए अपने Mac Mini M4 से कनेक्ट करें। जब आपने अपना MyRemoteMac सर्वर सेट किया था तब आपको अपने क्रेडेंशियल मिले होंगे। CircleCI रनर सेट करने से पहले हमें Xcode और iOS बिल्ड के लिए आवश्यक टूल इंस्टॉल करने होंगे।
SSH के ज़रिए कनेक्ट करें
# Connect to your Mac mini M4
ssh admin@your-server-ip
# Verify you're on Apple Silicon
uname -m
# Expected output: arm64
# Show the macOS version
sw_vers
Homebrew और Xcode Command Line Tools इंस्टॉल करें
# Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Add Homebrew to PATH: zsh for your sessions, bash for CircleCI job steps
# (CircleCI runs macOS steps in a bash login shell)
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
eval "$(/opt/homebrew/bin/brew shellenv)"
# Install Xcode Command Line Tools
xcode-select --install
# Accept the license agreement
sudo xcodebuild -license accept
Xcode इंस्टॉल करें (पूर्ण संस्करण)
iOS बिल्ड के लिए, आपको पूर्ण Xcode एप्लिकेशन की आवश्यकता होती है। 28 अप्रैल 2026 से App Store Connect केवल Xcode 26 या उससे नए वर्ज़न से बने बिल्ड स्वीकार करता है, इसलिए हेडलेस सर्वर पर सबसे तेज़ तरीके xcodes से मौजूदा रिलीज़ इंस्टॉल करें:
# Install the xcodes CLI tool
brew install xcodes
# Install the latest release of Xcode (asks for your Apple Account)
xcodes install --latest
# Show where it was installed, then make it the default Xcode
xcodes installed
# e.g. 27.0 (27A266a) /Applications/Xcode-27.0.0.app
sudo xcode-select -s /Applications/Xcode-27.0.0.app/Contents/Developer
# Verify installation
xcodebuild -version
iOS सिम्युलेटर और बिल्ड टूल इंस्टॉल करें
# Install the current iOS simulator runtime
xcodebuild -downloadPlatform iOS
# Verify simulator availability
xcrun simctl list runtimes
# Install additional build tools
brew install xcbeautify fastlane swiftlint
चरण 2: CircleCI रनर एजेंट इंस्टॉल करें
CircleCI का मशीन रनर 3 आपके Mac mini को CircleCI से जोड़ता है: यह जॉब्स प्राप्त करता है और उन्हें सीधे आपके macOS होस्ट पर चलाता है। macOS पर CircleCI इसे अपने Homebrew पैकेज से इंस्टॉल करने की सलाह देता है। यह कंटेनर रनर से अलग है (जो केवल Linux पर काम करता है)।
वह उपयोगकर्ता चुनें जो आपके जॉब्स चलाएगा
मशीन रनर 3 हर जॉब को उसी macOS उपयोगकर्ता के रूप में चलाता है जिसने उसे शुरू किया, उसी उपयोगकर्ता के Homebrew, कीचेन और Xcode के साथ। इसे अपने एडमिन उपयोगकर्ता से इंस्टॉल और शुरू करें, जिसके पास Homebrew है, root से नहीं: Homebrew root के रूप में चलने से मना करता है।
# Run the steps below as the user that will run CI jobs, not with sudo
whoami
# Homebrew must work for this user (prints /opt/homebrew)
brew --prefix
Homebrew से मशीन रनर 3 इंस्टॉल करें
# Add CircleCI's Homebrew tap and install machine runner 3
brew tap circleci-public/circleci
brew install circleci-runner
# Check that macOS accepts the binary notarized by CircleCI
spctl -a -vvv -t install "$(brew --prefix)/bin/circleci-runner"
# Expected: accepted, source=Notarized Developer ID,
# origin=Developer ID Application: Circle Internet Services Inc.
# Remove the quarantine attribute (asks for your macOS password)
sudo xattr -r -d com.apple.quarantine "$(brew --prefix)/bin/circleci-runner"
रनर एजेंट कॉन्फ़िगर करें
Homebrew पैकेज कॉन्फ़िगरेशन फ़ाइल बनाता है। आपको CircleCI वेब ऐप से अपने रनर प्रमाणीकरण टोकन की आवश्यकता होगी (चरण 3 में शामिल)। अभी के लिए, रनर का नाम सेट करें और टोकन की जगह एक प्लेसहोल्डर रखें:
# Open the configuration file created by the Homebrew package
nano "$HOME/Library/Preferences/com.circleci.runner/config.yaml"
# Contents (the token comes in Step 3):
runner:
name: "mac-mini-m4-runner"
working_directory: "/Users/$USER/Library/com.circleci.runner/workdir"
cleanup_working_directory: true
api:
auth_token: "YOUR_RUNNER_TOKEN_HERE"
# The file will hold a secret: make it readable by you only
chmod 600 "$HOME/Library/Preferences/com.circleci.runner/config.yaml"
हेडलेस Mac के लिए launchd सेवा तैयार करें
Homebrew पैकेज एक launchd एजेंट, com.circleci.runner, भी इंस्टॉल करता है। एजेंट आम तौर पर आपके उपयोगकर्ता के लॉग इन करने पर शुरू होता है; जिस Mac तक आप केवल SSH से पहुँचते हैं, उस पर CircleCI का हेडलेस सेटअप इसे /Library/LaunchAgents में ले जाता है ताकि यह रीबूट के बाद लोड हो। टोकन लगाने के बाद इसे चरण 3 में शुरू करें:
# The launchd agent installed by the Homebrew package
ls ~/Library/LaunchAgents/com.circleci.runner.plist
# Headless Mac reached over SSH only: move it to the per-user agents
# folder so it loads after a reboot (CircleCI's headless setup)
sudo mv ~/Library/LaunchAgents/com.circleci.runner.plist /Library/LaunchAgents/
महत्वपूर्ण: जब तक config.yaml में एक वैध प्रमाणीकरण टोकन नहीं होता, रनर कनेक्ट नहीं होगा। चरण 3 में टोकन जनरेट करें, उसे फ़ाइल में जोड़ें, फिर सेवा शुरू करें।
चरण 3: CircleCI डैशबोर्ड में रनर कॉन्फ़िगर करें
अब आपको CircleCI वेब इंटरफ़ेस में अपना रनर पंजीकृत करना होगा और एक प्रमाणीकरण टोकन जनरेट करना होगा। यह आपके Mac Mini को आपके CircleCI संगठन से जोड़ता है।
एक रिसोर्स क्लास बनाएं
CircleCI में, सेल्फ-होस्टेड रनर रिसोर्स क्लास द्वारा व्यवस्थित होते हैं। एक रिसोर्स क्लास एक लेबल है जो आपके .circleci/config.yml को रनर के एक विशिष्ट सेट से मैप करता है।
- CircleCI वेब ऐप में साइडबार से Runners खोलें (आपको संगठन का एडमिन होना चाहिए)
- "Create Resource Class" पर क्लिक करें
- Namespace को अपने संगठन के नाम पर सेट करें (उदाहरण:
your-org) - Resource Class नाम को कुछ वर्णनात्मक पर सेट करें (उदाहरण:
mac-runner) - इससे एक रिसोर्स क्लास पहचानकर्ता बनता है:
your-org/mac-runner
एक रनर प्रमाणीकरण टोकन जनरेट करें
- "Save and continue" पर क्लिक करें: CircleCI रिसोर्स क्लास बनाता है और उसका प्रमाणीकरण टोकन दिखाता है
- टोकन को तुरंत कॉपी करें और सुरक्षित रखें: यह केवल एक बार दिखाया जाता है
- खो गया? CircleCI CLI से नया बनाएं:
circleci runner token create your-org/mac-runner mac-mini-m4
अपना टोकन जोड़ें और रनर शुरू करें
# SSH back into your Mac mini
ssh admin@your-server-ip
# Replace YOUR_RUNNER_TOKEN_HERE with the resource class token
nano "$HOME/Library/Preferences/com.circleci.runner/config.yaml"
# Start the service. Headless Mac (plist moved to /Library/LaunchAgents):
launchctl bootstrap user/$(id -u) /Library/LaunchAgents/com.circleci.runner.plist
launchctl enable user/$(id -u)/com.circleci.runner
launchctl kickstart -k user/$(id -u)/com.circleci.runner
# Or, from a desktop session (VNC), with the plist left in ~/Library/LaunchAgents:
# launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.circleci.runner.plist
# launchctl enable gui/$(id -u)/com.circleci.runner
# launchctl kickstart -k gui/$(id -u)/com.circleci.runner
# Verify the service, then read the runner log
launchctl print user/$(id -u)/com.circleci.runner
tail -20 "$HOME/Library/Logs/com.circleci.runner/runner.log"
कनेक्ट होने के बाद रनर CircleCI वेब ऐप में Runners के अंतर्गत दिखता है, और circleci runner instance list your-org/mac-runner भी इसे दिखाता है। यदि यह 60 सेकंड के भीतर नहीं दिखता, तो त्रुटि संदेशों के लिए लॉग फ़ाइल जाँचें।
CircleCI CLI का उपयोग करना (वैकल्पिक)
आप CircleCI CLI के ज़रिए भी रनर प्रबंधित कर सकते हैं:
# Install the CircleCI CLI
brew install circleci
# Authenticate with CircleCI
circleci setup
# Create the namespace (once per organization)
circleci namespace create your-org --org-id YOUR_ORGANIZATION_ID
# Create the resource class and print its token
circleci runner resource-class create your-org/mac-runner \
"Mac mini M4 runner" --generate-token
# List the runners connected to this resource class
circleci runner instance list your-org/mac-runner
चरण 4: iOS बिल्ड के लिए अपना .circleci/config.yml बनाएं
अपने रिपॉज़िटरी के रूट में एक .circleci/config.yml फ़ाइल बनाएं। एक मानक CircleCI कॉन्फ़िग से मुख्य अंतर यह है कि अपने सेल्फ-होस्टेड रनर को टारगेट करने के लिए अपने कस्टम resource_class के साथ machine: true का उपयोग किया जाता है।
version: 2.1
jobs:
build-and-test:
machine: true
resource_class: your-org/mac-runner
environment:
# Xcode for this job, without sudo (path from `xcodes installed`)
DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
SCHEME: "MyApp"
# Any device listed by: xcrun simctl list devices available
DESTINATION: "platform=iOS Simulator,name=iPhone 17,OS=latest"
steps:
- checkout
- run:
name: Show the Xcode version
command: xcodebuild -version
# Caches live in $HOME, outside the job's working directory,
# so they survive cleanup_working_directory between jobs
- run:
name: Resolve Swift Package Dependencies
command: |
xcodebuild -resolvePackageDependencies \
-scheme "$SCHEME" \
-clonedSourcePackagesDirPath "$HOME/spm-cache"
- run:
name: Build the app
command: |
xcodebuild build \
-scheme "$SCHEME" \
-destination "generic/platform=iOS Simulator" \
-clonedSourcePackagesDirPath "$HOME/spm-cache" \
-derivedDataPath "$HOME/DerivedData/$SCHEME" \
| xcbeautify
# store_test_results needs JUnit XML: xcbeautify writes test-results/junit.xml
- run:
name: Run unit tests
command: |
xcodebuild test \
-scheme "$SCHEME" \
-destination "$DESTINATION" \
-clonedSourcePackagesDirPath "$HOME/spm-cache" \
-derivedDataPath "$HOME/DerivedData/$SCHEME" \
-resultBundlePath TestResults.xcresult \
| xcbeautify --report junit --report-path test-results
- store_test_results:
path: test-results
- store_artifacts:
path: TestResults.xcresult
destination: test-results
workflows:
ios-pipeline:
jobs:
- build-and-test:
filters:
branches:
only:
- main
- develop
ध्यान दें: resource_class: your-org/mac-runner मान बिल्कुल उसी रिसोर्स क्लास से मेल खाना चाहिए जो आपने CircleCI डैशबोर्ड में बनाई थी। यदि यह मेल नहीं खाता, तो जॉब्स अनिश्चित काल तक कतार में रहेंगे।
चरण 5: कैशिंग और पैरेललिज़्म के साथ ऑप्टिमाइज़ करें
सेल्फ-होस्टेड रनर के सबसे बड़े लाभों में से एक स्थायी कैशिंग है। चूँकि रनर का फ़ाइलसिस्टम स्थायी होता है, आपको CircleCI क्लाउड संसाधनों की तरह कैश अपलोड और डाउनलोड करने की आवश्यकता नहीं होती। हालाँकि, अपनी बिल्ड गति को अधिकतम करने के लिए अतिरिक्त ऑप्टिमाइज़ेशन मौजूद हैं।
स्थायी DerivedData का लाभ उठाएं
चूँकि रनर डिस्क बिल्ड के बीच बनी रहती है, DerivedData पहले से ही स्वचालित रूप से कैश हो जाता है। एक सुसंगत पथ का उपयोग करें:
# In your config.yml steps, always use a consistent DerivedData path:
- run:
name: Build with persistent cache
command: |
xcodebuild build \
-scheme "$SCHEME" \
-destination "$DESTINATION" \
-derivedDataPath ~/DerivedData/"$SCHEME" \
-clonedSourcePackagesDirPath ~/spm-cache \
| xcbeautify
# Periodically clean old DerivedData on the runner (cron job):
# 0 3 * * 0 find ~/DerivedData -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} +
जॉब्स के बीच वर्कस्पेस परसिस्टेंस
बने हुए प्रोडक्ट्स को टेस्ट जॉब तक पहुँचाने के लिए CircleCI वर्कस्पेस का उपयोग करें; यह जॉब उसी रिसोर्स क्लास के किसी दूसरे Mac पर भी चल सकता है:
jobs:
build:
machine: true
resource_class: your-org/mac-runner
steps:
- checkout
- run:
name: Build for testing
command: |
xcodebuild build-for-testing \
-scheme "MyApp" \
-destination "generic/platform=iOS Simulator" \
-derivedDataPath DerivedData \
| xcbeautify
# Pass only the built products, not the whole DerivedData
- persist_to_workspace:
root: .
paths:
- DerivedData/Build/Products
test:
machine: true
resource_class: your-org/mac-runner
steps:
- attach_workspace:
at: .
- run:
name: Run the tests built by the previous job
command: |
xcodebuild test-without-building \
-xctestrun "$(ls DerivedData/Build/Products/*.xctestrun | head -n 1)" \
-destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
| xcbeautify --report junit --report-path test-results
- store_test_results:
path: test-results
workflows:
build-test:
jobs:
- build
- test:
requires:
- build
पैरेलल टेस्ट एक्ज़ीक्यूशन
- run:
name: Run tests in parallel
command: |
# Xcode clones the simulator and runs test classes on up to 4 clones
xcodebuild test \
-scheme "MyApp" \
-destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
-parallel-testing-enabled YES \
-maximum-parallel-testing-workers 4 \
-derivedDataPath ~/DerivedData/MyApp \
| xcbeautify
CircleCI टेस्ट स्प्लिटिंग
बड़े टेस्ट सूट के लिए, CircleCI की टेस्ट स्प्लिटिंग टेस्ट क्लासेज़ को पैरेलल टास्क में बाँटती है। हर टास्क को अपना रनर चाहिए, इसलिए parallelism: 3 के लिए रिसोर्स क्लास में तीन Mac चाहिए; एक ही Mac पर टास्क एक के बाद एक चलते हैं:
jobs:
test:
machine: true
resource_class: your-org/mac-runner
# One task per runner: 3 tasks need 3 Macs in this resource class
parallelism: 3
steps:
- checkout
- run:
name: Split test classes and run this task's share
command: |
# One XCTest class per file, named like the file (LoginTests.swift)
CLASSES=$(circleci tests glob "MyAppTests/**/*Tests.swift" \
| xargs -n1 basename | sed 's/\.swift$//' \
| circleci tests split)
# -only-testing takes Target/Class identifiers, not file paths
ONLY_TESTING=""
for CLASS in $CLASSES; do
ONLY_TESTING="$ONLY_TESTING -only-testing:MyAppTests/$CLASS"
done
xcodebuild test \
-scheme "MyApp" \
-destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
$ONLY_TESTING \
| xcbeautify --report junit --report-path test-results
- store_test_results:
path: test-results
वर्कफ़्लो उदाहरण
सामान्य iOS CI/CD परिदृश्यों के लिए यहाँ संपूर्ण, प्रोडक्शन-रेडी वर्कफ़्लो उदाहरण दिए गए हैं।
संपूर्ण iOS बिल्ड, टेस्ट, और डिप्लॉय पाइपलाइन
version: 2.1
jobs:
lint:
machine: true
resource_class: your-org/mac-runner
steps:
- checkout
- run:
name: Run SwiftLint
command: swiftlint lint --reporter json > swiftlint-results.json || true
- store_artifacts:
path: swiftlint-results.json
build-and-test:
machine: true
resource_class: your-org/mac-runner
environment:
# Xcode for this job, without sudo (path from `xcodes installed`)
DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
steps:
- checkout
- run:
name: Resolve dependencies
command: |
xcodebuild -resolvePackageDependencies \
-scheme "MyApp" \
-clonedSourcePackagesDirPath ~/spm-cache
- run:
name: Build and test
command: |
xcodebuild test \
-scheme "MyApp" \
-destination "platform=iOS Simulator,name=iPhone 17,OS=latest" \
-clonedSourcePackagesDirPath ~/spm-cache \
-derivedDataPath ~/DerivedData/MyApp \
-resultBundlePath TestResults.xcresult \
-parallel-testing-enabled YES \
| xcbeautify --report junit --report-path test-results
- store_test_results:
path: test-results
- store_artifacts:
path: TestResults.xcresult
deploy-testflight:
machine: true
resource_class: your-org/mac-runner
environment:
DEVELOPER_DIR: "/Applications/Xcode-27.0.0.app/Contents/Developer"
steps:
- checkout
- run:
name: Install dependencies
command: bundle install
# MATCH_PASSWORD and the App Store Connect API key variables
# (ASC_KEY_ID, ASC_ISSUER_ID, ASC_KEY_CONTENT) come from a CircleCI
# context or the project's environment variables
- run:
name: Build and upload to TestFlight
command: bundle exec fastlane beta
workflows:
ios-pipeline:
jobs:
- lint
- build-and-test:
requires:
- lint
- deploy-testflight:
requires:
- build-and-test
filters:
branches:
only: main
Fastlane एकीकरण उदाहरण
यदि आप अपने बिल्ड ऑटोमेशन के लिए Fastlane का उपयोग करते हैं, तो इसे अपने CircleCI सेल्फ-होस्टेड रनर के साथ एकीकृत करने का तरीका यहाँ दिया गया है:
# Fastfile (fastlane/Fastfile)
default_platform(:ios)
platform :ios do
desc "Run tests"
lane :test do
scan(
scheme: "MyApp",
device: "iPhone 17",
derived_data_path: File.expand_path("~/DerivedData/MyApp"),
result_bundle: true,
output_directory: "./test_output",
# store_test_results reads JUnit XML
output_types: "junit",
output_files: "junit.xml"
)
end
desc "Build and push to TestFlight"
lane :beta do
# App Store Connect API key: no Apple ID password or 2FA on the runner
app_store_connect_api_key(
key_id: ENV["ASC_KEY_ID"],
issuer_id: ENV["ASC_ISSUER_ID"],
key_content: ENV["ASC_KEY_CONTENT"]
)
match(type: "appstore", readonly: true)
increment_build_number(
build_number: ENV["CIRCLE_BUILD_NUM"]
)
gym(
scheme: "MyApp",
export_method: "app-store",
derived_data_path: File.expand_path("~/DerivedData/MyApp")
)
pilot(skip_waiting_for_build_processing: true)
end
end
# .circleci/config.yml using Fastlane
version: 2.1
jobs:
fastlane-test:
machine: true
resource_class: your-org/mac-runner
steps:
- checkout
- run:
name: Install dependencies
command: bundle install
- run:
name: Run Fastlane tests
command: bundle exec fastlane test
- store_test_results:
path: ./test_output
- store_artifacts:
path: ./test_output
fastlane-deploy:
machine: true
resource_class: your-org/mac-runner
steps:
- checkout
- run:
name: Install dependencies
command: bundle install
- run:
name: Deploy to TestFlight
command: bundle exec fastlane beta
workflows:
ios-workflow:
jobs:
- fastlane-test
- fastlane-deploy:
requires:
- fastlane-test
filters:
branches:
only: main
प्रदर्शन तुलना
CircleCI क्लाउड macOS संसाधनों और MyRemoteMac के एक सेल्फ-होस्टेड Mac Mini M4 के बीच यहाँ एक विस्तृत प्रदर्शन और लागत तुलना दी गई है:
बिल्ड समय बेंचमार्क
| परिदृश्य | सेल्फ-होस्टेड Mac Mini M4 | CircleCI क्लाउड macOS | सुधार |
|---|---|---|---|
| क्लीन बिल्ड (मध्यम ऐप) | 5 मिनट | 14 मिनट | 2.8 गुना तेज़ |
| इंक्रीमेंटल बिल्ड | 1.5 मिनट | 14 मिनट (कोई कैश नहीं) | 9.3 गुना तेज़ |
| SPM डिपेंडेंसी रिज़ॉल्यूशन | 5 सेकंड (डिस्क पर कैश) | 3-5 मिनट (हर बार डाउनलोड) | ~60 गुना तेज़ |
| यूनिट टेस्ट सूट (500 टेस्ट) | 2.5 मिनट | 8 मिनट | 3.2 गुना तेज़ |
| कतार प्रतीक्षा समय | 0 सेकंड | 30 सेकंड - 5 मिनट | तत्काल |
मासिक लागत विश्लेषण
| टीम का आकार | MyRemoteMac लागत | बिल्ड/माह | CircleCI क्लाउड लागत | मासिक बचत |
|---|---|---|---|---|
| एकल डेवलपर | $85/माह | 100 बिल्ड (औसतन 10 मिनट) | $120/माह | $35/माह |
| छोटी टीम (5) | $85/माह | 500 बिल्ड (औसतन 10 मिनट) | $600/माह | $515/माह |
| मध्यम टीम (15) | $229/माह (M4 Pro) | 1500 बिल्ड (औसतन 10 मिनट) | $1,800/माह | $1,571/माह |
| एंटरप्राइज़ (50+) | $458/माह (2x M4 Pro) | 5000+ बिल्ड | $6,000+/माह | $5,542+/माह |
My Remote Mac की कीमतें USD में, कर अतिरिक्त।
निष्कर्ष: CircleCI की m4pro.medium क्लास की दर पर (200 क्रेडिट, लगभग $0.12 प्रति मिनट, अक्टूबर 2026 तक) 10 मिनट का एक बिल्ड लगभग $1.20 का पड़ता है, इसलिए $85/माह (USD, कर अतिरिक्त) वाला समर्पित Mac mini M4 लगभग 71 बिल्ड प्रति माह से सस्ता पड़ता है। स्थायी Mac के वार्म कैश हर बिल्ड पर आपकी टीम का इंतज़ार भी घटाते हैं।
सामान्य समस्याओं का निवारण
रनर डिस्कनेक्ट हो जाता है या "Offline" दिखाता है
नेटवर्क समस्या, क्रैश या रीबूट के बाद रनर का कनेक्शन टूट सकता है। gui डोमेन में शुरू किया गया रनर तभी लौटता है जब उसका उपयोगकर्ता लॉग इन करे; चरण 2 का हेडलेस सेटअप इससे बचाता है। सेवा और उसका लॉग जाँचें:
# Check the service (use gui/ instead of user/ if you started it
# from a desktop session)
launchctl print user/$(id -u)/com.circleci.runner
# View the runner log
tail -50 "$HOME/Library/Logs/com.circleci.runner/runner.log"
# Restart the service
launchctl kickstart -k user/$(id -u)/com.circleci.runner
# If the token was revoked, create a new one, put it in
# ~/Library/Preferences/com.circleci.runner/config.yaml and restart
circleci runner token create your-org/mac-runner mac-mini-m4
resource_class नहीं मिला या जॉब्स कतार में अटके हुए
यदि जॉब्स "No matching runner found" के साथ कतार में रहते हैं, तो आपके कॉन्फ़िग में रिसोर्स क्लास डैशबोर्ड से मेल नहीं खाती:
# Verify the exact resource class name in the CircleCI web app:
# Runners (sidebar) lists your resource classes
# The resource_class in .circleci/config.yml must match exactly:
# resource_class: your-org/mac-runner (case-sensitive!)
# Check your runner is online:
circleci runner instance list your-org/mac-runner
# Common mistakes:
# - Wrong namespace (org name vs personal namespace)
# - Typo in resource class name
# - Runner is offline or token is invalid
# - Using 'docker' executor instead of 'machine: true'
Xcode कोड साइनिंग त्रुटियाँ
एक CI मशीन पर कोड साइनिंग के लिए सावधानीपूर्वक कीचेन प्रबंधन की आवश्यकता होती है। रनर प्रक्रिया के पास लॉगिन कीचेन तक पहुँच नहीं हो सकती:
# Option 1: Use Fastlane Match (recommended)
# In your Fastfile:
match(type: "appstore", readonly: true)
# Option 2: Manual keychain management in your job steps
- run:
name: Setup code signing
command: |
# Decode and import the certificate
echo "$BUILD_CERTIFICATE_BASE64" | base64 --decode > /tmp/cert.p12
# Create a temporary keychain
security create-keychain -p "ci" /tmp/ci.keychain
security set-keychain-settings -lut 21600 /tmp/ci.keychain
security unlock-keychain -p "ci" /tmp/ci.keychain
# Import the certificate
security import /tmp/cert.p12 -P "$P12_PASSWORD" \
-A -t cert -f pkcs12 -k /tmp/ci.keychain
# Let codesign use the key without a GUI prompt
security set-key-partition-list -S apple-tool:,apple:,codesign: \
-s -k "ci" /tmp/ci.keychain
security list-keychain -d user -s /tmp/ci.keychain
# Install the provisioning profile (Xcode 16 and later location)
PROFILES=~/Library/Developer/Xcode/UserData/Provisioning\ Profiles
mkdir -p "$PROFILES"
echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode \
> "$PROFILES/profile.mobileprovision"
सिम्युलेटर बूट होने में विफल या टाइम आउट हो जाता है
लंबे समय तक चलने वाली CI मशीनों पर सिम्युलेटर खराब स्थिति में आ सकते हैं। उन्हें बिल्ड के बीच रीसेट करें:
# Add a pre-build step to clean simulators
- run:
name: Reset simulators
command: |
xcrun simctl shutdown all 2>/dev/null || true
xcrun simctl erase all 2>/dev/null || true
# If a specific runtime is missing, reinstall it:
xcodebuild -downloadPlatform iOS
# List available simulators
xcrun simctl list devices available
डिस्क स्थान कम हो रहा है
Xcode बिल्ड बड़ी मात्रा में डेटा उत्पन्न करते हैं। अपने रनर पर स्वचालित सफ़ाई सेट करें:
# Check available disk space
df -h /
# Clean DerivedData folders unused for a week
find ~/DerivedData ~/Library/Developer/Xcode/DerivedData \
-mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} +
# Delete simulators the current Xcode no longer supports
xcrun simctl delete unavailable
# List simulator runtimes, then delete the ones you no longer test on
xcrun simctl runtime list
# xcrun simctl runtime delete <runtime-identifier>
# Clean Homebrew cache
brew cleanup --prune=7
# Set up a weekly cron job for automatic cleanup
(crontab -l 2>/dev/null; echo "0 4 * * 0 find ~/DerivedData -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} + ; /opt/homebrew/bin/brew cleanup --prune=7") | crontab -