Деплоим с поддержкой ветвления без навыков DevOps на примере VueГрубо говоря, GitHub Actions – это написанные пользователем сценарии, выполнение которых можно затриггерить по определенным действиям в репозитории (например, новый коммит).Можно выделить следующие преимущества GitHub Actions среди других CI инструментов: модульность – сообществом поддерживаются пакеты для узких задач, избавляющие вас от дублирования кода и написания длинных скриптов (примеры: сборка Docker контейнера, передача файла на сервер, оповещение в Telegram и тысячи других)цена – бесплатный тарифный план покроет нужды небольших проектовскорость – быстрее бесплатных аналогов исходя из личного опытаВ статье описана реализация следующего сценария, который поможет упростить тестирование и разработку вашего приложения:Пользователь вносит изменения в веткуАвтоматически запускается отвечающий за сборку скриптСобранное приложение доставляется на сервер и доступно по адресу <имя_ветки>.app.example.ruПодготовка сервераВсе действия будут выполнены на OC Ubuntu 20.04. Также нам понадобится доступ к NS-записям домена.Подойдет cамая минимальная конфигурация, достаточная для раздачи статики. Остальную работу на себя возьмут серверы Гитхаба.P.S.: Читателям статьи VScale предоставили купон VCGUIDE на 250 рублей.Авторизуемся сгенерированным паролем с помощью командной строки или любого SSH клиента:ssh root@<ip вашего сервера>Установка необходимых пакетовУстановим nginx – он будет отвечать за раздачу файлов приложения:apt update && apt install nginx -yДалее создадим SSH-ключ, который понадобится нам для деплоя приложения на сервер:ssh-keygen -t rsa -b 4096 -f deployНам будет предложено задать секретный пароль, пропустим этот шаг (Enter).Добавим ключ в доверенные:cat ~/deploy.pub >> ~/.ssh/authorized_keysИ перезапустим сервис sshd для применения изменений:service sshd reloadНастройка репозиторияSecrets (Settings > Secrets)Подходит для хранения приватной информации – например, нашего SSH-ключа. Значения этих переменных будут скрыты из вывода в консоль и будут доступны только нам. Задаем следующие переменные в настройках:DEPLOY_SERVER_HOST – IP вашего сервераDEPLOY_SERVER_PORT – SSH порт (по умолчанию 22)DEPLOY_SERVER_USERNAME – Имя пользователя (по умолчанию root)DEPLOY_SERVER_KEY – Секретная часть сгенерированного ранее ключа (посмотреть можно командой cat ~/deploy)Github Actions: Создаем WorkflowСоздадим в нашем репозитории шаблон для задачи, отвечающей за деплой:Следующего содержания:name: CI on: [push] env: DEPLOY_PATH: /var/www/app # В теории можно собрать не только Vue-приложение, так как принцип сборки мало где отличается BUILD_SCRIPT: npm run build BUILD_SCRIPT_OUTPUT: dist jobs: deploy: runs-on: ubuntu-latest steps: # Делаем checkout текущей ветки - uses: actions/checkout@v2 # Устанавливаем Node.JS для сборки приложения - uses: actions/setup-node@v1 with: node-version: '14' # Записываем в переменные окружения имя текущей ветки # Чтобы избежать конфиликтов с URL, меняем точки на _, а слеши на минусы - name: Get branch name shell: bash run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_REF#refs/heads/} | sed 's/\//-/g' | sed 's/\./_/g')" # Устанавливаем зависимости для сборки - name: Install Dependencies run: npm i # Собираем приложение - name: Build Appliction run: $BUILD_SCRIPT # Доставляем собранное приложение на сервер - name: Deploy to Server uses: appleboy/scp-action@master with: host: ${{ secrets.DEPLOY_SERVER_HOST }} port: ${{ secrets.DEPLOY_SERVER_PORT }} username: ${{ secrets.DEPLOY_SERVER_USERNAME }} key: ${{ secrets.DEPLOY_SERVER_KEY }} source: ${{ env.BUILD_SCRIPT_OUTPUT }} target: ${{ env.DEPLOY_PATH }}/${{ env.BRANCH_NAME }} strip_components: 1 - name: Print Info run: echo "Deployed at https://${BRANCH_NAME}.app.example.ru/"В примере выше используется созданный пользователем пакет appleboy/scp-action, выполняющий функцию архивирования файлов, передачу созданного архива по SSH и его распаковку на удаленном сервере.Возле последнего коммита отображается статус последнего workflowНастройка фронтендаАвтообновляемые бесплатные SSL-сертификатыДля начала нужно привязать имеющийся домен к серверу.В панеле управления доменом зададим DNS-серверы/NS-записи ns1.vscale.io и ns2.vscale.io В настройках домена добавим новую запись *.example.ru, указывающую на IP нашего сервера:Пример настроенных записейУстановим клиент ACME.sh для работы с Let's Encrypt:curl https://get.acme.sh | sh && source ~/.bashrcДля получения и продления wildcard-сертификатов нужно добавлять специальную текстовую запись для домена. Создадим API токен с полными правами, чтобы не делать это каждый раз вручную. Инструкция для других поддерживаемых провайдеров.Добавим полученный токен в переменные окружения сервера:export VSCALE_API_KEY=<ваш токен>Следующая команда инициирует создание сертификатов для доменов *.example.ru и *.app.example.ru соответственно:acme.sh --issue --dns dns_vscale -d *.example.ru -d *.app.example.ru --key-file /etc/ssl/privkey.pem --fullchain-file /etc/ssl/fullchain.pem --reloadcmd "service nginx force-reload"Ждем окончания проверки, в случае успеха получаем такое сообщение:-----END CERTIFICATE----- [Mon Sep 14 10:03:50 UTC 2020] Your cert is in /root/.acme.sh/*.example.ru/*.example.ru.cer [Mon Sep 14 10:03:50 UTC 2020] Your cert key is in /root/.acme.sh/*.example.ru/*.example.ru.key [Mon Sep 14 10:03:50 UTC 2020] The intermediate CA cert is in /root/.acme.sh/*.example.ru/ca.cer [Mon Sep 14 10:03:50 UTC 2020] And the full chain certs is there: /root/.acme.sh/*.example.ru/fullchain.cer [Mon Sep 14 10:03:50 UTC 2020] Installing key to:/etc/ssl/privkey.pem [Mon Sep 14 10:03:50 UTC 2020] Installing full chain to:/etc/ssl/fullchain.pem [Mon Sep 14 10:03:50 UTC 2020] Run reload cmd: service nginx force-reload [Mon Sep 14 10:03:50 UTC 2020] Reload successНастройка nginxПри каждом коммите в ветку, GitHub Action собирает приложение и отправляет его в директорию /var/www/app/<branch_name>/ у нас на сервере.Нужно настроить сервер так, чтобы запросы к поддомену <branch_name>.app.example.ru указывали на соответствующую директорию.Создадим/заменим стандартную конфигурацию nginx (/etc/nginx/sites-available/default):server { listen 443 ssl; server_name "~^(?<branch>.*)\.app\.example\.ru$"; ssl_certificate /etc/ssl/fullchain.pem; ssl_certificate_key /etc/ssl/privkey.pem; ssl_trusted_certificate /etc/ssl/fullchain.pem; location / { root /var/www/app/$branch; try_files $uri /index.html; } }С помощью регулярного выражения проверяется директива server_name: при соответствии правилу, значение поддомена подставляется в качестве имени root-директории, в которой находится уже собранное приложение.Для применения изменений перезагружаем nginx:nginx -s reloadПроверяем, всё ли получилось:Также можно дополнить конфигурацию следующим правилом:server { listen 443 ssl; server_name app.example.ru; ssl_certificate /etc/ssl/fullchain.pem; ssl_certificate_key /etc/ssl/privkey.pem; ssl_trusted_certificate /etc/ssl/fullchain.pem; location / { root /var/www/app/master; try_files $uri /index.html; } }Теперь app.example.ru будет отображать состояние master-ветки.Репозиторий с исходниками#selectel_инструкция