Перенос стека с Traffic Fly
Пошагово: как перенести compose-стек с одного хоста на другой так, чтобы пользователи продолжали заходить по тому же адресу, — на примере Forgejo (git-сервер с PostgreSQL), веб и git по SSH которого идут через Traffic Fly.
Почему через Traffic Fly: A-запись git.example.com указывает не на хост, а на VPS-шлюз. При переносе хаб просто переключает цель маршрута на новый хост — DNS, сертификаты и настройки клиентов не меняются.
Простой есть
Стек на старом хосте останавливается на время копирования данных — пока они едут, сервис недоступен. Traffic Fly не убирает этот простой, а избавляет от смены DNS и сертификатов после. Переносите в тихое время; сколько данных поедет, окно плана покажет заранее.
0. Что нужно заранее
Хаб с «Картой хостов». Карта — экспериментальная функция: «О системе» → «Экспериментальные функции» → «Изменить» → «Карта хостов».
Два хоста в хабе, оба на связи, nkt на обоих — 1.13.62 или новее (на Ubuntu 26.04 старее — туннель Traffic Fly не поднимется, см. nkt-edge). На новом хосте установлен Docker. Отдельно настраивать туннель на новом хосте не нужно — хаб поднимет его сам, когда добавит туда цель маршрута.
Шлюз Traffic Fly — VPS с nkt-edge в роли fly, «Шлюзы» на странице Traffic Fly.
Forgejo, выложенный через Traffic Fly. Если Forgejo ещё нет — «Выкладки» → «Новый конвейер» → текст
examples/forgejo/pipeline.fly.yaml: вместо прокси на хосте в нём два маршрута:yamlfly: - route: forgejo-web # веб: https://git.example.com kind: https names: [git.example.com] tls: gateway # сертификат выпускает и продлевает шлюз service: forgejo target_port: 3000 check: http check_path: /api/healthz - route: forgejo-ssh # git по SSH: ssh://git@git.example.com:2222/… kind: tcp port: 2222 service: forgejo target_port: 2222A-запись
git.example.com— на адрес шлюза. Поправьте имя, хост (hosts: [web1]) и почту администратора, «Сохранить» → «Выложить». Forgejo уже выложен по обычному примеру (site:и SSH на 2222 у хоста)? — замените в его описанииsite:и строкуports:блокомfly:выше, выложите и перенесите A-запись на шлюз.Хост в конвейере — по имени (
hosts: [web1]), не группой: иначе перенос не сможет переключить конвейер, и следующая выкладка подняла бы стек на старом хосте снова.
Проверьте до переноса: https://git.example.com открывается, в Traffic Fly у обоих маршрутов цель на старом хосте — рабочая и живая.
1. Начать перенос
- «Хосты» → переключатель «Карта» справа.
- Кнопка «Перенос» над картой — режим перетаскивания плиток.
- Перетащите плитку
forgejo-forgejo-1на блок нового хоста. Весь стек (forgejoиdb) обведён общей рамкой и переносится целиком.
Переключатель «Применять сразу» рядом с «Перенос»: выключен — перенос сначала копится планом и запускается кнопкой «Применить переносы (N)»; включён — запускается прямо из окна плана (а если препятствий и предупреждений нет — даже без окна).
2. Окно плана

Что проверить:
- Стек целиком — оба контейнера.
- Данные — тома
forgejo-data(репозитории, вложения, ключ SSH-сервера) иdb-data(база) с размерами: столько поедет, столько будет простой. - Образы — «уже есть» у тех, что на новом хосте уже скачаны; остальные поедут вместе с данными.
- Препятствия (красным) — места не хватает, порт занят, нет внешней сети; пока они есть, перенести нельзя.
- Цель маршрутов Traffic Fly — оба маршрута,
рабочая. Галочка «Переключить маршруты на новый хост» — включена: рабочая цель станет рабочей на новом хосте. - Стек выложен конвейером forgejo — галочка «Переключить конвейер на новый хост» включена: хост в описании конвейера и учёт выкладки переедут вместе со стеком.
«Добавить в план» → «Применить переносы (1)» (или «Перенести» при «Применять сразу»). Откроется журнал задания.
3. Перенос
Задание идёт шагами, карта показывает их вживую:
План — ещё раз проверка обоих хостов.
Упаковка — стек на старом хосте останавливается (с этого момента сервис недоступен), тома и образы упаковываются.
Передача — данные идут через хаб на новый хост. На карте — призрак плитки на новом хосте и бегущие к нему точки с процентом.

