pulumi preview и установку плагинов на удалённом Mac, не ломая согласованность lockfile между регионами. Ниже — чеклист рисков, таблица параметров PULUMI_HOME и npm config, правила параллелизма и backoff, затем приёмка и откат. Связанные материалы: Nexus и npm-прокси, Terraform Registry (другой стек, сравнимый pull), GHCR: параллель и backoff.
Три боли 2026 года на Apple Silicon CI:
- Гонка за каталогом плагинов. Несколько job делят один домашний каталог пользователя раннера;
pulumi plugin installоставляет частичные файлы и флаки на APFS. - Две скорости сети. Трансграничный npm registry отвечает медленно, пока бинарный канал Pulumi ещё жив; суммарный таймаут job съедает очередь общего Mac.
- Дрейф lockfile. Разные минорные версии CLI или отсутствие
npm ciменяют дерево Node-провайдеров, иPulumi.lock.yamlперестаёт совпадать с тем что ожидает политика репозитория.
Предпосылки выбора и чеклист рисков
Прежде чем крутить параллелизм, зафиксируйте один эталонный образ раннера с версией pulumi и Node LTS, который совпадает с локальной разработкой в пределах semver-политики. Запретите глобальные npm install -g без пина: они меняют хеши и время установки между job. Проверьте что корпоративный прокси разрешает и registry.npmjs.org, и хосты релизов Pulumi, иначе зеркало должно быть явно описано в runbook. На общем удалённом Mac введите лимит одновременных тяжёлых pulumi preview не выше двух на хост, если дисковая подсистема без NVMe RAID. Согласуйте с безопасностью хранение .npmrc с токеном только через секреты CI, без копирования в лог. Зафиксируйте в репозитории политику: любое изменение Pulumi.lock.yaml только отдельным коммитом с описанием причины. Наконец сверьте часовые пояса артефактов: ночные зеркала иногда отстают по репликации и дают расхождение tarball относительно дневного npm registry.
Registry и каталоги кеша: параметры решения
| Режим | Когда выбирать | Ключевые параметры |
|---|---|---|
| Прямой публичный npm + прямой download плагинов | Низкая задержка до registry, малый монорепозиторий, жёсткий контроль версий CLI | PULUMI_HOME на job; maxsockets=5; fetch-timeout=300000; retries 5–7 |
| Корпоративное зеркало npm (Verdaccio/Nexus) | Трансграничный pull, политика артефактов, единый аудит | NPM_CONFIG_REGISTRY; отдельный cache в workspace; согласовать TTL метаданных с lockfile |
| Очередь job и один тёплый кеш на Mac | Много мелких сервисов, повторяющиеся плагины, дефицит исходящей полосы | Шар только для чтения плюс копирование в PULUMI_HOME job; запрет записи двумя job в один каталог |
Копируемый блок для шага подготовки окружения перед pulumi install или preview:
export PULUMI_HOME="${RUNNER_TEMP:-/tmp}/pulumi-${CI_JOB_ID:-local}"
mkdir -p "$PULUMI_HOME/plugins"
export PULUMI_SKIP_UPDATE_CHECK=true
npm config set maxsockets 5 --location=project
npm config set fetch-retries 6 --location=project
npm config set fetch-retry-mintimeout 20000 --location=project
npm config set fetch-retry-maxtimeout 120000 --location=project
npm config set fetch-timeout 300000 --location=project
PULUMI_HOME уникален для каждого job; (2) npm config list -l не показывает токен в stdout CI; (3) закоммиченный Pulumi.lock.yaml совпадает с эталонным pulumi install на golden-образе.
Параллельная загрузка и отказ с backoff
Ограничение maxsockets снижает вероятность ECONNRESET на длинных каналах, но не заменяет backoff на уровне шага. Оборачивайте pulumi preview в цикл с паузами 8 → 16 → 32 → 64 секунды при кодах 429 и сетевых обрывах, с потолком четырёх попыток до эскалации в алерт. Для npm ci держите отдельный кеш пакетов внутри workspace и включайте --prefer-offline только после успешного прогрева кеша, иначе получите скрытый дрейф версий. Если несколько репозиториев делят один Mac, разведите NPM_CONFIG_CACHE по префиксу репозитория. При пиковых релизах npm в 2026 году наблюдаются всплески латентности даже при стабильном провайдере сети; закладывайте запас по wall-clock в SLA пайплайна. Не параллельте два тяжёлых plugin install одного пакета разных версий на одном хосте без изоляции каталогов. Логируйте длительность каждой фазы install и preview отдельно, чтобы отличить узкое место npm registry от сервера плагинов.
attempt=1
max=4
while [ "$attempt" -le "$max" ]; do
pulumi preview --non-interactive --stack "${STACK}" && exit 0
code=$?
if [ "$code" -eq 0 ]; then exit 0; fi
sleep $((8 * attempt))
attempt=$((attempt + 1))
done
exit 1
Приёмочные сценарии и откат
Приёмка: на чистом каталоге клонируйте коммит, выполните блок переменных выше, затем npm ci и pulumi install; сравните хеш Pulumi.lock.yaml с эталоном. Запустите pulumi preview --non-interactive с флагом политики «ожидание нулевых изменений» там где это допускается командой инфраструктуры. Сохраните артефакт лога и список установленных плагинов из pulumi plugin ls. Проверьте что время фазы не превышает порог p95, зафиксированный для вашего региона. Откат: при неверном lock откатите merge-коммит, удалите каталог PULUMI_HOME job и повторите установку; не пытайтесь чинить частично скачанные плагины вручную на общем раннере. Если откат касается только npm-зависимостей Node-провайдера, верните package-lock.json и пересоберите lock Pulumi на golden-образе. Документируйте причину сетевого сбоя с меткой времени для сравнения с графиком зеркала.
Нода, тариф и следующий шаг
Для трансграничных команд выгоднее выделить удалённый Mac с предсказуемым исходящим каналом и диском NVMe под кеш плагинов, чем бесконечно наращивать retries на общем пуле. Подберите тариф и регион ноды ближе к зеркалу npm registry и к корпоративному relay для Pulumi, затем закрепите golden-образ. Публичные страницы MacPull без обязательного входа: главная, цены, аренда и покупка, центр помощи, каталог блога.
Apple Silicon под Pulumi и npm CI
Выделенный Mac и понятная сеть снижают дрейф lockfile и время install. Ниже только открытые страницы сайта.