[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-recipes\u002Ffast-redeploy":3,"docs-tabs-recipes\u002Ffast-redeploy":6},{"content":4,"lastmod":5},"# Быстрый цикл редеплоя\n\n🚀 **Сложность:** medium | **Скоупы:** vibe:infra | **Стек:** cURL\n\nПолный редеплой через [`POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fdeploy`](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fdeploy) прогоняет девять шагов подряд: остановка сервиса, очистка, скачивание архива, установка рантайма, установка зависимостей, запись `.env`, команды `preStart`, создание systemd-юнита, запуск и проверка работоспособности. Спящий сервер деплой будит сам. Это правильный путь для первого выпуска и для смены рантайма, но на каждой мелкой правке кода прогонять все девять шагов долго. Ниже — четыре приёма, которые сокращают цикл: убрать раздувание тела запроса, не переустанавливать тяжёлые зависимости, обновлять один изменившийся файл вместо всего дерева, держать данные отдельно от кода.\n\nВо всех примерах `$VIBE_URL` — базовый адрес `https:\u002F\u002Fvibecode.bitrix24.tech`, `$SERVER_ID` — идентификатор BLACKHOLE-сервера, `$VIBE_API_KEY` — API-ключ Вайбкод со скоупом `vibe:infra`.\n\n### Multipart вместо base64\n\nВстроенный `source.content` — это base64-строка архива, а base64 увеличивает объём примерно на 33 %: архив 30 МБ уходит по проводу как 40 МБ. Multipart-режим передаёт архив файлом-как-есть, без этой надбавки. Второе отличие — `cleanDeploy` в multipart-режиме по умолчанию `\"false\"` (merge-деплой: новые файлы кладутся поверх существующего дерева), тогда как inline-деплой из JSON по умолчанию `cleanDeploy: true` и стирает `\u002Fopt\u002Fapp` перед распаковкой. Для итеративной правки merge-режим быстрее — не нужно каждый раз выкладывать полное дерево.\n\n```bash\ntar -czf app.tar.gz -C .\u002Fmy-app .\ncurl -sS -X POST \"$VIBE_URL\u002Fv1\u002Finfra\u002Fservers\u002F$SERVER_ID\u002Fdeploy\" \\\n  -H \"X-Api-Key: $VIBE_API_KEY\" \\\n  -F \"archive=@app.tar.gz\" \\\n  -F \"start=cd \u002Fopt\u002Fapp && node server.js\" \\\n  -F \"port=3000\"\n```\n\nПорт в multipart-режиме передавать обязательно — строкой (`\"3000\"`). Чтобы вместо merge сделать чистый деплой, добавьте `-F \"cleanDeploy=true\"`.\n\n### Тяжёлые зависимости — вне install-скрипта\n\nУ шага `install` таймаут 300 секунд, и запускается он на каждом деплое. Долгая установка набора инструментов сборки на этом шаге либо упирается в таймаут, либо отнимает минуты у каждого деплоя. Файловая система виртуальной машины помогает этого избежать: `cleanDeploy` стирает только `extractTo` (по умолчанию `\u002Fopt\u002Fapp`), а установленные рантаймы, каталог `\u002Fusr` и `\u002Fopt\u002Fdata` переживают редеплой. Поэтому системный инструмент ставится один раз и остаётся на месте.\n\nУстановите тяжёлый инструмент однажды и в дальнейшем проверяйте его наличие идемпотентной строкой — она запускает установочный скрипт, только если инструмента ещё нет:\n\n```bash\ncommand -v pg_restore >\u002Fdev\u002Fnull || bash \u002Fopt\u002Fdata\u002Finstall-tools.sh\n```\n\nСтроку помещают в `preStart`. При первом деплое `pg_restore` не найден — скрипт отработает. На следующих деплоях инструмент уже на месте, проверка проходит мгновенно, установка не повторяется. Так каждый деплой не платит за переустановку того, что уже стоит на диске.\n\n### Точечные обновления через \u002Fupload\n\nКогда изменился один файл или один бандл, полный редеплой избыточен. Загрузите изменившийся архив через [`POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fupload`](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fupload) с `extract: true` — агент распакует его прямо в рабочую директорию, минуя остальные восемь шагов деплоя. Затем перезапустите сервис через [`\u002Fexec`](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fexec):\n\n```bash\ncurl -sS -X POST \"$VIBE_URL\u002Fv1\u002Finfra\u002Fservers\u002F$SERVER_ID\u002Fupload\" \\\n  -H \"X-Api-Key: $VIBE_API_KEY\" -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"url\": \"https:\u002F\u002Fexample.com\u002Fdist.tar.gz\",\n    \"path\": \"\u002Fopt\u002Fapp\u002Fdist.tar.gz\",\n    \"extract\": true,\n    \"extractTo\": \"\u002Fopt\u002Fapp\"\n  }'\n\ncurl -sS -X POST \"$VIBE_URL\u002Fv1\u002Finfra\u002Fservers\u002F$SERVER_ID\u002Fexec\" \\\n  -H \"X-Api-Key: $VIBE_API_KEY\" -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"command\": \"systemctl restart app\"}'\n```\n\nИмя сервиса в команде перезапуска — то, под которым приложение задеплоено. По умолчанию это `app`, поэтому и `systemctl restart app`. Загрузка размером до 500 МБ — с ней проходит и целый бандл, и отдельный файл.\n\n### Данные — никогда в install-шаге\n\nШаг `install` (и `preStart`) выполняется на каждом деплое. Если положить в него загрузку данных — вставку строк в базу, импорт справочника, накат начальных данных — эта загрузка повторится при каждом деплое, и записи задвоятся. Данные грузят в `\u002Fopt\u002Fdata` один раз и под идемпотентной защитой, чтобы повторный запуск ничего не добавлял:\n\n```bash\ntest -f \u002Fopt\u002Fdata\u002F.seeded || { bash \u002Fopt\u002Fdata\u002Fload-seed.sh && touch \u002Fopt\u002Fdata\u002F.seeded; }\n```\n\nКаталог `\u002Fopt\u002Fdata` переживает редеплой, поэтому файл-маркер `.seeded` остаётся на месте между деплоями. Первый деплой загрузит данные и поставит маркер, все следующие увидят маркер и пропустят загрузку. Команды-шаги деплоя держите для установки кода и зависимостей, а разовую загрузку данных выносите под такую защиту.\n\n## Смотрите также\n\n- [Полный деплой приложения](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fdeploy)\n- [Загрузить файл](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fupload)\n- [Выполнить команду](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fexec)\n- [Длинные операции через exec](\u002Fdocs\u002Frecipes\u002Flong-operations)\n","2026-07-07",{}]