DevOps 2026-04-02 8 мин

2026: глобальные команды — управление кэшем сборки iOS: Xcode Derived Data и зависимости — одна зона или региональные физические Mac?

Глобальные iOS-команды колеблются между «один авторитетный кэш + трансрегиональная синхронизация» и «локальные кэши на физических Mac в каждом регионе». Здесь — выравнивание задержки, консистентности и стоимости по порогам для согласования: две матрицы, семь шагов выкатки, готовые фрагменты rsync и переменных окружения, FAQ.

2026: кэш сборки iOS, Xcode Derived Data и региональная стратегия физических Mac

Кому больно: когда глобальные команды переиспользуют Xcode Derived Data и кэши SPM/CocoaPods между CI и удалёнными физическими Mac, трансокеанское восстановление кэша раздувает P95 времени сборки, а дрейф кэша даёт спорадические ошибки линковки. Вывод: не связывайте низкооборотные read-only кэши зависимостей с той же политикой репликации, что и высокочастотный Derived Data; выбирайте одну зону или колокацию по матрице порогов. Что внутри: две таблицы, семь шагов, готовые команды, FAQ.

1. Боли и скрытые издержки

  1. «Шторм мелких файлов»: Derived Data содержит огромное число крошечных файлов и индексов. Трансрегиональный rsync или листинг метаданных в объектном хранилище часто съедает полезную пропускную способность — джобы висят на «Restore cache», а не на компиляции.
  2. Консистентность важнее «последней ночной сборки»: смесь патч-версий Xcode, Swift toolchains, модульных кэшей и индексов даёт флейки инкремента. Нужны проверяемые content-addressed ключи. Для базовой линии RTT см. мультирегиональную приёмку удалённого физического Mac: SLO по RTT, джиттеру и потерям пакетов; для контекста iOS-поставки и пулов — Xcode Cloud и мультирегиональный пул физических Mac для iOS.
  3. Права и комплаенс: концентрация в одном регионе часто сводит отпечатки исходников и артефакты в одном бакете. С пер-региональными Mac явно разделите, какие каталоги могут покидать юрисдикцию, а какие остаются на локальных аудируемых дисках.

2. Derived Data и кэши зависимостей: авторитет одного региона vs локально на физических Mac

Сначала отрежьте по вопросам: насколько независимо регионы гоняют полные сборки и какую долю джобы съедает восстановление кэша (порядок величины можно подстроить под размер репозитория).

Измерение Один авторитетный регион + асинхронная репликация Локальный кэш на физическом Mac в регионе (колокация)
Лучше всего подходит Один основной регион сборок; остальные < 3 полных сборок/сутки и терпят холодный старт 15–45 мин В регионе ≥ 5 интеграционных или полных сборок/сутки либо restore > ~25% длительности джобы
Сеть Репликация по выделенке или внутри одного облака; массовое копирование — в окна обслуживания Билдер, Git и артефакты в регионе; Derived Data не на горячем трансокеанском пути
Derived Data «Золотые» снимки для вытягивания другими регионами; жёсткое разбиение по точной версии Xcode Независимый записываемый каталог на регион; без жёстких ссылок между патч-версиями Xcode
SPM / CocoaPods Объектное хранилище + CDN только для чтения; слой отдельно от Derived Data Региональный том или локальный SSD; периодически сверяйте checksum с upstream
Главные риски Один плохой снимок отравляет все регионы; счета за трансрегион Дрейф раскладки диска и политик удержания; нужна автоматическая эвикция

3. Трансграничная коллаборация: матрица задержка × консистентность

Отложите на ось P95 RTT к Git и артефактам и долю инцидентов кэша (недетерминированные сбои, отнесённые к кэшу, за неделю ÷ все сборки) для быстрых ревью.

Инциденты кэша < 0,5% Инциденты кэша ≥ 0,5%
Региональный P95 RTT к Git < 80 мс Предпочитайте колокацию: локальный Derived Data + кэш зависимостей в регионе Сначала keyspace: бакеты по точной версии Xcode и ветке, затем колокация
P95 RTT ≥ 80 мс или нестабильные потери Допустим авторитетный кэш зависимостей в одном регионе + минимальный набор compile-критичного вне региона Запретите горячую трансокеанскую синхронизацию Derived Data; переходите на канареечные чистые пересборки

В SLO-документ добавьте: максимальный возраст записи кэша в текущем релизном поезде; P95 от завершения restore до старта первой компиляции xcodebuild < 90 с (средние репо) или 180 с (монорепо). Нарушение — отключение удалённого кэша для метки джобы и принудительная чистая региональная сборка.

4. Семь шагов выкатки

  1. Инвентаризация путей: разделите DerivedData, глобальный кэш SPM, кэш CocoaPods и кастомные бинарные фреймворки. В объектное хранилище — только content-addressed деревья только для чтения.
  2. Ключи кэша: минимум версия Xcode, Swift, ветка или хэш lockfile, конфигурация Debug/Release. Запрет на один репозиторный указатель latest.
  3. Основной регион сборок: совместите с основным Git remote и реестром артефактов; остальные регионы синхронизируют только слой зависимостей или принимают длинные холодные старты.
  4. Канареечная джоба: продвигайте новый бакет только после полной чистой сборки и тестов на одном физическом Mac.
  5. Три фазы метрик: restore, компиляция, тесты отдельно. Если доминирует restore — чините топологию раньше, чем покупаете CPU.
  6. Инвалидация: в день апгрейда Xcode автоматически уберите старые бакеты; держите N−1 снимок только для чтения 7–14 дней для отката.
  7. Артефакт согласования: распечатайте обе матрицы на обложку runbook дежурства. Перед сменой топологии кэша повторите региональные пробы RTT/джиттера из статьи по приёмке выше.

