Уровень диска · DerivedData / CocoaPods / Gradle · 3 слоя артефактов · Runbook из 6 шагов · жёсткие пороги
Операции, мобильная платформа и tech lead'ы с договорными disk SLO для общих Mac build pool часто получают в пятницу вечером одинаковые алерты: Runner онлайн, jobs «No space left»; DerivedData заполняет системный том; глобальные кэши CocoaPods/Gradle без владельца; артефакты остаются локально после rsync. Сначала кто с какой проблемой сталкивается, когда мультитенантная ротация Mac Mesh не имеет наблюдаемых уровней диска и контрактов послойного возврата. Затем вывод: L1 DerivedData / L2 кэши зависимостей / L3 артефакты CI и runbook из 6 шагов — аудируемая рутина вместо «пожарной» схватки. Вы получаете 5 скрытых налогов, таблицу стратегий, поля зонда, 6 шагов, 3 жёстких порога, FAQ. См. также: блокировки seat lock, чеклист дрейфа golden image, rsync и объектное хранилище, матрица SLO трёх пулов et изоляция Git worktree.
В тикетах Mac Mesh 2026 диск — не только «не хватает 100 ГБ». Без единого контракта между ротацией арендаторов, локальностью кэша и жизненным циклом артефактов APFS выглядит свободным, а Xcode падает на записи временных файлов.
DerivedData без границ: Несколько репозиториев делят ~/Library/Developer/Xcode/DerivedData; index и ModuleCache перемешиваются по веткам; один clean удаляет ModuleCache соседа — случайные ошибки линковки, а не «диск полон».
Глобальный кэш CocoaPods/Gradle без TTL: ~/Library/Caches/CocoaPods et ~/.gradle/caches только растут; старые tarballs после обновления Pods; worktree с несколькими ветками параллелизм усиливает contention.
Артефакты «загружены, но остались локально»: объектное хранилище OK, но $CI_ARTIFACTS_DIR без политики retention; хук завершения rsync не привязан — IPA/dSYM съедают диск.
Снимки APFS vs «доступно»: Локальные снимки обманывают df; реальная ёмкость записи рвётся на пиках компиляции. Нет waterline_used_pct по томам/слоям.
Очистка vs seat lock: обход каталогов до окончания lease или конфликт с TTL seat lock, — «диск пуст, build красный».
Результаты: словарь каталогов 3 слоёв, двойной уровень warn/hard, LRU по окончании lease, еженедельная проверка дрейфа golden image отдельно. Без этого не обещайте «любой monorepo параллельно» на общем пуле. Далее — три философии очистки, без «пятница ssh rm -rf для всех».
Управление диском — не «чистить сильнее». Баланс hit rate сборки, аудируемая очистка, изоляция арендаторов. Закрепите таблицу в change review: одна стратегия по умолчанию на слой (L1/L2/L3).
| Стратегия | L1 DerivedData | L2 Pods/Gradle | L3 Artifacts | Подходит для | Главный риск |
|---|---|---|---|---|---|
| Ручной cron | глобальный rm на выходных | редкий pod cache prune | find по возрасту | Малые команды, низкий параллелизм | Удаление у соседа, нет аудита |
| Daemon уровня | LRU по workspace hash | Evict по ёмкости | 48ч после успешного rsync | По умолчанию для общего пула | Нужны метрики и контракт блокировки |
| Сброс образа | откат snapshot очищает | Обновлено с образом | Замена тома | Дрейф вне контроля, compliance snapshots | Замедление cold-start компиляции |
Правило: общие пулы по умолчанию — «daemon уровня»; сброс образа только квартальный fallback с чеклист дрейфа golden image, не ежедневный LRU.
Когда Dedicated и Shared ротация сосуществуют, ключи кэша L1 должны иметь тег типа пула, иначе sweep общего пула вытеснит локальность dedicated.
L1: /var/mesh/cache/deriveddata/{workspace_hash}, привязка через Xcode DERIVED_DATA_DIR. L2: /var/mesh/cache/cocoapods, /var/mesh/cache/gradle—без записи в глобальные кэши home пользователя. L3: /var/mesh/artifacts/{job_id}—после upload — только sidecar checksum. Мониторинг сообщает layer_*_bytes по слоям вместо расплывчатого «partition / 85%».
Эти 6 шагов требуют runners на метках Mac Mesh и seat acquire/release. Не меняйте порядок: уровни без метрик — слепые удаления.
Зафиксировать словарь и пути трёх слоёв: записать корни L1/L2/L3 и пороги warn (82%)/hard (92%) в repo mesh-disk-policy.yaml, зарегистрировать точки монтирования в чеклист образа.
развернуть зонд disk-waterline: каждые 60 с: использование тома и байты по слоям; экспорт Prometheus/OpenTelemetry; на hard — runners в drain и fail-fast новых jobs.
Изолировать DerivedData: CI задаёт DERIVED_DATA_DIR в бакет workspace hash; окончание lease — LRU этого бакета — никогда не sweep глобальный DerivedData.
Evict кэша зависимостей L2: pod cache clean по ёмкости; GRADLE_USER_HOME под mesh; ограничить max-cache-size.
Артефакты и хуки rsync: callback multipart-complete объектного хранилища удаляет локальный L3; неудачные retries 7 дней — поля как в runbook артефактов.
Еженедельная проверка и учение: сверить checksums golden image, симулировать отказ job на 90%, журнал аудита очистки; при переполнении Burst сначала очистить L3, затем принимать прерываемые jobs.
hostname pool_type volume_mount waterline_used_pct waterline_warn_threshold waterline_hard_threshold layer_l1_deriveddata_bytes layer_l2_cocoapods_bytes layer_l2_gradle_bytes layer_l3_artifacts_bytes seat_lease_id last_cleanup_ts_unix cleanup_evicted_bytes_1h disk_waterline_hard_stop
Примечание: Вывод зонда — первая строка Grafana, не только OS-алерты. Стройте cleanup_evicted_bytes_1h с успешными сборками, чтобы отличить реальную очистку от «меньше сборок — диск кажется лучше».
Алерты диска часто пересекаются с SLO очереди симптомами. Таблица покажет, это ёмкость, ключи кэша или накопление артефактов, до выбора scope очистки.
| Симптом | layer_* dominant | Вероятная причина | Первое действие |
|---|---|---|---|
| Падает только шаг Xcode | L1 high | Загрязнённый DerivedData или битый index | Очистить бакет по workspace hash |
| Медленный смешанный Android/iOS пул | L2 high | Pods/Gradle никогда не evict | ужесточить потолок L2 |
| Upload OK, диск полон | L3 high | хук rsync не привязан | добавить callback объектного хранилища |
| df OK, запись падает | Snapshots | APFS local Snapshots | сократить retention снимков + зонд |
Предупреждение: Не запускайте rm -rf на уровне тома, удерживая seat lock. Скрипты очистки должны видеть пустой seat_lease_id или истёкший lease, иначе удалят ModuleCache во время компиляции.
Если L1 снова заполняется за 24 ч после очистки бакета, проверьте изоляцию worktree — несколько полных деревьев DerivedData на узле, прежде чем покупать диск.
Компромисс полей для пулов 16/24 ГБ. Прикрепляйте к change tickets как внешнее SLO; Dedicated может снизить warn на 5 п.п. для стабильного hot cache index.
waterline_warn_threshold=82 запускает eviction L3→L2→L1; waterline_hard_threshold=92 отклоняет новые jobs и ставит disk_waterline_hard_stop=1.На системных томах 512 ГБ с ~60% под mesh: L2 суммарно 80 ГБ (по 40 ГБ soft cap CocoaPods/Gradle), L3 на job 12 ГБ (с dSYM). «Только cron на выходных» или «все чистят кэш по SSH» без полей аудита и seat-контрактов — удаления у соседей, cold start, полузаписанные артефакты в релизную неделю. Для команд с CI iOS/Android и disk SLO на контрактной облачной Mac Mini аренда Mac Mini VpsMesh обычно лучший выбор. См. страница цен, центр помощи и страница заказа.
По умолчанию: бакеты по workspace hash с seat lease; по окончании lease — LRU. Параллельные ветки: изоляцию worktree article; не допускайте неограниченного роста глобального ~/Library/Developer/Xcode/DerivedData.
Runner делает fail-fast и шлёт disk_waterline_hard_stop; планировщик маршрутизирует на узел с запасом или Burst. Семантика seat — в статье о seat lock.
Да. Очистка диска только забирает runtime-мусор; не заменяет чеклист дрейфа snapshot. Подключение: центр помощи; тарифы на страница цен.