Как автоматизировать деплой проектов на белорусском VPS с помощью Git и systemd

ГлавнаяКак автоматизировать деплой проектов на белорусском VPS с помощью Git и systemd

Содержание

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

В статье рассказали, как организовать деплой проекта на белорусском VPS с помощью Git и systemd.

Подготовка сервера

Сначала подготовьте сам сервер, арендуйте VPS и настройте операционную систему. Для деплоя хорошо подходят дистрибутивы вроде Ubuntu или Debian, но можно взять CentOS или другой Linux. После доступа по SSH первым делом обновите систему и установите базовые инструменты. Введите в консоли:

sudo apt update && sudo apt install git nginx docker.io -y

Это установит Git для клонирования репозитория, Nginx для веб-сервера и отдачи статики и Docker, если нужны контейнеры. Если ваш проект написан на Python, установите необходимые пакеты:

sudo apt install python3-venv python3-pip

Если приложение на Node.js, поставьте Node и npm:

sudo apt install nodejs npm

Также может понадобиться СУБД, если вы используете базы данных:

sudo apt install postgresql

Проверьте, есть ли доступ по SSH. Сгенерируйте ключ ssh-keygen и добавьте публичный ключ в /home/deploy/.ssh/authorized_keys, чтобы вы могли пушить код без пароля. Создайте пользователя для деплоя командой sudo adduser deploy и назначьте ему нужные права. На всякий случай настройте файрвол, разрешите порты 22, 80 и 443 через ufw. Все эти базовые действия — обычная подготовка, и они экономят кучу времени в будущем.

Настройка Git-репозитория на сервере

Теперь займёмся репозиторием проекта. Есть два распространённых подхода: bare-репозиторий и pull-подход. В варианте bare-репо вы создаёте голый репозиторий на сервере и пушите туда. Выполните на сервере:

ssh deploy@server
git init --bare /home/deploy/project.git

В такой папке хранится только структура Git без рабочих файлов. Bare-репозиторий — это своего рода чистый контейнер. В нём хранятся только метаданные Git, без самих файлов проекта. Вы можете не опасаться перезаписать рабочую копию. Содержимое вашего приложения будет появляться в отдельной папке /home/deploy/app после выполнения хука. Потом в локальном проекте добавьте новый remote:

git remote add vps ssh://deploy@server/home/deploy/project.git
git push vps main

Так вы отправите изменения на VPS.

Чтобы код из bare-репо оказался в нужном месте, пишем хук. В каталоге /home/deploy/project.git/hooks создайте файл post-receive и сделайте его исполняемым (chmod +x post-receive):

#!/bin/bash
GIT_WORK_TREE=/home/deploy/app git checkout -f
systemctl restart myapp.service

Эта простая последовательность сначала распаковывает из репозитория актуальные файлы в папку /home/deploy/app, а затем перезапускает сервис приложения. Если репозиторий содержит несколько веток, можно деплоить только конкретную, например, main. Для этого в post-receive проверяют переменную ref. Например:

while read oldrev newrev ref; do
  if [[ "$ref" == "refs/heads/main" ]]; then
    GIT_WORK_TREE=/home/deploy/app git checkout -f main
    sudo systemctl restart myapp.service
  fi
done

В этом случае пуши в другие ветки будут игнорироваться, а на main деплой произойдёт автоматически. Если вам не нравится bare-репо, можно сразу клонировать проект в папку и обновлять командой git pull. Однако bare-подход часто удобнее, потому что всегда чистый и независимый. Схема работы почти не отличается от CI/CD-процессов: как говорится в примере, скрипт деплоя копирует проект на сервер по SSH и перезапускает systemd-сервис. После git push vps main ваш код оказывается на сервере без дополнительного вмешательства.

Создание и настройка systemd-сервиса

Далее нужно создать unit-файл для вашего приложения. Заведите файл /etc/systemd/system/myapp.service со следующим содержимым:

[Unit]
Description=MyApp Service
After=network.target

[Service]
User=deploy
WorkingDirectory=/home/deploy/app
ExecStart=/usr/bin/python3 /home/deploy/app/app.py
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Здесь User и WorkingDirectory указывают, под каким пользователем и в какой папке запускать приложение. ExecStart — это команда запуска для Python-файла или исполняемого скрипта. Если вы используете виртуальное окружение, путь до интерпретатора нужно указать явно, например, ExecStart=/home/deploy/app/venv/bin/python3 /home/deploy/app/app.py, чтобы systemd запустил именно ваш виртуальный Python. Опция Restart=on-failure говорит systemd автоматически перезапускать сервис при сбое. RestartSec=5s добавляет паузу в 5 секунд перед перезапуском, чтобы не гонять ресурсами.

По умолчанию systemd отправляет логи в свою подсистему journald. Если нужно выводить их в syslog, чтобы, например, собирать логи централизованно, можно добавить строки в секцию:

