Сайт ↗
Разделы документации
Эксплуатация · 0.8.1

Восстановление после прерванного развёртывания

Что делать после ошибки deploy: посмотреть состояние, продолжить операцию или закрыть её. Отдельно — неудачный первый запуск и reconfigure.

На этой странице

После ошибки deploy или обрыва соединения сначала узнайте, что успело выполниться. Повторный запуск новой операции не заменяет восстановление старой.

Работайте из корня проекта: Source — на VPS под пользователем deploy, Archive/Registry — на управляющем компьютере, prod-local — на своём компьютере.

1. Найдите ID и этап операции

bash ./deploy/control status --env local --json
bash ./deploy/control reconcile --env local --json
bash ./deploy/control logs --env local --service backend

Для сервера замените local на имя окружения. reservation означает, что операция удерживает окружение; current — последний успешный релиз. Контейнер может работать и при current: null, например после неудачного первого запуска.

2. Выберите продолжение или закрытие

Resume подходит, если причина устранена и нужен тот же релиз:

bash ./deploy/control resume --env local \
  --operation OPERATION_ID --confirm local

Resume поддерживает provision, deploy, backup, down, certificates, rollback и restore. Reconcile только показывает состояние и не снимает блокировку. Завершённые этапы пропускаются. Неопределённый результат миграции проверяется по БД; некоторые побочные действия требуют ручного разбора. Другой образ через resume подставить нельзя, параметра --release у него нет.

Abandon закрывает выбранную операцию без успеха:

bash ./deploy/control abandon --env local \
  --operation OPERATION_ID --confirm local

Данные и история остаются. Команда не отменяет миграции, не возвращает прежний код и не открывает доступ автоматически. Закрытую операцию нельзя возобновить. Не удаляйте reservation и не меняйте её JSON вручную.

Provision прервался при выпуске HTTPS-сертификата

Откройте путь к certbot.log из сообщения ошибки. Исправьте указанную причину: DNS, доступ к HTTP-проверке либо права на её файлы. Затем продолжите тот же provision через resume с его ID. Текущие инструменты сохраняют лог каждой попытки и повторно используют уже подготовленные секреты. Это поведение относится к актуальным generated-инструментам: git pull не заменяет сохранённый payload старого релиза; для такой операции может понадобиться отдельный разбор.

После успешного resume provision приложение ещё нужно выпустить:

bash ./deploy/control deploy --env production --release release-001.json --confirm production

Используйте тот JSON релиза, с которым начинали provision. Новая сборка для повторной проверки сертификата не нужна.

Если старые инструменты сообщают secrets.json: cannot overwrite existing file, не удаляйте секреты: обновите генераторные инструменты проекта. Это не сигнал пересоздавать БД.

Первая установка создала таблицы, но не записала релиз

Ошибка missing release record with an existing application schema is not first install означает: БД уже заполнена, а успешного первого релиза нет. Новый deploy не может считать её пустой. Универсального переключения такой установки на другой релиз сейчас нет.

Если данные нужны, сохраните БД и состояние, затем разберите происхождение схемы и миграции. Не создавайте current.json или фиктивные записи миграций. Для одноразового prod-local с ненужными данными подходит отдельная процедура ниже.

Пересоздать одноразовый prod-local

Этот вариант подходит только для локального окружения, которое вы согласны начать с пустой БД. Новая установка не будет содержать прежние записи, аккаунты и изображения; старый каталог мы переместим целиком в архив, а не удалим. Не выполняйте это для production, dev-local или окружения с ценными данными вместо согласованного восстановления.

Все команды ниже — из корня сгенерированного проекта. Имя окружения намеренно фиксировано: local, preset — prod-local. Для другого имени не копируйте команды без адаптации.

Сначала закройте известную активную операцию

Посмотрите status --env local --json. Только если там есть активная операция этого окружения, подставьте ее точный ID:

bash ./deploy/control abandon --env local \
  --operation OPERATION_ID_FROM_STATUS --confirm local

