CI/CD для начинающих: деплой React-приложения без боли

6g-gegevpe84lpgnj0pc1kf1zqu.png


Следующий шаг после разработки веб-приложения — размещение его на сервере. Независимо от сложности проекта или используемой инфраструктуры, общий процесс остается одинаковым: нужно «упаковать» код в CI/CD-конвейер и отправить на сервер. В тексте рассмотрим, как это происходит на примере простого приложения to-do list на React. Подробности под катом!
Используйте навигацию, если не хотите читать текст полностью:

→ Описание проекта
→ Создание проекта в облаке
→ Настройка веб-сервера и ручной деплой
→ Настройка раннера
→ Автодеплой
→ Заключение

Описание проекта


59e4c09eb79ed5235ed86d6a1de828dd.png


Скриншот приложения.

To-do list — это приложение для управления задачами. Оно помогает пользователю быстро добавлять, удалять и помечать задачи как выполненные. Так как они хранятся в локальном хранилище браузера, нам не нужна внешняя база данных и API для работы. Сосредоточимся на деплое приложения и настройке веб-сервера. В качестве последнего используем Nginx, а для обеспечения доступности из глобальной сети — облачную инфраструктуру.

dieiksvcuar3umm3kjj24s37br8.png


Создание проекта в облаке


1. Переходим в Панель управленияОблачная платформа. Нажимаем Создать проект.

414a076552a697fe7005388131e43033.png


[врезка на полях Академии]

Подробнее об облачных серверах
2. Вводим название для нового проекта и нажимаем Создать проект.

9b536ee7c0add1e9dc0b73662e85917d.png


3. В разделе Облачная платформа видим новый проект. Во вкладке Серверы нажимаем Создать сервер.

379e7f01d0d426cd16c904ae874fb347.png


4. Выбираем произвольное имя (в нашем случае — todo-list), локацию, пул и источник.

4cb7b5b0d5159265931ed8813d926585.png


В качестве источника выбрали Debian 12, но есть множество других вариантов. Вы можете выбрать подходящий дистрибутив Linux или уже готовый образ с приложениями.

41520a2421b57c728b18075527b1843d.png


5. Настраиваем конфигурацию. В нашем случае подойдет Standard с локальным SSD-диском на 8 ГБ, 1 vCPU и 1 ГБ ОЗУ. В блоке Сеть выбираем Новый публичный IP-адрес. Так наше приложение будет доступно из интернета.

efd02ad1da33b629d0cf0b1ac0303ee2.png


6. В блоке Доступ добавляем SSH-ключ (публичную часть) для пользователя root.

0e7152aa044a2ee56f5d0a7758d83c4b.png


7. После нажатия на кнопку Добавить SSH-ключ появляется окно ввода. Здесь есть шпаргалка для генерации пары SSH-ключей, а также ссылка на полную версию инструкции. Вводим публичный ключ в формате OpenSSH и имя для него, нажимаем Добавить.

4be213caa28075e1b3fc32ead60a302d.png


8. Получаем пароль и сохраняем его в безопасное место.

3e0a455ce64bde2d046cffd0e848ac13.png


9. Проверяем стоимость выбранной конфигурации и создаем сервер.

484ce3a183f3afd3c42aa0da9d11cec6.png


Отлично — сервер готов. Видим его в списке созданных.

3595180c73ceabdc62744a8c6c7b3cd6.png


После получения статуса ACTIVE можно заходить на сервер по выделенному белому IP-адресу:

ssh root@31.129.35.121


2690cc636b535734afc0bb760a00f15b.png


В примере мы сосредоточены на публикации нашего приложения и не рассматриваем вопросы первичной настройки и безопасности сервера. О необходимых мерах по защите сервера, настройке, подключении SSH и установку специализированного ПО для блокировки злоумышленников — рассказываем в пошаговой шпаргалке.


Настройка веб-сервера и ручной деплой


1. Обновляем информацию о пакетах:

apt update


2. Устанавливаем пакеты:

  • mc — для удобной графической навигации по файловой системе,
  • git — для клонирования репозитория с приложением,
  • nginx — для организации веб-сервера,
  • nodejs и npm — для установки пакетов и сборки веб-приложения на React.
apt install mc git nginx nodejs npm


3. После установки проверяем корректность работы Nginx. Для этого в браузере переходим по IP-адресу сервера 31.129.35.121, который ранее арендовали:

86a25b0cc00c104113083a327e56a39a.png


Приветственная страница Nginx. Если вы ее видите, значит сервер работает корректно.

4. Перемещаемся в директорию /var/www/ и клонируем репозиторий с веб-приложением:

git clone https://gitlab.com/Byurrer/todo-list.git


9449a417a1611ee7374d1c3abb3f3707.png


5. Переходим в директорию todo-list и устанавливаем пакеты:

npm install


6. Производим сборку проекта:

npm run build


Теперь появилась директория build, в которой лежит вся статика нашего приложения:

f57934db74355f38120189b8cbd6dea4.png


7. Готовим конфигурацию сайта в Nginx. Для этого в директории /etc/nginx/sites-available/ создаем файл todo-list и записываем в него код:

server {
        listen 80;
        server_name 31.129.35.121;
        location / {
                root /var/www/todo-list/build/;
                try_files $uri $uri/ =404;
        }
}


Записать код можно с помощью mcedit:

mcedit /etc/nginx/sites-available/todo-list


В этом конфиге приложение будет доступно на 80 порте (http) при обращении к хосту 31.129.35.121.