[Service]: StandardOutput=syslog SyslogIdentifier=myapp

Это позволит отличать логи вашего приложения в общем журнале. После создания или изменения unit-файла выполните:

sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp

Команда daemon-reload сообщит systemd о новом/изменённом сервисе. После start сервис запустится сразу, а enable включит его при старте сервера. Проверить статус приложения можно командой systemctl status myapp, а полные логи смотреть через journalctl -u myapp.

systemd будет держать ваш сервис в фоне, перезапускать при сбоях и запускать при загрузке сервера. Можно прописать запуск бекап-скриптов или других вспомогательных процессов в этом же unit-файле. Например, в секции [Service] можно указать Environment=MY_ENV=prod или другие переменные окружения прямо здесь, чтобы не хранить секреты в коде. Главное убедиться, что файлы в /home/deploy/app принадлежат пользователю deploy, иначе скрипт не сможет их читать.

Интеграция Git-хука и сервиса

Остаётся связать всё воедино. Когда хук выполняет команду checkout или pull, нужно, чтобы сервис увидел обновлённый код. Достаточно вызвать systemctl restart. Например, полный скрипт /home/deploy/project.git/hooks/post-receive может выглядеть так:

#!/bin/bash
echo "Получаем последние изменения..."
GIT_WORK_TREE=/home/deploy/app git checkout -f
echo "Останавливаем и перезапускаем сервис..."
sudo systemctl restart myapp.service

Скрипт выводит сообщения в журнал, обновляет файлы из репозитория и перезапускает сервис. Можно добавить небольшую паузу (sleep 2) между командами, чтобы убедиться, что предыдущий процесс завершился. Если приложение требует сборки или установки зависимостей, добавьте это в хук. К примеру:

cd /home/deploy/app
npm ci
npm run build

Или для Python/Django:

python manage.py migrate

Главное, чтобы команды выполнялись от пользователя deploy, поэтому если он не имеет прав на перезапуск сервиса, можно дать ему нужные привилегии через sudo. Например, добавить в /etc/sudoers строку:

deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp.service

И вызывать sudo systemctl restart в скрипте.

В некоторых случаях вы хотите обновить только конфигурацию веб-сервера. Например, если изменился файл Nginx или статический контент, можно вместо полного перезапуска службы приложения выполнить:

sudo systemctl reload nginx

Это применит новую конфигурацию без остановки сервера. Наконец, после того как хук завершил свою работу, сервер увидит изменения и запустит обновлённый код. Эта схема превращает деплой в одну команду. Как отмечено в примере, достаточно запустить git pull, и дальше systemd сам поднимет сервис. Привычное «влепить файлы вручную» уходит в прошлое.

Тестирование и практические советы

Когда всё настроено, протестируйте процесс. Сделайте пробный коммит, например, поменяйте строку комментария в коде, и выполните git push vps main. После этого загляните в логи:

sudo journalctl -u myapp -f

Здесь отображаются сообщения при старте и возможные ошибки. Если приложение не запустилось, команда systemctl status myapp подскажет причину. После успешного обновления вы можете буквально забыть про деплой: сделали коммит вечером за чашкой чая, а к утру новое изменение уже развёрнуто в продакшене. Такой подход превращает деплой в невидимую операцию, позволяя сосредоточиться на любимых задачах, пока сервер делает всю рутинную работу.

Не забудьте о безопасности. На этапе тестирования удостоверьтесь, что приложение корректно запускается от указанного пользователя и папки. Настройте файрвол или fail2ban для SSH-подключений, чтобы отпугнуть злоумышленников. И главное — делайте резервные копии баз данных и важных файлов перед крупным обновлением. К примеру, можно настроить скрипт бекапа базы данных:

pg_dump mydatabase > /home/deploy/db_backup_$(date +%F).sql

И запускать его перед деплоем. Тогда при критической ошибке вы легко вернётесь к предыдущему состоянию.

Если в будущем захотите развернуть на том же сервере ещё один проект, просто заведите для него новый Git-репозиторий и unit-файл. В итоге каждый ваш сервис будет самоустанавливающимся, осталось только нажать git push, как по волшебству. Стоит также настроить уведомления или дополнительные логи, например, добавьте в скрипт запись в общий лог-файл или отправку сообщения (Telegram/Slack) о новом деплое, чтобы команда точно видела результат.

Заключение

Автоматизация деплоя освобождает ваше время и позволяет сконцентрироваться на самом важном — развитии проекта. Теперь достаточно сделать push в репозиторий, и сервер сам подтянет обновления и перезапустит сервис. Пусть рутинные задачи возьмёт на себя система, вы же занимайтесь новыми идеями и фичами. Такой подход не только экономит нервы, но и даёт ощущение контроля и порядка в продакшене.

За стабильность — с бонусом

Долгосрочные клиенты получают больше: +1 месяц в подарок по промокоду

Месяц в подарок
COPIED
NEWCOMM COPIED