GitHub Actions: build → test → push → deploy
Цель урока
Сделать полноценный CRUD для задач с правильными HTTP-статусами (201/204/404), обработкой ошибок, и подготовить Task к подключению JPA.
Теория · для собеса
1 Что такое CI/CD ▸
CI (Continuous Integration) — на каждый merge в main: запустить тесты, собрать проект.
CD (Continuous Deployment) — после успешной CI: задеплоить на production автоматически.
2 GitHub Actions — компоненты ▸
- Workflow — файл
.github/workflows/*.yml - Job — набор шагов, выполняется на runner'е
- Step — отдельная команда (run) или action (uses:)
- Runner — VM, где выполняется workflow (ubuntu-latest, или self-hosted)
- Trigger — событие запуска (
on: push,on: pull_request,on: schedule)
3 Этапы нашего CI/CD ▸
- build —
./gradlew build - test —
./gradlew test(unit + slice) - integration-test —
./gradlew test --tests "*IT"(Testcontainers) - build-image —
docker build -t taskflow:$SHA . - push-image —
docker push ghcr.io/user/taskflow:$SHA - deploy (только main) — обновить deployment в k8s
---
Практика: улучшаем CRUD
-
1
.github/workflows/ci.ymlname: CI on: push: branches: [main, develop] pull_request: branches: [main] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: name: Test (unit + slice) runs-on: ubuntu-latest services: postgres: image: postgres:16-alpine env: POSTGRES_DB: taskflow_test POSTGRES_USER: test POSTGRES_PASSWORD: test ports: [5432:5432] options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout uses: actions/checkout@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: 21 cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Run unit + slice tests run: ./gradlew test env: SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/taskflow_test SPRING_DATASOURCE_USERNAME: test SPRING_DATASOURCE_PASSWORD: test - name: Upload coverage if: always() uses: actions/upload-artifact@v4 with: name: coverage path: build/reports/jacoco/test/ integration-test: name: Integration tests (Testcontainers) runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: 21 cache: gradle - name: Run integration tests run: ./gradlew test --tests "*IT" build-and-push: name: Build & Push Docker image runs-on: ubuntu-latest needs: [test, integration-test] permissions: contents: read packages: write steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GHCR if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=sha,prefix= type=ref,event=branch type=ref,event=pr type=raw,value=latest,enable={{is_default_branch}} - name: Build and push uses: docker/build-push-action@v5 with: context: . push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max deploy: name: Deploy to k8s runs-on: ubuntu-latest needs: build-and-push if: github.ref == 'refs/heads/main' && github.event_name == 'push' environment: name: production url: https://taskflow.example.com steps: - name: Checkout uses: actions/checkout@v4 - name: Set up kubectl uses: azure/setup-kubectl@v4 with: version: v1.29.0 - name: Configure kubeconfig run: | mkdir -p ~/.kube echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config - name: Update image in deployment run: | kubectl set image deployment/taskflow \ taskflow=ghcr.io/${{ github.repository }}:${{ github.sha }} \ -n taskflow - name: Wait for rollout run: | kubectl rollout status deployment/taskflow -n taskflow --timeout=5m - name: Verify deployment run: | sleep 10 curl -f https://taskflow.example.com/actuator/health || exit 1 -
2GitHub Secrets (в настройках репо)
KUBECONFIG— base64 от~/.kube/config- (GITHUB_TOKEN — авто)
-
3Branch protection
Settings → Branches → Branch protection rules → main:
- ✅ Require status checks to pass before merging
- ✅ Require branches to be up to date
- ✅ Include administrators
-
4Workflow dispatch (ручной запуск)
on: workflow_dispatch: inputs: environment: description: 'Environment to deploy' required: true type: choice options: [dev, staging, production] -
5Артефакты
- name: Upload JAR uses: actions/upload-artifact@v4 with: name: taskflow-jar path: build/libs/*.jar retention-days: 7 -
6Матрица (Java 21, 23)
strategy: matrix: java: [21, 23] runs-on: ubuntu-latest steps: - uses: actions/setup-java@v4 with: distribution: temurin java-version: ${{ matrix.java }} -
7Badges в README
---
Зачем это на собесе
После урока ты должен уметь ответить на:
kubectl rollout undo deployment/taskflow -n taskflow (или helm rollback).5 вопросов на углубление
Раскрой вопрос и нажми «🤔 Хочу разобрать подробнее» — он попадёт в страницу ответов.
Разбор внутри: build/test на push и доставка в окружение.
Разбор внутри: cache-from type=gha и ускорение сборки image.
Разбор внутри: env, маскирование и запрет печатать секреты.
Разбор внутри: GitOps-подход и прямое применение из pipeline.
Разбор внутри: права GITHUB_TOKEN для публикации image в GHCR.
Готов идти дальше?
Выбери вопросы, которые тебе интересны, и изучи их. Потом — к следующему уроку.
🚀 Перейти к Уроку 27Сначала пройди все секции и выбери хотя бы 1 вопрос
⬅️ Назад к Уроку 25