Azimjon Abdurasulov

DevOps 5: Self-Hosted CI Runnerlar va Build Kesh — Mac mini Klasteri, Docker va Remote Caching

🛠️ DevOps Engineering

DevOps 5: Self-Hosted CI Runnerlar va Build Kesh — Mac mini Klasteri, Docker va Remote Caching

Holat: 2026-yil sentabr. Bulutdagi macOS runner'lar (GitHub Actions macos-14/15, Bitrise, CircleCI) qulay bo'lsa-da, katta iOS jamoalari uchun juda qimmatga tushadi va har bir build yangi toza mashinada noldan yig'ilgani sababli sekin ishlaydi. Ushbu darsda o'z Mac mini klasteringizni qurish, DerivedData keshini saqlash va build vaqtini 3-4 barobarga tezlashtirish usullari tahlil qilinadi.

Mundarija

  1. Iqtisodiy va texnik tahlil: Cloud vs Self-Hosted
  2. Mac mini'da GitHub Actions Runner o'rnatish
  3. Runner'ni tizim xizmati (launchd) sifatida ishga tushirish
  4. Kesh strategiyasi: DerivedData va SPM keshlash
  5. Tozalash skriptlari: Simulator va disk gigiyenasi
  6. Virtualizatsiya: Tart va Cirrus CLI orqali toza VM'lar
  7. Remote Caching: Tuist va Bazel yondashuvi
  8. Xulosa
  9. Manbalar