8. Указываем корень нашего сайта /var/www/todo-list/build/ и в директиве try_files обращаемся к файлам/директориям, переданным в строке запроса. Если их не удается найти — отдаем страницу 404.

9. Создаем символьную ссылку на нашу конфигурацию в директорию /etc/nginx/sites-enabled/ и проверяем ее на валидность. Если ошибок нет, отправляем Nginx команду на перезагрузку конфигурации:

ln -s /etc/nginx/sites-available/todo-list /etc/nginx/sites-enabled/
nginx -t
nginx -s reload


56c69c037dd9867bd15637a2128373b4.png


Вывод должен выглядеть примерно так.

10. Если ошибок не было, то при обращении к серверу через веб-браузер http://31.129.35.121/ вы получите страницу веб-приложения:

d6af5e4b7d20940b47045b7cb383e142.png


Настройка раннера


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

Пойдем простым путем. У нас есть сервер с развернутым веб-приложением, а код хостим на GitLab, где доступен удобный инструмент для организации CI/CD-конвейера — GitLab CI. С его помощью сможем поставлять приложение на веб-сервер. Рабочий механизм — GitLab Runner, а процессы описываются с помощью gitlab-ci.yml в корне репозитория.

1. Создадим раннер для проекта. Перейдем в Settings → CI/CD → Runners и нажмем New Project Runner.

8faeb328138ed153e177e9478c5374b2.png


2. Укажем произвольный тег, который мы дальше будем использовать при настройке CI/CD, а также описание раннера. Нажмем Create runner.

0b33b16f0adfd9e1c5a6e232fb02abf4.png


3. Следующая страница содержит инструкции по настройке раннера, а при клике по выделенной ссылке появится шпаргалка по установке раннера на сервер.

c298a0e6b4bec1a045ec847afe4dfcb5.png


Выполнение шагов установки должно выглядеть примерно так:

d67e21ef4c0dbc0d15bda3b832aa2be1.png


Во время выполнения джобов CI/CD можно столкнуться с ошибкой:

ERROR: Job failed: prepare environment: exit status 1.  Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information


e5e9c200670f4db4580d0e609dcb631c.png


Для решения нужно использовать подсказку из документации.

4. Перейдем к регистрации раннера, как указано в Step 1.

d5e16f839fe6406fbed1f1f1d7bf5bb7.png


Указываем источник и название по умолчанию, тип раннера — shell, так как исполнять команды будем на самом сервере:

a32221024291709c7eb1546335e29b09.png


5. После успешной регистрации на странице появится блок об успешном завершении.

10ec13015dac45567449ac1202b6fa45.png


6. Нажимаем кнопку View runners и видим страницу с раннерами для нашего проекта.

65a17f0fe9d1e36a62324fae613c16eb.png


Важно! Нажимаем кнопку Enable for this project, чтобы раннер был включен для этого проекта.

6cd4600e22a896aa5f06b0430fc983d3.png


Автодеплой


Созданный раннер будет выполнять все команды от пользователя gitlab-runner, но сперва попробуем сделать все вручную.

1. Создаем новую директорию, в котором будем размещать всю «статику» (статические файлы). Меняем владельца и группу на gitlab-runner.

mkdir /var/www/todo-list-build
chown gitlab-runner:gitlab-runner /var/www/todo-list-build


2. Меняем путь до корня сайта в конфиге Nginx.

a237c948df3b433b383851c9d420d0da.png


3. При помощи nginx -t проверяем конфигурацию на ошибки, а далее перезагружаем конфиг командой nginx -s reload.

4. Заходим от имени пользователя gitlab-runner, собираем и деплоим проект.

su gitlab-runner
cd # переход в домашнюю директорию пользователя
git clone https://gitlab.com/Byurrer/todo-list.git
npm install
npm run build
rsync -av --delete build/ /var/www/todo-list-build/


5. Проверяем в директории /var/www/todo-list-build/, что файлы скопированы.

341d088dea84fd99fe2cf3742826690f.png


6. Переходим в браузере по IP сервера. Веб-приложение также должно работать.

7. Теперь, когда мы поняли, какие команды будет выполнять раннер, можем реализовать автодеплой. Для его настройки нужно в корне репозитория создать файл .gitlab-ci.yml с таким содержимым:

stages:
  - build
  - deploy
build:
  stage: build
  script:
    - npm install
    - npm run build
  cache:
    paths:
      - node_modules/
  artifacts:
    paths:
      - build/
  tags:
    - todo-list
deploy:
  stage: deploy
  script:
    - rsync -av --delete $CI_PROJECT_DIR/build/ /var/www/todo-list-build/
  only:
    - main
  tags:
    - todo-list


387cb909ebba711b3232e9a69b53d119.png


8. Запушим в ветку main произвольные изменения и перейдем в Builds → Pipelines, где появился автоматически запущенный конвейер.

aa1b2af9ae50202e7849ad6585514f0a.png


Внутри выполняются две джобы:

703d3a78b90aa06ec41d06c42f4afac5.png


Можно перейти к каждому из них и наблюдать процесс выполнения.

a6eb902326825df78f95cfbef9fb9850.png


Успешное исполнение джобы на стадии deploy выглядит примерно так.

После выполнения всего конвейера наши правки должны поступить в приложение на веб-сервере.

Заключение


Мы рассмотрели один из простых вариантов организации CI/CD-конвейера для веб-приложения. В реальных условиях процесс становится более сложным и гибким, однако понимание его основ — первый шаг. Далее вы можете масштабировать и адаптировать проект под задачи в рабочей среде.

© Habrahabr.ru