Почему одного Nomad мало для «параллельной» фермы
Двойная запись в общий том ломает деревья артефактов; при трансграничной задержке порядок синхронизации может «переворачиваться», и вы получите обрывки бинарников. Сочетайте build lock на уровне ОС с политикой fan-out и promotion — параметры rsync и дисковые пороги разобраны ниже в разделе о стыке с rsync и в связанной статье блога по той же линейке.
- Дрейф размещения: без meta тяжёлый batch случайно попадает на «лёгкий» узел, IO становится зубчатым.
- Два писателя: если несколько job’ов одновременно promote в один каталог, приёмник rsync оказывается повреждённым.
- Обрыв диска: даже на 1 ТБ DerivedData и симуляторы быстро загоняют том в жёлтую зону; конфигурация 2 ТБ лишь отодвигает ту же проблему без ротации.
Матрица решений: роль Nomad × хранилище
| Топология | Цель на стороне Nomad | Хранилище и синхронизация |
|---|---|---|
| Один «золотой» узел + fan-out воркеры | promote — count = 1 или отдельная очередь; остальное — batch. |
После фиксации золотого каталога — rsync на чтение/инкремент; bwlimit по профилям региона. |
| Золотой на каждый регион | meta region_lane в constraint; аффинити ведёт тяжёлую компиляцию на выделенные Mac mini M4. |
Больше сверок консистентности и времени. Split DNS и реестр — по чек-листу из статьи про split DNS и реестр. |
| Полная локальная сборка на каждом узле | spread по node.datacenter; артефакты уводите в объектное хранилище или собирайте только через promote. |
Пороги диска срабатывают раньше; планируйте линию 2 ТБ и агрессивную чистку кэшей. |
На практике наименьше инцидентов даёт правило: «компиляция параллельна, запись в канонический каталог и rsync-promote — однопоточны».
Исполняемые ограничения job: смысл фрагментов HCL (без полного файла)
На каждом клиенте задайте meta — например ci_tier (heavy/light), artifact_lane (golden/worker) и disk_class (1tb/2tb). В спецификации job уровень job обычно получает type = "batch" для одноразовых сборок; блоки constraint с оператором = или distinct_hosts отсекают неподходящие узлы (обязательные условия). Блоки affinity с весом задают «мягкое» предпочтение: например чаще выбирать узлы с meta.disk_class = 2tb, не ломая планирование, если таких мало.
Внутри group поле count для promote держите равным единице; для воркеров — по числу параллельных слотов. Секция spread по node.datacenter или по произвольному атрибуту равномерно распределяет batch, чтобы один датацентр не съел всю очередь. Для задач с чувствительным SLA поднимайте priority и сузьте restart, чтобы «зацикленный» promote не забивал очередь. Интерактивный SSH/Mosh для операторов держите отдельно от этой плоскости пакетной выкладки, иначе смешиваются SLA и блокировки.
| Элемент | constraint | affinity |
|---|---|---|
| Назначение | Жёсткий фильтр: job не стартует, если условие не выполнено. | Предпочтение с весом: планировщик старается выполнить, но может отступить. |
| Типичный кейс на Mac mini M4 | Только узлы с artifact_lane = golden для promote. |
Предпочесть disk_class = 2tb для тяжёлого Xcode batch. |
| Риск | Слишком узкие правила → pending без явной причины в UI. | Слишком высокий вес → неочевидный перекос по одному пулу. |
Мини-пример смысла (не полный HCL): для группы компиляции добавьте пару constraint на ${meta.ci_tier} и ${node.class}; для promote — отдельный job с единственной группой, constraint «только golden», без spread по воркерам.
Build lock: два уровня — планировщик и ОС
Nomad разводит размещение, но разделяемое дерево APFS всё равно нужно защищать: короткий участок promotion оборачивайте flock. Batch пишет в локальный WORK_DIR; только после эксклюзивной секции — rsync в канонический путь. Поверх SSHFS advisory-lock считайте ненадёжным.
LOCK_FILE="/var/tmp/ci-artifact-promote.lock"
flock -n "$LOCK_FILE" bash -c '
./scripts/compile.sh
rsync -az --delete ./out/ "/Volumes/Artifacts/promote/"
' || { echo "блокировка занята"; exit 17; }
Обертку вызывайте из задачи exec или raw_exec. Код выхода 17 трактуйте как метрику конкуренции за promote.
Пороги расширения: 1 ТБ и 2 ТБ (матрица)
| Заполнение тома | Линия 1 ТБ | Линия 2 ТБ |
|---|---|---|
| до ~70% | Рутинная чистка DerivedData и старых симуляторов; ротация логов Nomad. | То же; запас больше, но политику не отменяет. |
| 70–80% (жёлтая зона) | В спринте закрепите апгрейд диска или вынос архивов; ограничьте новые «полные» сборки на всех узлах. | Жёлтая зона наступает позже — заранее снизьте одновременность burst-batch. |
| 80–90% | Сузьте параллелизм исполнения и bwlimit fan-out rsync; при необходимости остановите всё, кроме promote, пока не отступит заполнение. | На 2 ТБ снова наступит давление, если копятся версии симуляторов; связка с meta disk_class помогает Nomad не забивать «тонкие» узлы. |
| >90% (красная зона) | Жёсткий стоп до касания скрытого объёма APFS и снимков. Расширение кластера или диска — в приоритете. Пороги — триггеры масштабирования; закрепите их на дашборде SRE. | |
Сравнить конфигурации и шаг диска без аккаунта можно на странице «Тарифы» — удобно заложить запас до жёлтой зоны.
Стык с rsync-синхронизацией артефактов
Расписание и очередь оставьте в Nomad; после появления «золотого» снимка распространение делайте профилями rsync — так проще читать полосу, докачку и таймауты. Единственный писатель кладёт gate-файл (контрольная сумма или манифест); fan-out воркеры тянут дерево только после проверки. Смещайте периодические оценки диска и rsync, чтобы не бить по IO одним фронтом. Подробные флаги и runbook — в материале про rsync-матрицу; держите оба документа согласованными для команды эксплуатации.
FAQ: Nomad и параллельный Mac-кластер
Constraint против affinity: обязательные условия — в constraint; экономия и мягкое предпочтение узлов — в affinity.
flock постоянно «занят»: критическая секция слишком широкая; укоротите promote, компиляцию вынесите за пределы лока.
2 ТБ, а жёлтая зона снова близко: узкое место в политике симуляторов и кэшей; разведите «тяжёлые» и «лёгкие» узлы через meta и очереди Nomad.
--delete в rsync прогоняйте dry-run.
Стабильный Nomad + rsync на однотипных Mac mini M4
Без входа в аккаунт откройте тарифы и оформите узлы: выровняйте пул под Nomad, согласуйте класс диска и расширяйтесь до жёлтой зоны диска.