1. Iqtisodiy va texnik tahlil: Cloud vs Self-Hosted {#iqtisod}

Narxlar taqqoslovi (2026)

GitHub Hosted macOS runner'lar standart Linux runner'lardan 10 barobar qimmatroq (1 daqiqasi taxminan $0.08 - $0.16).

10 kishilik iOS jamoasi kuniga o'rtacha 30 marta CI build ishga tushiradi (har biri 20 daqiqa):

  • Oylik sarf: $30 \times 20 \times 22 \text{ kun} = 13,200 \text{ daqiqa} \approx \$1,050 - \$2,100 / \text{oy}$.
  • Bitta Apple Silicon Mac mini (M4, 24GB RAM): ~$800 bir martalik xarajat.
  • Xulosa: O'z Mac mini serveringizni o'rnatish 1-2 oy ichida o'zini to'liq oqlaydi (ROI payback).

2. Mac mini'da GitHub Actions Runner o'rnatish {#ornatish}

Mac mini'da alohida ci-runner foydalanuvchisi yaratiladi va Homebrew hamda Xcode o'rnatiladi:

# Runner papkasini yaratish:
mkdir -p actions-runner && cd actions-runner || exit 1

# GitHub Runner arxivini yuklab olish va ochish:
curl -o actions-runner-osx.tar.gz -L https://github.com/actions/runner/releases/download/v2.320.0/actions-runner-osx-arm64-2.320.0.tar.gz
tar xzf ./actions-runner-osx.tar.gz

# Repoga ulash (token GitHub Settings -> Actions -> Runners orqali olinadi):
./config.sh --url https://github.com/my-org/my-ios-app --token AABBCCDDEEFF112233 --name "mac-mini-01" --labels "self-hosted,macOS,ARM64,xcode-16"

3. Runner'ni tizim xizmati (launchd) sifatida ishga tushirish {#launchd}

Mac qayta yuklanganda (reboot) runner avtomatik yonishi uchun u launchd xizmati sifatida sozlanadi:

# Xizmatni o'rnatish va yoqish:
sudo ./svc.sh install
sudo ./svc.sh start

# Holatni tekshirish:
sudo ./svc.sh status

💡 Muhim: Mac sozlamalarida Energy Saver -> Prevent automatic sleeping when display is off yoqilgan bo'lishi va avtomatik login sozlanishi shart (Keychain va UI testlar ishlashi uchun).


4. Kesh strategiyasi: DerivedData va SPM keshlash {#kesh-strategiyasi}

Self-hosted runner'ning eng katta ustunligi — doimiy disk xotirasi (persistent disk). Har safar Package.resolveddagi barcha kutubxonalar noldan yuklab olinmaydi.

SPM Umumiy Keshini yoqish:

# Xcode SPM keshini umumiy tizim papkasida saqlash:
defaults write com.apple.dt.Xcode IDEPackageSupportUseSharedCache -bool YES

GitHub Actions Workflow:

name: Self-Hosted iOS CI

on:
  pull_request:
    branches: [main]

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

    steps:
      - name: Reponi klonlash
        uses: actions/checkout@v4

      - name: Build va Test (DerivedData keshi bilan)
        run: |
          xcodebuild test \
            -workspace AzimjonDev.xcworkspace \
            -scheme AzimjonDev \
            -destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
            -derivedDataPath ./build/DerivedData \
            -resultBundlePath ./build/TestResults.xcresult

5. Tozalash skriptlari: Simulator va disk gigiyenasi {#gigiyena}

Persistent runner'lar vaqt o'tishi bilan "axlat" to'playdi (eskirgan simulyator keshlar, gigabaytlab loglar). Har bir build yakunida tozalash scripti ishga tushishi kerak:

#!/bin/bash
set -euo pipefail

echo "==> Simulyatorlarni tozalash..."
xcrun simctl erase all

echo "==> 7 kundan oshgan eski DerivedData fayllarni o'chirish..."
find "$HOME/Library/Developer/Xcode/DerivedData" -maxdepth 1 -mindepth 1 -mtime +7 -exec rm -rf {} +

echo "==> Xcode Caches tozalash..."
rm -rf "$HOME/Library/Caches/com.apple.dt.XCTest"

6. Virtualizatsiya: Tart va Cirrus CLI orqali toza VM'lar {#virtualizatsiya}

Agar jamoangizda bir vaqtning o'zida bir nechta build yursa va ular bir-birining muhitini buzmasligi kerak bo'lsa, Tart (Apple Silicon uchun engil macOS virtualizatsiyasi) ishlatiladi:

# Tart o'rnatish:
brew install cirruslabs/cli/tart

# Tayyor toza macOS + Xcode obrazini yuklash:
tart clone ghcr.io/cirruslabs/macos-sonoma-xcode:latest my-clean-vm

# VM'ni ishga tushirish (har bir CI run tugagach, VM o'chirib tashlanadi):
tart run my-clean-vm

Bu usul bulutli GitHub runnerlar kabi 100% toza muhit beradi, lekin lokal Mac mini tezligida ishlaydi.


7. Remote Caching: Tuist va Bazel yondashuvi {#remote-caching}

Loyiha kattalashgani sari (500,000+ qator kod), bitta dasturchi yig'gan modulni boshqa dasturchi qayta yig'masligi kerak. Remote Caching arxitekturasi:

Dasturchi A (PR ochdi) ──> Kod o'zgarmagan modullar ──> AWS S3 / Tuist Cloud Kesh
                                                              ▲
Dasturchi B (Pull qildi) ────────────────────────────────────┘ (Yig'ilgan .framework yuklab olinadi)
  • Tuist Cache: tuist cache warm buyrug'i orqali o'zgarmagan barcha ichki frameworklar binary (.xcframework) qilib olinadi va lokal build vaqti 10 daqiqadan 45 soniyagacha tushadi.

8. Xulosa {#xulosa}

  • Kichik va o'rta jamoalar uchun 1-2 ta Mac mini runner'i CI xarajatlarini 90% ga kamaytiradi.
  • DerivedData va SPM keshlarini to'g'ri boshqarish orqali build vaqti 3 baravargacha qisqaradi.
  • Tart va Tuist Cache kabi zamonaviy vositalar self-hosted infratuzilmani korporativ darajadagi ishonchlilikka olib chiqadi.

9. Manbalar {#manbalar}

  1. GitHub Docs — Adding self-hosted runners
  2. Tart — macOS virtualization for CI
  3. Tuist Documentation — Caching

Markdown manba

iOS Lessons