nodbox
Разделы документации

Версии и откат

История выкладок, причины отказа, отмена идущего деплоя и возврат на одну из последних выкаченных версий.

Каждый деплой заводит в приложении новую версию, а все версии собраны в историю на вкладке «Версии». Работающая версия отвечает, пока собирается новая, а откат возвращает прежнюю за секунды: с тем же образом, переменными и размером, с которыми она работала.

Версия хранит код, переменные и размер

Версия - результат одного деплоя. Она запоминает образ с собранным кодом, переменные и секреты, размер, порт, проверку готовности, сон и масштаб на момент заказа.

Версия не меняется. Правка переменных или размера работающую версию не трогает и доезжает со следующим деплоем. Пересборка после ошибки и смена размера тоже создают новую версию, а не повторяют старую.

У версии есть номер внутри приложения: v1, v2 и так дальше. Номер не переиспользуется, и версия, которая не доехала, свой номер тоже занимает.

История показывает путь каждого деплоя

В панели история лежит на вкладке «Версии» страницы приложения, версии идут от новых к старым. В API её отдаёт GET /api/v1/applications/{id}/revisions, одну версию - GET /api/v1/revisions/{id}. Обоим запросам хватает права токена «читать».

Строка истории в панели состоит из таких частей:

  • номер версии и статус
  • доля трафика, только у версии, которая отвечает сейчас
  • сообщение коммита и короткий хеш, а у архива и образа - откуда взята версия
  • автор и время заказа
  • время деплоя, у идущей версии оно считается вживую
  • кнопка «Сборка», она открывает Лог сборки этой версии

В ответе API у версии такие поля:

Поле Что отдаёт
number номер версии внутри приложения
status provisioning, active, superseded или error
phase шаг деплоя, на котором версия сейчас или на котором остановилась
failure_reason причина отказа, у версии без отказа пусто
origin откуда взят код: git, zip или image
url адрес выкаченной версии, до выката пусто
commit ветка или тег, хеш, сообщение и автор коммита
traffic_percent доля трафика: 100 у версии, которая отвечает, 0 у остальных
duration_seconds сколько шёл деплой, у идущего пусто
operation операция деплоя: done, status, failure_reason и message

Статус версии складывается из двух полей

Статус называет итог деплоя, фаза - шаг, на котором версия сейчас или на котором остановилась. В панели они сливаются в одно слово:

В панели status и phase Что значит
В очереди provisioning, queued версия заказана, работа не началась
Код загружается provisioning, fetching платформа клонирует репозиторий или распаковывает архив
Код получен provisioning, fetched исходники получены, сборка впереди
Образ собирается provisioning, building идёт сборка
Образ публикуется provisioning, pushing собранный образ сохраняется на платформе
Образ собран provisioning, built образ готов, запуск впереди
Деплоится provisioning, deploying приложение запускается
Работает active, deployed версия запущена и отвечает на запросы
Отработала superseded версия работала, потом её заменила следующая или остановка
Ошибка error версия не доехала или деплой отменён

«Работает» значит ровно одно: status = active и phase = deployed. Версия остаётся на deployed, и когда приложение уснуло: сон версию не отменяет.

Фаза замирает там, где деплой оборвался. Статус error вместе с фазой building читается как «упало на сборке». Состояние самого приложения платформа считает отдельно, его слова разобраны в разделе Состояния приложения.

Версию можно заказать вручную

Новая версия заказывается из панели или по API. У приложения из репозитория она заводится ещё и сама, по push в выбранную ветку: Автодеплой по push.

В панели:

  • «Задеплоить снова» на странице приложения, рядом с состоянием
  • «Задеплоить» на вкладке «Версии»
  • «Загрузить новый архив» или «Новый архив» у приложения из архива: каждой версии нужна своя загрузка

По API это POST /api/v1/applications/{id}/revisions с правом токена «деплоить». Тело зависит от источника кода:

Источник Тело запроса
Репозиторий необязательное ref: ветка или тег, без него деплоится ветка приложения
Архив обязательное upload_id новой загрузки
Образ пустое

Деплоится последний коммит ветки или тега, конкретный коммит выбрать нельзя. Заголовок Idempotency-Key обязателен: повтор запроса по таймауту тогда не заведёт вторую версию. Ответ - 202 с операцией. Опрашивай GET /api/v1/operations/{id}, пока done не станет true: у операции деплоя action равен deploy_revision.

Платформа откажет в заказе в таких случаях:

  • версия дороже работающей, а денег на балансе не хватает на неделю разницы, у первой версии разница равна всей цене
  • проект заблокирован за долг
  • почта аккаунта не подтверждена
  • подключение к git-аккаунту отозвано или удалено
  • приложение останавливается или удаляется, ответ 409

Работающая версия отвечает, пока собирается новая

Пока новая версия собирается и запускается, прежняя продолжает отвечать на запросы, а приложение остаётся в состоянии «Работает». Весь трафик переезжает на новую версию, когда она запустилась. Прежняя при этом получает статус «Отработала»: работает всегда ровно одна версия.