5. Чек-лист параметров синхронизации (копируйте в скрипты)

Подставьте хосты и пути. Удаления сначала в dry-run.

A. rsync: массовый Derived Data (осторожно с --delete)

Пуш на региональный том (пример):

rsync -aH --numeric-ids --delete-delay \
  --exclude 'ModuleCache.noindex/**' \
  --exclude 'CompilationCache.noindex/**' \
  --timeout=300 --contimeout=60 \
  ~/Library/Developer/Xcode/DerivedData/ \
  build@REGION-MAC.CORP:/Volumes/BuildCache/DerivedData/

B. rsync: SPM только для чтения (без --delete, чтобы не трогать параллельных билдеров)

rsync -aH --numeric-ids --omit-dir-times \
  ~/Library/Caches/org.swift.swiftpm/ \
  s3proxy-local:/spm-ro/KEY/

C. Поток tarball кэша CocoaPods (дорогой трансрегион — допустима устарелость порядка часа)

tar --posix -cf - -C ~/Library/Caches/CocoaPods . \
  | pigz -1 \
  | ssh -o ServerAliveInterval=30 build@REMOTE 'pigz -d | tar -xf - -C /Volumes/Cache/CocoaPods'

D. Переменные окружения (фрагмент шаблона CI)

export DERIVED_DATA_PATH="/Volumes/BuildCache/DerivedData/${CACHE_KEY}"
export CLONED_SOURCE_PACKAGES_DIR_PATH="/Volumes/BuildCache/SPM/${CACHE_KEY}"
export COCOAPODS_CACHE_DIR="/Volumes/BuildCache/CocoaPods/${CACHE_KEY}"
# Перед xcodebuild: проверьте права на запись и совпадение Xcode с CACHE_KEY

6. Резюме и цифры для цитирования

Примеры порогов: ① restore > ~25% длительности джобы → архитектурный разбор. ② сбои, связанные с кэшем, ≥ 0,5%/нед → заморозить трансрегиональный Derived Data. ③ --timeout=300, --contimeout=60 для rsync. ④ ключи обязаны включать точную версию Xcode. ⑤ пуловое продвижение только после канареечной чистой сборки.

Универсального рецепта нет: зависимости хотят «далеко, медленно, только чтение», а Derived Data — «рядом, быстро, одноразово». Сначала разведите бакеты; спор одна зона vs много регионов тогда сводится к арифметике полосы и математике SLO.

7. Запускайте эту модель управления на Mac mini и macOS

Все пути выше нативны для macOS: Xcode, SwiftPM, локальные SSD и Unix-утилиты без прослоек. Mac mini на Apple Silicon даёт высокую пропускную способность объединённой памяти при порядка 4 Вт в простое — удобный круглосуточный якорь регионального кэша, который прогревает индексы и зависимости, пока парк простаивает. Низкая частота падений macOS и связка Gatekeeper, SIP и FileVault упрощают согласование с ИБ по сравнению с «собранными» хостами.

Если цель — чтобы restore плюс компиляция укладывались в локальный RTT, а не тащили Derived Data через океан архивами, стандартизация пулов Mac mini по регионам — один из самых тихих форм-факторов: компактно, часто без вентилятора, ниже по энергии и вниманию эксплуатации на горизонте нескольких лет.

Когда нужно перейти от «где-то собирается» к подписанному SLO, Mac mini M4 — сильная точка входа по цене и стабильности для эталонных билд-узлов: арендуйте или масштабируйте региональную физическую ёмкость и закрепляйте политику кэша на реальных дисках и сетях.

Готовы разместить узлы там, куда указывают метрики? Откройте ZoneMac — физические Mac под вашу топологию CI.

8. FAQ

Где жить Derived Data — в одном регионе или на каждом региональном физическом Mac?

Если сборки в основном в одном регионе, а остальные лишь легко валидируют — авторитет в одном регионе с асинхронной репликацией. Если в каждом регионе ежедневные полные сборки и RTT к Git/артефактам через океан критичен — записываемый Derived Data колокируйте на региональных физических Mac, разрешение зависимостей — в регионе билдера.

Какие пороги консистентности важнее всего?

Примеры для согласования: макс. возраст записи в окне релизного поезда, согласованность checksum/content key, запрет общего пути для разных патч-версий Xcode, доля сбоев SPM и доля холодных стартов. Выше порога — региональная чистая пересборка вместо инкрементальной трансрегиональной синхронизации.

Должны ли SPM и CocoaPods следовать той же политике, что Derived Data?

Нет. Зависимости — content-addressed read-only; Derived Data — вывод сборки и индексы. Держите зависимости на объектном хранилище или томах только для чтения, Derived Data — записываемым per-регион.

Главный риск концентрации в одном регионе?

Трансрегиональная полоса, длинный хвост задержки на огромных деревьях каталогов и одна плохая синхронизация, отравляющая несколько регионов. Смягчайте порционной проверкой, бакетами по веткам и канареечными сборками до продвижения.

Региональные физические Mac

iOS-сборки ближе к Git и артефактам

Колокация узлов с репозиториями сокращает задержку восстановления Derived Data и зависимостей — пулы Xcode и удалённые рабочие столы по требованию.

По факту использования Быстрый старт Надёжность
Аренда macOS в облаке Региональные узлы для iOS CI
Получить сейчас