Три способа деплоя, которые я пробовал

Прошёл классический путь: от «scp и молитвы» до «push в main и забыть». Расскажу, чем каждый способ хорош и где болит.

Вариант 1. Ручной: копирование кода на хост

Так я начинал, и это нормально для самого первого запуска.

# на локальной машине
rsync -avz --exclude node_modules ./dist/ deploy@server:/var/www/site/
ssh deploy@server
cd /var/www/site && docker compose up -d

Плюсы: ничего не надо настраивать. Минусы, которые проявились быстро: копирую не то / забыл исключить / на хосте остались файлы от прошлой версии, и никакого отката. Для статики сойдёт, для чего-то живого — нет.

Вариант 2. Ручной с пулом образов

Следующий этап: код собирается в образ локально или в CI, я на хосте только пуляю.

docker login registry.example.com
docker compose pull
docker compose up -d
docker image prune -f

Плюсы: хост получает всегда собранную и проверенную в CI версию, конфиги и секреты живут рядом на хосте. Минусы: ручной труд остаётся, а значит — забытый docker compose pull и «а почему на сайте старая версия?». Между прочим, именно этот способ я до сих пор использую для ручных действий в промежутках между релизами.

Вариант 3. Автоматический через GitLab CI

Теперь так живут все мои проекты: push в main → линт, тесты, сборка, деплой.

Общая схема, которую я применяю:

stages: [QualityOfCode, Test, Build, Deploy]

Build:build:
  script:
    - pnpm run build                 # или docker build + push в registry

Deploy:site:
  stage: Deploy
  script:
    # релизный каталог + symlink current — откат за секунды
    - rsync -a dist/ "$DEPLOY_DIR/releases/$CI_COMMIT_SHORT_SHA/"
    - ln -sfn "$DEPLOY_DIR/releases/$CI_COMMIT_SHORT_SHA" "$DEPLOY_DIR/current"
    - docker compose up -d
    - curl -fsS https://example.com | grep -q "ок"   # smoke-тест обязателен

Для деплоя есть два подхода, оба использую:

Главные уроки автоматического пути:

  1. Smoke-тест после деплоя — не украшение. Он дважды возвращал меня к рабочей версии вместо битой.
  2. Релизы — каталоги + symlink current. Откат = перекинуть ссылку.
  3. Секреты — на хосте (shared/.env), не в переменных GitLab, если раннеры групповые.

Ручные варианты никуда не делись: ручной пул образов — запасной выход, когда CI лежит, а фиксить надо сейчас.