Сорвавшийся деплой работающую версию не трогает. Сборка не прошла, приложение не запустилось, деплой отменён или не уложился в срок: прежняя версия отвечает как отвечала. Если работающей версии ещё не было, как при первом деплое, приложение остаётся в состоянии «Ошибка».

Сборка идёт до 16 минут, весь деплой - до 48. Что не уложилось, платформа останавливает с причиной timed_out.

Новый заказ отменяет предыдущий деплой, если тот ещё идёт. Это касается и деплоя по push: два быстрых push подряд оставят в работе последний, а у первого будет причина canceled. Повторно нажимать «Отменить деплой» перед новым заказом не нужно.

Идущий деплой можно отменить

В панели пока идёт деплой, рядом с состоянием приложения стоит кнопка «Отменить деплой». По API это POST /api/v1/revisions/{id}/cancel с правом токена «деплоить».

Ответ - 202 с операцией самого деплоя, своей операции у отмены нет. Опрашивай её, пока done не станет true.

Отменённая версия получает такой вид:

  • status равен error, а phase остаётся на шаге, где деплой оборвался
  • причина canceled лежит на операции, у самой версии failure_reason пуст
  • в панели строка стоит со статусом «Ошибка» и пояснением «Операция отменена по запросу»

Отдельного статуса «Отменён» у версии нет: отменённый деплой не работает так же, как упавший. Повторить отменённую версию нельзя, закажи новую. У приложения из архива для неё нужна и новая загрузка.

Отмена - просьба, а не гарантия. Деплой, который успел доехать, пока просьба была в пути, завершится своим итогом. Пока идёт сборка, отмена занимает до минуты. У версии без идущего деплоя отмена отвечает 409: отменять нечего.

Работающая версия продолжает отвечать. За отменённую версию платить не нужно, а письма о провале деплоя она не вызывает: отменил ты сам.

Причина отказа называет, что случилось

Когда версия не доехала, панель показывает сообщение «Версия vN не доехала», причину словами и кнопку, которая открывает лог сборки или лог приложения. По API причина лежит в failure_reason у версии и у операции, а текст - в message операции. Значение причины стабильно, текст платформа может поправить.

У провала после сборки failure_reason версии может быть пуст, а причина лежит только на операции. Поэтому читай обе.

Код не дошёл до сборки

Причина Что случилось Что делать
source_unavailable платформа не добралась до исходников: подключение отозвано, репозиторий или ветка не найдены, загруженный архив пропал проверь подключение и ветку в настройках приложения, а у архива загрузи его заново
archive_invalid архив не разбирается собери его заново обычным «сжать в zip»
archive_encrypted архив защищён паролем упакуй без пароля
compression_unsupported архив сжат методом, который платформа не разбирает упакуй обычным zip
limit_exceeded исходников слишком много: объём, число файлов или время получения кода вышли за потолок убери из проекта лишнее

Что именно проверяет платформа в архиве и какие у неё потолки, разобрано в разделе Источники кода.

Сборка не прошла

Причина Что случилось Что делать
language_not_detected платформа не нашла в проекте знакомых файлов сборки положи файл зависимостей в корень, задай корневую папку или добавь Dockerfile: Настройки сборки и свой Dockerfile
dockerfile_missing выбран сборщик dockerfile, а Dockerfile в корне сборки нет положи файл или верни автоматический выбор сборщика
root_directory_missing корневой папки сборки нет в исходниках поправь root_directory в настройках приложения
build_failed сборка дошла до работы и не собралась прочитай Лог сборки, проверь, что проект собирается у тебя локально, и закажи версию с исправлением
build_timeout сборка не уложилась в 16 минут и остановлена сократи сборку или убери из неё лишние шаги
image_too_large собранный образ больше допустимого размера убери из образа лишнее

Приложение не запустилось

Эти причины приходят после того, как образ собран и отправлен на запуск. Причину тут ищи в логе приложения, а не в логе сборки.

Причина Что случилось Что делать
container_exited процесс приложения раз за разом завершается с ошибкой, в сообщении стоит код выхода прочитай Логи приложения: там последние слова процесса
out_of_memory приложению не хватило памяти, и процесс остановлен возьми размер побольше: Размеры приложения
port_unreachable процесс запустился и не отвечает на порту, в сообщении стоит номер порта проверь, на каком порту слушает приложение, и сверь с настройкой: Порт, протокол и проверка готовности

Падающий процесс платформа распознаёт на третьем перезапуске, примерно через 70 секунд после запуска, не дожидаясь пяти минут. Молчащий порт отличим от медленного старта только по сроку, поэтому такой приговор приходит позже, около пяти минут. Приложение, которое падает раз-другой и потом поднимается, до конца деплоя доезжает.

Сбои деплоя без своей причины на версии

Эти причины лежат только на операции деплоя.

Причина Что случилось Что делать
revision_not_ready приложение не запустилось, а точнее платформа не определила: например, образ не скачался. Упавший процесс и молчащий порт получают свои причины выше загляни в логи и закажи версию с исправлением
api_server_rejected платформа отклонила запрос, и повтор не поможет напиши в поддержку
timed_out деплой не уложился в 48 минут и остановлен закажи версию ещё раз
canceled деплой отменили закажи новую версию

