Эта статья отвечает ровно на один вопрос: вы на несколько дней в Сингапуре с одним ультрабуком — успеете ли за 72 часа пройти цепочку правка кода → удалённая сборка → TestFlight без Mac Studio в багаже?
Допущение (всё ниже опирается на него): у вас уже есть постоянно доступный macOS build node с зафиксированной версией и предсказуемым egress — не Mac коллеги «на вечер» и не CI-runner с холодным стартом на каждый job. Runbook описывает, как запускать этот node в дороге; без стабильного build node рухнет даже идеальный SSH-чеклист.
Хронология — реальный hotfix команды 13–15 ноября 2025 (время Сингапура), зафиксированный на 3 июня 2026. Идентификаторы замаскированы; фрагменты логов — дословно из терминала и GitHub Actions, чтобы вы повторили те же проверки у себя.
Российские и СНГ-команды часто путают «я в Сингапуре» и «нужен локальный Mac в аренду». Для сборки iOS и XCTest город Mac в облаке не важен; на месте решают стабильный uplink и то, что App Store Connect видит egress build-машины, а не IP номера в отеле.
Перед вылетом согласуйте три пункта:
-
Сначала стабильный build node
Фиксированный IP, закреплённый Xcode, match с единственным писателем; в поездке только триггер, не поднимать подпись в отельном Wi‑Fi.
commit + run ID в тикете
-
Узел следует за egress артефактов
Только APAC-бета — приоритет Сингапур; ASC Северной Америки и фиксированный egress — builder в Канаде.
см. таблицу
-
Не кодить весь день по VNC
Отель или транстихоокеанский канал делают screen sharing хрупким; VNC — только для связки ключей.
сначала SSH
Проверяемые якоря (фрагмент поездки, ноябрь 2025)
В день зелёного релиза мы зафиксировали в тикете те же поля — в вашем runbook должно быть так же, иначе потом не отличить медленную сеть от медленной компиляции:
В российских командах часто не архивируют hash коммита и URL run в Actions: помнят «долго», но не то, что archive занял 11 или 38 минут. Эти метаданные дешёвы и спасают post-mortem после Чанги.
| Поле | Записанное значение | Как снять |
|---|---|---|
| Git commit | 7f2a91c (main) | git rev-parse --short HEAD |
| GitHub Actions | Run #18472930156 · workflow ios-ship.yml | UI Actions → URL run |
| Xcode на builder | 16.2 (16C5032a) · SDK iphoneos18.2 | xcodebuild -version + заголовок лога |
| Xcode на ноутбуке | 16.2 (сверено с builder за T-48h) | то же, до вылета |
| Длительность archive | 11m 34s (облачный M4 24 ГБ) | разница времени до ** ARCHIVE SUCCEEDED ** |
| Тот же commit, clean build на Air локально | 38m 12s (после одной неудачи) | локальная база; объясняет offload |
| Обработка TestFlight | upload 4m 08s · ASC «Processing» ~22m | altool / API + письмо ASC |
| Egress builder | 203.0.xxx.xxx (хост Канада, без изменений) | curl -4 ifconfig.me на builder |
Build description signature: 7f2a91c7e3b2… ExecuteExternalTool …/Xcode.app/Contents/Developer/Toolchains/… ** CLEAN SUCCEEDED ** ** ARCHIVE SUCCEEDED ** [684.123 sec] ← ~11m 24s (с clean) note: Using codesigning identity: Apple Distribution: Acme *** (TEAMID)
Той ночью в Сингапуре запускал по SSH через раздачу с телефона; логи сборки и загрузки только на builder. Ультрабук хранил ссылку на run Actions и commit. Для self-hosted runner вставляйте run ID в описание PR — как в статье про самостоятельные macOS runner на облачном Mac.
Какой build node предполагает runbook? (выбрать до вылета)
Худшая неделя спорить «арендуем Mac на три дня?». Мы записали отклонённое и оставшееся — названия продуктов только в последней колонке, не вывод:
Для iOS с Fastlane, match и whitelist ASC API build node — актив compliance. Менять его на неделе выставки — change event, не «быстро попробуем».
| Вариант | Почему не на неделе поездки | Что всё равно нужно было |
|---|---|---|
| Xcode Cloud | Ключи match, свой Fastlane, фиксированный egress трудно полностью контролировать; непрозрачная диагностика | PR-checks ок; hotfix-подпись — свой node |
| AWS EC2 Mac | Минимум аренды 24h, квоты/регионы; egress часто плавает | Настоящий macOS; команды на AWS compliance |
| Общий / ротируемый Mac cloud | Остатки Keychain и Derived Data; риск перепутать сертификаты | Дёшево, только unsigned compile |
| Mac mini в офисе | Коллега выключил, обновления ОС, никто не меняет диск в 2 ночи | Полный контроль, но не 7×24 в поездке |
| Выделенный облачный Mac (наш выбор) | Нужно заранее включить, закрепить версию, whitelist IP | SSH + фиксированный egress + Keychain на одной машине; SG/Канада |
Днём SSH из APAC на M4 в Сингапуре (спеки на странице узла Сингапур), загрузка TestFlight по-прежнему из Канады — whitelist ASC API и приватные ключи match уже привязаны к egress Канады 203.0.xxx.xxx. Смена провайдера — в окне обслуживания; смена egress на неделе поездки — нет. Hashvps: при продлении IP не ротируется, bare-metal mini — как в одна машина — один IP. EC2 Mac или офисный mini с фиксированным IP и закреплённым Xcode — остальной runbook без изменений.
Разделить проблему: сеть и вычисления
Многие ищут «аренду Mac на месте» сразу после посадки. Если нужна только сборка iOS и XCTest, аренда облачного Mac не обязана быть в том же городе — SSH из Чанги ощущается как из Москвы. На месте решаете:
- Стабильный uplink: eSIM в роуминге или надёжная точка доступа для непрерывного SSH (обзор GSMA про eSIM; dual-SIM — данные и голос раздельно).
- Часовые пояса: стендапы и окна review с домашней командой — не влияют на время compile, но на момент push.
- Compliance egress: App Store Connect и корпоративные прокси смотрят egress build-машины, не IP номера отеля.
По compute: до вылета repo клонирован, сертификаты импортированы, пути Derived Data зафиксированы. После прилёта — git pull и скрипты; не ставьте Xcode в аэропорту, иначе сожжёте окно 72 ч на загрузку компонентов.
Цепочка зависимостей упорядочена: (1) машина с предсказуемым egress и single-writer подписью; (2) workflows и Fastlane под этот хост; (3) ноутбук как пульт; (4) качество отеля/роуминга — ограничение для (3), не для throughput compile. Пропустить (1) и надеяться на (3) — archive на MacBook Air в переговорке и вопрос «почему upload упал, хотя демо-IPA встала».
Хронология 72 часов (реальные метки времени)
T-48h · 11.11.2025 Москва: builder в Канаде прогнал archive + TestFlight в зелёный (commit 9e0b44f, run #18451002201). На обоих хостах xcodebuild -version 16.2. SSH public key в authorized_keys; ServerAliveInterval 60 в ~/.ssh/config ноутбука.
T-24h · 12.11.2025: роуминг включён; mosh build-ca 10 минут без обрыва. Приватный ключ match только в Канаде (см. хост загрузки TestFlight).
T+0 · 13.11.2025 19:10 SGT Чанги: первый сбой SSH на Wi‑Fi отеля (инцидент ①); hotspot, git pull + инкрементальный build за 4m 02s (не archive).
T+24h · 14.11.2025: встречи с клиентом днём; 20:15 SGT push 7f2a91c. 23:41 SGT archive → 00:03 SGT upload в ASC → 00:25 SGT TestFlight готов к тесту. Меня не было у клавиатуры; builder и Actions закончили сами.
T+48h–72h: демо на площадке с уже обработанной сборкой TestFlight, без live archive на Wi‑Fi выставки. Upload через App Store Connect API с builder; роуминг ноутбука не важен.
Между T+0 и T+24h хост в Сингапуре — интерактивный builder: низкий RTT, логи «как локальные» — каждая минута compile в ЦОД. Между T+24h и upload Канада — compliance gate: match readonly, export, API — ASC уже знал этот egress. Скучно — хорошо: никто не открывает Keychain на телефоне в полночь.
Узел Сингапур vs Канада в короткой поездке
Региональный разбор: гид по удалённому Mac в пяти регионах. В поездке — два правила:
| Измерение | Сингапур / ЦОД APAC редактируете на месте | Канада / ЦОД Северной Америки артефакты с NA egress |
|---|---|---|
| Ощущение SSH | Низкий RTT, логи идут с вами | 150–250 ms через океан; норм, compile удалённо |
| TestFlight / ASC | Работает, если egress в whitelist | У большинства match/API на NA IP |
| Подходит для | Внутренние беты, коллаб APAC, дневные итерации | Релиз в Store, нотаризация, deps с NA CDN |
| Мигрировать из-за перелёта? | Нет; несколько ролей хоста в repo | Нет; SG compile + Canada upload — норма |
Мы не переносили match, потому что человек оказался в Сингапуре: там собирали debug/internal; Канада продолжала upload. Миграция сертификатов — change event, на неделе поездки запрещена (то же разделение, что в медленная сборка Xcode на облачном Mac M4, география наоборот).
Чеклист связи: роуминг, Wi‑Fi отеля, SSH
В отелях часто режут UDP, рвут idle TCP через ~5 минут или сбрасывают SSH после ARP-странностей. Минимальный набор:
- Ноутбук + телефон: SSH через hotspot, видеозвонки через Wi‑Fi отеля.
ServerAliveInterval 60иServerAliveCountMax 3в~/.ssh/config.- Длинные задачи в
tmuxилиscreen; после обрыва —tmux attach. - Никогда
rsync DerivedDataпо нестабильному каналу — только Git.
Корпоративный VPN с полным туннелем: до поездки согласовать split — внутренние ресурсы через VPN, SSH к builder напрямую. Многие вешают Mac только в Tailscale. Mosh помогает при потерях; не заменяет firewall, убивающий UDP — держите обычный SSH запасным.
Инциденты дня 2 (с логами)
Все четыре ниже — 14.11.2025 в одном окне, по порядку, не гипотезы. Пути замаскированы.
① Wi‑Fi отеля: обрыв idle SSH
$ ssh build-sg 'cd ~/workspace/MyApp && git pull' client_loop: send disconnect: Broken pipe Connection to build-sg.xxx port 22: Broken pipe
Причина: NAT отеля оборвал idle TCP ~через 300 с. Исправление: hotspot + ServerAliveInterval 60; длинные задачи в tmux. Повтора не было.
② Archive упал: нет сертификата Distribution в Keychain
error: No signing certificate "iOS Distribution" found error: No profiles for 'com.acme.myapp' were found ** ARCHIVE FAILED **
Причина: коллега установил сертификаты через VNC login, но не импортировал Distribution в login keychain облака; ноутбук прошёл из‑за Automatic Signing в Xcode. Исправление: bundle exec fastlane match appstore --readonly в Канаде, проверить security find-identity -p codesigning -v на Apple Distribution, повторить archive (11m 34s выше).
③ Параллельные тесты: runtime Simulator vs патч Xcode
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
{ platform:iOS Simulator, OS:18.1, name:iPhone 16 }
Ineligible destinations: … missing matching iOS Simulator runtime
Причина: builder на Xcode 16.2 (runtime 18.2), workflow всё ещё OS:18.1. Исправление: destination в ios-ship.yml на 18.2, закоммитить .xcode-version — не проблема удаления Derived Data.
④ Derived Data «битый»: диск полон
error: unable to attach DB: error: accessing build database "/Users/builder/Cache/DerivedData/…/build.db": database or disk is full
Исправление: df -h показал 6,2 ГБ свободно на /; удалили старые .xcarchive и Derived Data ветки. При «cache corrupt» сначала уровень диска, потом rm -rf DerivedData.
Матрица режимов сбоя
| Симптом | Сцена | Причина cloud / remote | Действие |
|---|---|---|---|
| Обрыв SSH | Wi‑Fi отеля | NAT idle timeout | hotspot + ServerAlive + tmux/mosh |
| build OK, upload fail | ASC / корп. proxy | egress не в whitelist | фиксированный IP builder; не менять хост |
| локально OK / удалённо fail | archive / подпись | дрейф Keychain vs match | match readonly + find-identity |
| нет Simulator | ночные CI-тесты | SDK/runtime не залочены | .xcode-version + destination |
| build.db / cache | параллельные ветки | полный диск как corrupt | df -h → archives / DerivedData |
| подпись истекла | релиз в конце квартала | истёк Distribution | ротация за 14 дней; на неделе поездки только readonly match |
Минимальный удалённый цикл Xcode (команды)
Первая ночь на месте — доказать цикл 72 ч; параметры по TN2339; commit 7f2a91c:
ssh build-sg 'set -e
cd ~/workspace/MyApp
git fetch origin && git checkout 7f2a91c && git pull --ff-only
xcodebuild -scheme MyApp -configuration Release \
-derivedDataPath ~/Cache/DerivedData \
-destination "generic/platform=iOS" \
build 2>&1 | tee /tmp/build-7f2a91c.log'
Archive и upload — в Fastlane lanes; в Сингапуре только make ship COMMIT=7f2a91c, Actions Run #18472930156 как аудит. Builder также self-hosted runner.
Спеки и диск: не урезать на неделе поездки
| Уровень | Память | Диск | Рекомендация |
|---|---|---|---|
| 16 ГБ / 256 ГБ | параллельные тесты легко уходят в swap | может заполниться за неделю | только hotfix одного repo |
| 24 ГБ / 512 ГБ | большинству iOS repo хватает | еженедельная чистка archives | дефолт для поездок |
| 24 ГБ / 1 ТБ | комфортный запас | кэш нескольких веток OK | monorepo + много симуляторов |
Уменьшить диск в неделю вылета — путь к инциденту ④: archives и runtime Simulator съедают десятки ГБ быстрее интуиции. Финансам лучше урезать параллельные тесты, чем диск на хосте подписи.
Что ещё положить в чемодан
Сознательно легче: без MacBook Pro 16", с ноутбуком с Terminal, тестовым Lightning/USB-C, запасными зарядками, бумажной или офлайн PDF-копией QR активированной eSIM в роуминге. Аккаунты builder, API keys, пароли match — в командном 1Password, но в офлайн-аварийке — IP builder, порт SSH, телефон дежурного — чтобы «роуминг мёртв + SMS 2FA не пришла» не заблокировали вдвойне.
Демо клиенту — TestFlight или Ad Hoc уже на устройстве, не live archive на Wi‑Fi выставки. Демо и релиз — разные пути: демо через потребительскую сеть, релиз через фиксированный egress builder — иначе «демо встало, значит upload должен пройти».
Физические тестовые устройства нужны для Bluetooth/NFC, которым не доверяете Simulator. Облачный Mac заменяет throughput compile/sign, не лабораторию девайсов.
Скрытая стоимость недели (для того, кто утверждает бюджет)
Купить или отправить Mac mini, или арендовать на месте: таможня, адаптеры, переустановка ОС, импорт сертификатов, новое доверие отпечатку устройства. Выделенный build node с понедельной оплатой покупает готовую среду — Derived Data, match, фиксированный IP не пересобирают в неделю поездки. Тот же TCO-рамка, что недорогой Mac-офис для стартапа: CapEx → OpEx без сертификатов на личных ноутбуках.
Упущенная выгода чувствуется руководством: час compile в отеле — час меньше с клиентом. Push в коридоре, логи в номере. При трёх–четырёх перелётах в ЮВА в год предсказуемый builder надёжнее «купить Mac в аэропорту».
Последняя практическая заметка из Чанги: в тикете фиксируйте не только «build зелёный», но и какой node делал archive и какой заливал — если поменять роли в неделю командировки, ночью отлаживаете с половиной контекста. Run ID в описании PR дешевле страховки, чем лишний пакет роуминга.
FAQ
Нужен ли Mac с собой? Достаточно машины с Git и SSH (Windows — в наших статьях про облачный Mac). Тестовые девайсы — если обязателен device debug; compile остаётся в облаке.
Новый builder за три дня до вылета? Да — сертификаты и первый полный compile до полёта; на месте только инкремент.
ЦОД Сингапура должен совпадать с городом? Нет. Co-location снижает RTT SSH; релиз в североамериканский Store — builder в Канаде.
Хватит ли роуминга для IPA? Не должно понадобиться. IPA с builder в ASC; ноутбук передаёт только мелкие Git-объекты.
Чем отличается от статьи про медленную сборку? Та — про перегрев ноутбука; эта — про географический сдвиг и нестабильные сети с runbook и размещением узлов.
Переносить gateway OpenClaw / agent? Нет. Может остаться в Канаде; Сингапур — только SSH-триггер сборок.
Корпоративный VPN 24/7? По политике. Полный туннель ломает SSH → split или Tailscale только к builder.
Часовые пояса и окна релиза? Сингапур UTC+8, запад США ~15–16 ч разницы. Archive днём в Сингапуре, upload ночью в Канаде — совместимо с ночными североамериканскими batch «следом за солнцем»; не нужно смотреть upload в 3 ночи.
Проверить ваш commit / run ID? Цифры из внутреннего repo, домены/IP скрыты; копируйте формат полей в тикеты, не наши числа.
Зачем два дата-центра? Латентность для ежедневной работы vs compliance upload — одна машина покрывает оба, если ASC и match уже на одном IP; мы сознательно разделили.