Распаковка — тома и образы на новом хосте, стек запускается.
Traffic Fly — в оба маршрута добавляется цель на новом хосте резервом; хаб ждёт до 90 секунд, пока шлюз увидит её живой, затем обмен: новая — рабочая, старая — резерв. На карте к новой плитке прорисовывается линия маршрута, пока шлюз проверяет — бегущий пунктир, потом точки трафика переходят на новую линию.

Конвейер — хост в описании (новой версией с примечанием «перенос стека») и учёт выкладки — на новый хост.
Готово — запись переноса: старый стек остался остановленным на старом хосте для отката.
Ошибка на любом шаге после остановки — задание откатывается само: на новом хосте распакованное убирается, на старом стек запускается снова.
4. Проверить

- Карта: Forgejo работает на новом хосте («← с web-1»), на старом — серые плитки «→ web-2 · остановлен»; у маршрутов на старой плитке — пустые кружки (резерв).
- Traffic Fly: у
forgejo-webиforgejo-sshрабочая цель — на новом хосте и живая, старая — резерв. - Сам Forgejo: откройте
https://git.example.com, войдите, откройте репозиторий и задачи — данные на месте. - git:
git clone https://git.example.com/<владелец>/<репо>.gitиgit clone ssh://git@git.example.com:2222/<владелец>/<репо>.git. Ключ SSH-сервера лежит в томе Forgejo и переехал вместе с ним — клиенты не увидят предупреждения о смене ключа. - Конвейер forgejo в «Выкладках»: в описании — новый хост.
5. Если что-то не так
- «Откатить» — щелчок по серой плитке на старом хосте: стек на новом хосте останавливается, на старом запускается, маршруты (рабочая — снова старая) и конвейер возвращаются. Данные — те, что были на старом хосте на момент переноса: изменения, сделанные после переноса на новом, при откате не переезжают обратно.
- Новый хост не отвечает (выключен, сеть) — в том же меню «Откатить без нового хоста»: стек снова работает на старом, маршруты и конвейер возвращены. На новом хосте может остаться работающая вторая копия — когда хост вернётся, карта пометит её «вторая копия», щелчок — «Остановить вторую копию».
- «Не ожила за 90 с» в журнале — шлюз не увидел новую цель живой, но обмен всё равно сделан (старая уже остановлена). Причины — в Traffic Fly под шлюзом и у маршрута: туннель нового хоста не поднялся (журнал «Применить»), Forgejo ещё стартует (проверка оживёт сама), неверный порт.
- Следующая выкладка конвейера сверяет цели маршрутов с хостом из описания и убирает старую резервную цель — после неё откат маршрутов уже не вернёт. Откатывайте до следующей выкладки.
6. Убрать старую копию
Когда всё проверено (день-два работы на новом хосте) — щелчок по серой плитке → «Убрать старый»: остановленные контейнеры уходят со старого хоста, старая цель — из маршрутов. Галочка «и данные» удаляет и тома на старом хосте; без неё они остаются — перенести стек обратно туда можно будет только с уборкой этих остатков (окно переноса предложит). Через неделю после переноса хаб напомнит о неубранной копии в «Оповещениях».
То же сценарием
Всё от выкладки до проверки после переноса — одним сценарием хаба «Forgejo за Traffic Fly: выкладка и перенос» (он же — examples/scripts/forgejo-fly.nkt, нужен хаб 1.13.67+).
Как запустить: «Профили» → вкладка «Сценарии» → «Новый сценарий», в окне редактора — «Готовые сценарии ▾» → «Forgejo за Traffic Fly: выкладка и перенос»; впишите имя → «Сохранить» → «Проверить» → «Сухой прогон» → «Выполнить» (параметры спросит при запуске, ход — в журнале задания). Готовые сценарии есть и на вкладке «Справка» страницы сценариев (кнопка «В редактор»).
При запуске спрашивает хост, где выложить, хост, куда перенести, и имя; «Сухой прогон» покажет сухой прогон конвейера, а план переноса — при запуске (до выкладки стека на хосте ещё нет).
# Forgejo за Traffic Fly: выкладка и перенос на другой хост
param FROM "хост, где Forgejo будет выложен сначала"
param TO "хост, куда его перенести"
param DOMAIN "имя Forgejo — A-запись на адрес шлюза Traffic Fly"
# Веб и git по SSH — через шлюз; сертификат выпускает шлюз
pipeline forgejo
repo: https://github.com/piqab/nkt.git
ref: main
action: compose
compose:
file: examples/forgejo/deploy/docker-compose.yml
project: forgejo
hosts: [${FROM}]
wait_timeout: 5m
env_keys:
forgejo-admin: [FORGEJO_ADMIN_USER, FORGEJO_ADMIN_PASSWORD, FORGEJO_ADMIN_EMAIL]
env:
POSTGRES_PASSWORD: generate:password
FORGEJO_DOMAIN: ${DOMAIN}
FORGEJO_ROOT_URL: https://${DOMAIN}/
FORGEJO_ADMIN_USER: gitadmin
FORGEJO_ADMIN_PASSWORD: generate:password
FORGEJO_ADMIN_EMAIL: admin@example.com
fly:
- route: forgejo-web
kind: https
names: [${DOMAIN}]
tls: gateway
service: forgejo
target_port: 3000
check: http
check_path: /api/healthz
- route: forgejo-ssh
kind: tcp
port: 2222
service: forgejo
target_port: 2222
end
deploy forgejo 20m
# Проверка снаружи — через DNS и шлюз, как зайдёт пользователь
wait url https://${DOMAIN}/api/healthz 200 10m
# Перенос: маршруты Traffic Fly и конвейер переключаются на новый хост
migrate ${FROM} forgejo-forgejo-1 to ${TO} switch-fly switch-pipeline
wait url https://${DOMAIN}/api/healthz 200 5mpipeline forgejo … end— конвейер, как «Сохранить» в окне: пароли создаст хаб, значения уйдут в «Секреты».deploy forgejo 20m— выкладка с ожиданием; маршрутыforgejo-webиforgejo-sshсоздаёт сам конвейер (блокfly:).wait url …— проверка снаружи, с хаба по настоящему имени: DNS, шлюз и сертификат — как у пользователя.migrate … switch-fly switch-pipeline— перенос, как с карты: при препятствиях сценарий остановится до остановки стека, упавший перенос откатится сам.
Сценарий — разовый: повторный запуск снова сохранит конвейер с хостом FROM и следующая выкладка вернула бы стек туда. Откат и уборку старой копии делайте с карты (шаги 5 и 6).
По API и из n8n
Перенос запускается и без карты: API-токеном администратора — план POST /api/hub/migrate/preview, перенос POST /api/hub/migrate (switch_fly, switch_pipeline), откат и уборка — POST /api/hub/migrations/{id}/rollback|remove; в n8n — Migration → Preview / Move Stack. Подробно — API хаба.
См. также
- Карта хостов — перенос подробно: что переносится, препятствия, общие сети.
- Traffic Fly — маршруты, цели, шлюзы.
- Выкладки — блок
fly:в конвейере.