Сбой на стороне платформы

Две причины говорят, что дело не в твоём коде.

Причина Что случилось Что делать
push_failed образ собрался, но не сохранился закажи версию ещё раз
internal сбой на нашей стороне, твой код тут ни при чём закажи версию ещё раз, а если сбой повторяется, напиши в поддержку

О провале деплоя платформа пишет письмом, и проект сам решает, приходит ли оно. Подробности - в разделе Уведомления.

Откат возвращает то, что работало

Откат переставляет трафик на одну из прежних версий и не создаёт новой. Возвращается ровно то, что работало: тот же образ, те же переменные и тот же размер. Сегодняшние настройки приложения откат не подхватывает, их снимет следующий деплой. Занимает это секунды, потому что собирать нечего.

В панели:

  1. Открой вкладку «Версии».
  2. Нажми «Откатить» в строке нужной версии.
  3. Подтверди в окне «Откатиться на vN?».

Кнопка стоит не у каждой строки. Её нет у версии, которая уже отвечает, и у версии, которая ни разу не доезжала до запуска. Пока приложение не работает, кнопки нет совсем, а пока идёт другая работа, она недоступна. Агент откатывает фразой «верни предыдущую версию»: Фразы для агента.

По API это POST /api/v1/applications/{id}/rollback с правом токена «деплоить» и телом {"revision_id": "rev_..."}. Ответ - 202 с операцией приложения, не версии: у неё action равен rollback_application. Опрашивай её, пока done не станет true. Ключ Idempotency-Key не нужен.

После отката:

  • выбранная версия снова получает status = active и 100% трафика
  • прежняя работавшая версия получает superseded и 0% трафика
  • число версий в истории не меняется
  • откат попадает в Ленту событий

Следующий деплой снимает закрепление: он создаёт новую версию, и трафик уходит на неё. Новая версия берёт код ветки и сегодняшние настройки приложения, а не версию, на которую ты откатился. Если сломанный коммит остался в ветке, он поедет снова. Исправь код или верни коммит, прежде чем деплоить или пушить.

Когда откат отказывает

Запрос на откат отвечает 409 в трёх случаях, которые различает текст:

Ответ Что случилось
«Приложение не работает: откатывать нечего. Сначала запусти его.» приложение остановлено или первый деплой не удался
«Эта версия ни разу не работала - откатиться на неё нельзя.» версия не доезжала до запуска
«Эта версия уже обслуживает приложение.» откатываться некуда: нужная версия уже работает

Четвёртый случай - идущий деплой: откат отвечает 409 и просит дождаться деплоя или отменить его. Версия чужого приложения даёт 422.

Откат на версию с размером крупнее работающей проверяет квоту проекта на процессор и память и баланс: нужны деньги на неделю разницы в цене. Квота отвечает 403, деньги - 402. Откат на размер поменьше этих проверок не встречает. Проект, заблокированный за долг, откатиться может, хотя новую версию не закажет.

Если версии уже нет на платформе, запрос принимается, а операция заканчивается ошибкой revision_gone: «Версии, на которую идёт откат, на платформе больше нет». Работающая версия при этом остаётся как была. Выбери версию поновее или задеплой заново.

Платформа хранит три последние выкаченные версии

Платформа держит три последние версии, которые доезжали до запуска. Работающая входит в эти три, поэтому в обычном случае откатиться можно на две предыдущие. Версии, которые не доехали, в счёт не идут.

Всё, что старше этих трёх, платформа убирает раз в час. С версии уходят исходники, собранный образ и запись в истории. Пока в приложении меньше трёх выкаченных версий, убирать нечего. Запись о вышедшей из окна версии может пробыть в истории до следующего прохода уборки, и откат на неё уже отвечает revision_gone.

Уборка не трогает работающую версию, даже если она старше окна. Так бывает после отката: работает версия v3, а свежие v4 и v5 лежат рядом. Образ платформа удаляет, только если на него не ссылается ни одна оставшаяся версия.

Остановка приложения уносит с собой и прежние версии: после запуска откатиться на версии, выкаченные до остановки, нельзя, откат ответит revision_gone.

Запуск после остановки берёт образ прежней версии

Запуск остановленного приложения заводит новую версию. Сборки нет: версия берёт образ последней версии, которая доезжала до запуска. Настройки она берёт сегодняшние, из приложения, а не из той версии. В этом запуск отличается от отката, который возвращает прежние настройки. Подробности - в разделе Остановка и удаление.

Деньги идут за работающую версию

Платить за приложение начинают с подтверждённого запуска. Версия, которая собирается, упала или отменена, ничего не стоит.

Цена берётся с размера работающей версии. После отката платишь по размеру той версии, на которую вернулся. Как списываются деньги, разобрано в разделе Тарификация.

Что дальше


Страница в markdown, так её читает агент: /docs/deploy/versions.md