Разберём, как с нуля настроить пайплайн в GitHub Actions: тесты, сборка, выкладка на сервер — пошагово и на практике.
Когда в проекте появляется несколько разработчиков, правки в код начинают множиться, а вместе с ними растёт и вероятность ошибок. Если не наладить процесс проверки и доставки изменений, ошибки начнут попадать в продакшен до того, как их заметят. Автоматизация помогает избежать этого за счёт того самого CI/CD. В материале рассказали, как с нуля настроить CI/CD на GitHub: что такое пайплайн, как он работает и как выглядит на практике.
Подключение GitHub Actions
GitHub Actions — это встроенный механизм GitHub, который позволяет настроить автоматические действия при каждом коммите, пулл-реквесте или пуше. Тесты, сборка, деплой, уведомления — всё можно настроить в одном YAML-файле. Работает прямо в репозитории, без дополнительного ПО и сторонних сервисов.
Начнём с основ. Если репозитория ещё нет, заведите его на GitHub. Репозиторий можно создать за несколько минут. После этого в корне проекта создайте папку .github/workflows. Именно туда будут попадать все файлы конфигурации для Actions. Это делается командой:
mkdir -p .github/workflows
Затем добавьте в эту папку YAML-файл, например, ci.yml. Внутри опишите, что должно происходить при конкретных событиях. Самый частый вариант — запуск пайплайна при пуше в ветку main. Также здесь же задаются последовательности задач.
Actions активируются автоматически после добавления и коммита конфигурационного файла в ветку. Дополнительно ничего включать не нужно, всё работает сразу.
Первым шагом практически в любом пайплайне идёт загрузка репозитория:
- uses: actions/checkout@v3
Это действие позволяет остальным шагам работать с кодом проекта. После этого можно устанавливать зависимости, запускать тесты, собирать приложение или делать деплой.
GitHub автоматически предоставляет токен $GITHUB_TOKEN, который используется для API-запросов, пуша и авторизации в экшенах — настройка не требуется.
Если раньше вы собирали проект вручную или делали деплой через SSH, теперь это можно перенести в YAML. Всё будет работать по расписанию или в ответ на действия команды.
Пример базового пайплайна
Представим, что при каждом пуше в ветку main нужно автоматически собрать проект, прогнать тесты и при успехе выложить его на сервер. Такое поведение удобно описать в YAML-файле:
.github/workflows/ci.yml
Как выглядит пайплайн в GitHub Actions на практике:
name: CI-CD Pipeline
on:
push:
branches: [ main ]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Build project
run: npm run build
deploy:
needs: build-test
runs-on: ubuntu-latest
if: ${{ success() }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
rsync -avz --delete ./build/ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/var/www/html
Остановимся поподробнее на том, что здесь происходит.
Workflow запускается после каждого коммита в ветку main. В первой задаче выполняется три шага: клонируется код, устанавливаются зависимости через npm, запускаются тесты. Все шаги выполняются в изолированной среде GitHub Actions на базе Ubuntu.
Вторая задача отвечает за выкладку. Она стартует только если предыдущая завершилась без ошибок. Сначала снова загружается код, затем с помощью appleboy/ssh-action происходит подключение к серверу. Чтобы не хранить ключи в коде, используют секреты. Их добавляют в настройках репозитория, а затем подключают в пайплайне.
В SERVER_HOST указываем IP-адрес сервера. В SERVER_USER — имя пользователя. В SERVER_SSH_KEY вставляется приватный SSH-ключ, который создавался ранее. Все эти данные добавляются в GitHub в разделе Settings → Secrets and variables → Actions.
Все переменные вида ${{ secrets.NAME }} скрыты от чужих глаз и не отображаются даже в логах — это обеспечивает надёжную защиту. Хранить в них можно ключи, токены, пароли и другие важные данные. Это безопаснее, чем прописывать всё напрямую в коде.
Такой сценарий поможет наладить автоматическую доставку обновлений. Со временем его можно расширить: добавить деплой в несколько сред, проверки кода, уведомления или публикацию контейнеров.
Настройка деплоя на сервере
Обычно автодеплой на сервер настраивают через GitHub Actions. Чаще всего приложение размещают на VPS или другом удалённом хостинге. Один из самых простых способов — использовать SSH и rsync. Сначала нужно сгенерировать SSH-ключ:
ssh-keygen
Публичную часть (.pub) добавляем в панель управления хостингом, а приватную сохраняем в GitHub. Затем подключаем один из экшенов, например:
appleboy/ssh-action
appleboy/rsync-action
Сначала экшен подключается к серверу по SSH, а потом уже выполняет всё, что вы ему задали: например, перенести файлы и перезапустить сервис:
- name: Remote deploy script
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /var/www/project
git pull origin main
npm install --production
pm2 reload all
Значения SERVER_HOST, SERVER_USER и SERVER_SSH_KEY нужно задать в настройках репозитория GitHub. Это делается в разделе Settings → Secrets and variables → Actions. В SERVER_HOST укажите IP-адрес сервера, в SERVER_USER — имя пользователя на сервере, а в SERVER_SSH_KEY вставьте приватный ключ, сгенерированный заранее через ssh-keygen.
Панель управления VPS от AdminVPS поддерживает загрузку SSH-ключей, что упрощает настройку доступа.
Когда приложение крутится в Docker, его можно упаковать в образ и отправить в Docker Hub или GitHub Container Registry — оттуда его потом удобно разворачивать. Сначала авторизация:
- name: Log in to Docker registry
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
Здесь нужно заменить DOCKER_USER и DOCKER_PASSWORD на свои данные от Docker Hub или другого контейнерного реестра. Эти данные тоже добавляются в GitHub Secrets.
Затем сборка и отправка:
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKER_USER }}/myapp:latest
Значение myapp:latest можно заменить на нужное имя образа и тег. Например, myproject:v1 или mycompany/backend:prod.
После этого на сервере достаточно выполнить docker pull и docker run или обновить контейнер через docker-compose. Этот вариант особенно удобен для микросервисов и гибкой работы с окружениями.
Если SSH недоступен, можно использовать FTP. Для этого подойдёт экшен:
SamKirkland/FTP-Deploy-Action
Он синхронизирует локальную папку с директориями на сервере. Как выглядит команда на практике:
- name: Deploy via FTP
uses: SamKirkland/FTP-Deploy-Action@v4
with:
server: ${{ secrets.FTP_HOST }}
username: ${{ secrets.FTP_USER }}
password: ${{ secrets.FTP_PASS }}
local-dir: ./build
В FTP_HOST укажите адрес FTP-сервера, в FTP_USER — логин, а в FTP_PASS — пароль. Все три значения хранятся в секции GitHub Secrets. local-dir — путь к папке на вашем проекте, которую нужно загрузить. Его можно изменить на, скажем, dist, если проект собирается туда.
Все данные, такие как сервер, логин, пароль, передаются через секреты. Главное заранее указать, что именно нужно отправлять.
Дополнительно можно настроить деплой в облачные платформы вроде AWS, Google Cloud, Azure или подключить Heroku, Netlify, Vercel и другие. Суть остаётся той же: GitHub Actions получает доступ к окружению и выполняет нужные шаги. Это может быть даже простой bash-скрипт, который обновляет код и перезапускает приложение.
Полезные советы
Когда что-то идёт не по плану, первое место, куда стоит заглянуть — это вкладка Actions в вашем репозитории. Там отображаются логи всех шагов, и часто одной строчки достаточно, чтобы понять, где запнулась сборка. Если логов мало, можно включить расширенный режим отладки. Для этого создаётся секрет с именем ACTIONS_STEP_DEBUG, в который нужно записать true. После этого в логах появятся дополнительные сообщения, включая строки вида echo "::debug::...", а сами шаги можно запускать в режиме трассировки: run: set -x; команда. Это поможет увидеть, что именно выполняется внутри.
Особое внимание уделите безопасности. Всё, что связано с токенами, паролями и ключами, должно жить в GitHub Secrets. Их не видно в логах, их нельзя вывести случайно в консоль, и они не попадут в pull-реквест. Секреты — это специальные переменные для защищённой передачи данных в pipeline. Подключать их в код нужно через ${{ secrets.NAME }} и не пытаться вписать напрямую, даже если кажется, что для теста можно.
Ошибки в CI/CD бывают у всех. Иногда причина банальная, например, опечатка, недостающий пакет, забытая настройка окружения. Если пайплайн упал, посмотрите лог, поправьте и нажмите Re-run jobs. GitHub сам перезапустит только неудачные шаги. А если что-то идёт совсем не так, задайте вопрос в GitHub Community.
Заключение
CI/CD поначалу может казаться чем-то громоздким, но постепенно приходит ощущение контроля. Привыкаешь к ритму, начинаешь доверять процессу, и это даёт свободу. Можно сосредоточиться на развитии продукта, зная, что сборка всё проверит и выложит, если всё в порядке. А если что-то пойдёт не так, система подскажет.
Главное не спешить. Настраивать всё по шагам, пробовать, возвращаться, если нужно. А когда пайплайн заработает как часы, можно выдохнуть.
Читайте в блоге:
- Деплой на VPS без проблем: как автоматизировать процесс и забыть о рутине
- Как открыть и закрыть порты в Ubuntu 22.04 и защитить систему от угроз
- Как установить и настроить PostgreSQL в Ubuntu 22.04