Введение: Почему CI/CD — must have для Java-разработчика
Современная Java-разработка немыслима без автоматизации. Ручной запуск тестов, сборка .jar файлов и деплой на сервер отнимают часы и приводят к человеческим ошибкам. CI/CD (Continuous Integration / Continuous Deployment) решает эту проблему: каждый коммит в репозиторий автоматически проверяется, собирается и, при необходимости, отправляется в продакшн.
GitHub Actions — встроенный инструмент GitHub, который позволяет создавать пайплайны прямо в репозитории. Он бесплатен для публичных проектов, легко интегрируется с Maven/Gradle и поддерживает Java 8–21. В этой статье мы разберём полный цикл: от триггера на пуш до публикации артефакта.
1. Основы GitHub Actions: структура workflow
Workflow (рабочий процесс) — это YAML-файл, лежащий в .github/workflows/. Он состоит из:
- Триггеров (push, pull_request, schedule);
- Jobs (задач), которые выполняются на виртуальных машинах (runner’ах);
- Steps (шагов) внутри каждой задачи.
Для Java-проекта типовой workflow включает установку JDK, запуск тестов Maven/Gradle и сборку артефакта.
1.1. Первый workflow: тестирование Java-проекта
Создайте файл .github/workflows/ci.yml со следующим содержимым:
name: Java CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Run tests
run: mvn test
Что здесь происходит:
actions/checkout— клонирует репозиторий;setup-java— устанавливает JDK 17 (Temurin) и кеширует Maven-зависимости;mvn package— собирает проект и запускает тесты;mvn test— явный запуск тестов (можно объединить с package).
После пуша в main вы увидите зелёную галочку рядом с коммитом — это значит, что пайплайн прошёл успешно.
2. Продвинутая настройка для Java: матрица версий и кеширование
Реальные проекты часто требуют проверки на нескольких версиях Java. GitHub Actions поддерживает матрицу стратегий (matrix strategy).
2.1. Матрица JDK
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
java: [11, 17, 21]
steps:
- uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: maven
- run: mvn test
Такой подход гарантирует, что ваш код совместим с LTS-версиями Java. При этом задачи выполняются параллельно, что экономит время.
2.2. Кеширование зависимостей
Мы уже указали cache: maven — это автоматически кеширует ~/.m2/repository. Для Gradle используйте cache: gradle. Кеш ускоряет сборку в 2–3 раза.
3. Сборка и публикация артефактов (JAR/Docker)
После успешного тестирования нужно получить готовый артефакт. Рассмотрим два популярных сценария.
3.1. Загрузка JAR-файла в артефакты GitHub
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- run: mvn clean package
- name: Upload JAR
uses: actions/upload-artifact@v4
with:
name: my-app-jar
path: target/*.jar
Артефакт появится на странице workflow и будет доступен для скачивания в течение 90 дней.
3.2. Сборка Docker-образа и публикация в Docker Hub
Для деплоя микросервисов удобно использовать Docker. Пример workflow с публикацией образа:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build JAR
run: mvn clean package -DskipTests
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myuser/myapp:latest
Не забудьте добавить секреты DOCKER_USERNAME и DOCKER_PASSWORD в настройках репозитория (Settings → Secrets and variables → Actions).
4. Деплой на сервер: от простого к сложному
Финальная стадия CI/CD — доставка приложения на сервер. Рассмотрим два подхода.
4.1. SCP-деплой на VPS
Для небольших проектов можно копировать JAR по SSH:
jobs:
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v4
with:
name: my-app-jar
- name: Deploy to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "*.jar"
target: "/opt/myapp/"
- name: Restart service
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets