Контекст. Я делал сравнение разных CI/CD решений для автоматизации наших систем (сборка, деплой java бекендов с ts/angular фронтендов). Смотрел на штуки типа github action, gitlab actions, jenkins, bamboo и иже с ними. В итогде остановился на github actions как самом дешевом и гибком варианте. Думаю что эта платформа отлично подойдет под ваш случай так как вы уже работаете с гитхабом. Если имеешь представление о том как работает bash, linux, command line и docker, то за 2-3 дня можно получить рабочую демку для сборки вашего проекта. Система достаточно простая чтобы разработчик мог сам накрапать решение, и достаточно популярная чтобы нагуглить ответы на свои вопросы.
Ответ. Я бы решал твою задачу через github actions (есть путанье в терминологии в одном месте они называются github workflow, в других github actions. Я продолжу называть их github actions). Ниже опишу элементы из которых будет состоять ваше решение, и в каких условиях оно будет запускаться. Еще ниже покажу каким скриптом собираю и деплою наш проект.
Триггер. Можно делать экшены которые будут запускаться по пушу в ветку, по коммиту, по мержу а так же есть ручные экшены. Ручным экшенам можно задать ввод. Я реализовывал ручной экшен для деплоя на test окружение, ввод для него был название git объекта: коммита, ветки, тега.
Тело экшенов. В теле экшенов у тебя будет микс из уже готовы экшенов (например установка nodejs и npm нужных версий) и bash скриптов. Все это дело будет запускаться в докере на серверах гитхаба. Кстати, платить вы будете по затраченному времени этими серверами. Тех бесплатных минут что идут из коробки будет достаточно чтобы поэкспериментировать и собирать ваш проект. Есть варианты оптимизации этого времени через хостинг воркеров (в которых запускаются шаги github actions) на своем хостинге.
Из готовых экшенов, есть, например работа с гитом: чекаут определенной версии, чекают всего дерева или с глубиной в 1, создание нового коммита, создание релиза. Большой бонус что github actions хорошо интегрированы с самим гитхабом: т.е. merge request, релизы - это все можно найти как реализовать.
В теле экшенов тебе будут доступен богатый набор переменных окружения (от названия ветки до пользовательского инпута для ручных экшенов). Секреты, такие как ssh ключи и пароли хранятся уровне “secrects” самого репозитория и подтягиваются в экшенах через те же переменные окружения. Например, я храню ssh данные для того чтобы экшен ходил на наш сервер и запускал там скрипты бекапа и рестарта.
Из явных нюансов: сделать так чтобы github actions запускались локально можно (GitHub - nektos/act: Run your GitHub Actions locally 🚀), но это требует работы по воссозданию переменных окружения которые используют твои экшены.
Там еще куча нюансов и приколов с системой, давай пообщаемся про то что интересует тебя.
Вот код github actions которым мы пользуемся для деплоя приложения в тестовое окружение.
name: Deploy manually to test
on:
workflow_dispatch:
inputs:
gitEntity:
description: 'Branch name, commit hash or tag'
required: true
default: 'development'
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
MAIL_APP_NAME: Hours Administration (BE/FE)
MAIL_APP_URL: https://ppp.metafactory.io/
MAIL_RECIPIENTS: a@mail.com
jobs:
deploy-be:
concurrency:
group: hours-be
cancel-in-progress: true
runs-on: ubuntu-latest
env:
SSH_USER: ${{ secrets.SSH_USER_BE }}
SSH_SERVER: ${{ secrets.SSH_SERVER_BE }}
JAR_SERVER: hoursadministration.jar
steps:
- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
sudo chmod 600 ~/.ssh/id_rsa
echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- name: Check out code
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.gitEntity }}
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
cache: maven
- name: Build with Maven
run: mvn -Pprod clean package
- name: Backup server's application.yml
run: ssh ${SSH_USER}@${SSH_SERVER} "mv ./application/config/application.yml ./application/config/application.yml-$(date +"%Y-%m-%d_%H%M%S")"
- name: Upload application.yml
run: scp ./config/application.yml ${SSH_USER}@${SSH_SERVER}:/var/virtual_hosts/hours-backend-test.metafactory.io/application/config/application.yml
working-directory: ./hours-administration
- name: Stop server if running
run: ssh ${SSH_USER}@${SSH_SERVER} "cd application && ./stop.sh"
- name: Persist previous .jar
run: ssh ${SSH_USER}@${SSH_SERVER} "cp application/${JAR_SERVER} application/application_backup/${JAR_SERVER}-$(date +\"%Y-%m-%d_%H%M%S\")"
- name: Backup current DB in the server
run: ssh ${SSH_USER}@${SSH_SERVER} "cd application && ./backup_database.sh"
- name: Upload new jar
run: scp target/hoursadministration-0.0.1-SNAPSHOT.jar ${SSH_USER}@${SSH_SERVER}:/var/virtual_hosts/hours-backend-test.metafactory.io/application/${JAR_SERVER}
working-directory: ./hours-administration
- name: Start server
run: ssh ${SSH_USER}@${SSH_SERVER} '((cd application && ./start.sh) &)'
deploy-fe:
concurrency:
group: hours-fe
cancel-in-progress: true
runs-on: ubuntu-latest
env:
SSH_USER: ${{ secrets.SSH_USER_FE }}
SSH_SERVER: ${{ secrets.SSH_SERVER_FE }}
steps:
- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
sudo chmod 600 ~/.ssh/id_rsa
echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- name: Check out code
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.gitEntity }}
- name: Set up nodejs@14
uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'npm'
cache-dependency-path: hours-angular/package-lock.json
- name: Install npm dependencies
run: npm install
working-directory: ./hours-angular
- name: Build with npm
run: npm run build
working-directory: ./hours-angular
- name: Deploy assets
run: rsync -avz --delete --exclude '.git' build/resources/main/static/ ${SSH_USER}@${SSH_SERVER}:/var/virtual_hosts/hours-angular-test.metafactory.io/application
working-directory: ./hours-angular
notify-success:
needs:
- deploy-fe
- deploy-be
runs-on: ubuntu-latest
env:
SSH_USER: ${{ secrets.SSH_USER_BE }}
SSH_SERVER: ${{ secrets.SSH_SERVER_BE }}
steps:
- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
sudo chmod 600 ~/.ssh/id_rsa
echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- name: Send email notification about success
run: ssh ${SSH_USER}@${SSH_SERVER} "echo -e \"${GITHUB_ACTOR} manually deployed \"${{ github.event.inputs.gitEntity }}\" of ${MAIL_APP_NAME} to ${SSH_SERVER} on $(date +'%Y-%m-%d %H:%M:%S').\n\nCheck ${MAIL_APP_URL}\" | mail -s \"${MAIL_APP_NAME} is manually deployed by ${GITHUB_ACTOR}\" -r no-reply@${SSH_SERVER} ${MAIL_RECIPIENTS}"