Если активной операции нет, этот шаг пропустите. Если abandon не завершился, остановитесь и разберите причину, не удаляйте reservation вручную.

Остановите только контейнеры local и сохраните каталог

Следующий фрагмент явно запускается в Bash; он не использует docker system prune, удаление volumes или rm данных:

bash <<'BASH'
set -euo pipefail
project_root=$(pwd -P)
env_file=$(mktemp)
trap 'rm -f "$env_file"' EXIT
bash deploy/generated/runtime/environment.sh "$project_root" local > "$env_file"
jq -e '.environment=="local" and .preset=="prod-local"' "$env_file" >/dev/null
state_root=$(jq -er .root "$env_file")
test "$state_root" = "$project_root/deploy/.state/local"
jq -e --arg root "$state_root" '
  .media.storage=="local" and .media.root==($root+"/data/media") and
  .backup.kind=="local" and .backup.root==($root+"/backups")
' "$env_file" >/dev/null
test -d "$state_root"
test ! -L "$state_root"
project_name=$(jq -er .project "$env_file")
compose_project="$project_name-local"
archive="$project_root/deploy/.state/local-archive-$(date -u +%Y%m%dT%H%M%SZ)-$$"
test ! -e "$archive"
container_ids=$(docker ps -aq --filter "label=com.docker.compose.project=$compose_project")
while IFS= read -r container_id; do
  test -n "$container_id" || continue
  docker stop "$container_id"
  docker rm "$container_id"
done <<< "$container_ids"
mv "$state_root" "$archive"
printf 'Старое окружение сохранено: %s\n' "$archive"
BASH

Команды выбирают контейнеры по Compose project, поэтому останавливают только этот prod-local. Контейнеры dev с другим именем Compose project продолжают работать.

В сохранённой папке остаются файлы остановленного PostgreSQL, изображения, ключи и история. Это копия каталога окружения, а не переносимый SQL-дамп. Чтобы вернуть прежний запуск, понадобятся его настройки и Docker-образы. Не удаляйте архив сразу после создания новой установки.

Создайте чистое окружение заново

Сначала убедитесь, что нужное исправление есть в исходниках и generated-файлах проекта. Затем:

bash ./deploy/control provision --env local
bash ./deploy/control check --env local
bash ./deploy/control up --env local
bash ./deploy/control status --env local --json

Команда provision заново создаст образы, ключи и сертификаты. Если вы добавляли локальную CA в доверенные сертификаты ОС, удалите старую и импортируйте новую: deploy/.state/local/pki/ui-ca.crt. Затем создайте первого суперадминистратора по инструкции prod-local.

Это сброс одноразового окружения с сохранением старых файлов в архиве, а не продолжение прежней операции. Для переноса нужных записей используйте отдельную процедуру данных после проверки новой установки.

Таймаут или потеря связи

После обрыва SSH используйте status/reconcile: сервер мог продолжить работу. Если ошибка возникла при build до создания операции, устраните сетевую причину и повторите сборку с новым output. При наличии reservation сначала разберите эту операцию.

Этап по умолчанию ждёт до 1800 секунд; DEPLOY_STAGE_TIMEOUT_SECONDS принимает 1–86400. Больше времени не исправит недоступный DNS/registry. Таймаут CI должен покрывать несколько этапов.

Прервалась смена секретов

Обычный resume не обслуживает rotate-secrets. Сохраните журналы и подготовленные файлы: часть секретов могла уже примениться. Не запускайте новую ротацию и не удаляйте старые ключи, пока не установлено, какой этап завершился. Потребуется разбор сохранённого состояния ротации.

Прервалась reconfigure

Сохраните тот же новый JSON и повторите reconfigure --env production --confirm production --operation ID; для перехода с Source оставьте --on-host. Обычный resume здесь не используется.

До публикации конфигурации abandon возможен; для проверки окружения сначала верните локальный JSON к прежней сохранённой конфигурации. После начала публикации нужен повтор reconfigure с тем же новым JSON и ID, а не abandon.