Три способа деплоя, которые я пробовал
Прошёл классический путь: от «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-тест обязателен
Для деплоя есть два подхода, оба использую:
- SSH-доставка — job подключается к хосту по ключу (
before_scriptс ssh-agent). Просто, но надо следить за ключами. - DooD (Docker outside of Docker) — раннер запущен на том же хосте, что и прод, и управляет хостовым докером через смонтированный сокет. Без SSH вообще, это то, как сейчас работает kovss.com.
Главные уроки автоматического пути:
- Smoke-тест после деплоя — не украшение. Он дважды возвращал меня к рабочей версии вместо битой.
- Релизы — каталоги + symlink
current. Откат = перекинуть ссылку. - Секреты — на хосте (
shared/.env), не в переменных GitLab, если раннеры групповые.
Ручные варианты никуда не делись: ручной пул образов — запасной выход, когда CI лежит, а фиксить надо сейчас.