SpringBoot + GitHub Actions CI/CD 완벽 구성 & 문제 해결

SpringBoot 애플리케이션에 GitHub Actions를 활용한 CI/CD 파이프라인을 구축하고, 실제 운영 환경에서 발생하는 문제를 해결하는 방법을 단계별로 설명합니다. 이 가이드는 JDK 설치부터 클라우드 배포까지 전체 워크플로우를 다루며, 실패 사례별 트러블슈팅 기법을 포함합니다.

튜토리얼: SpringBoot CI/CD 기본 구성

1. GitHub 리포지토리 연결 및 기본 Workflow 생성

  1. SpringBoot 프로젝트를 GitHub에 업로드합니다.
    git init
    git add .
    git commit -m "Initial commit"
    git branch -M main
    git remote add origin https://github.com/<your-id>/<repo-name>.git
    git push -u origin main
    
  2. .github/workflows/springboot-ci-cd.yml 파일을 생성합니다.

2. 기본 Workflow YAML 구성

name: SpringBoot CI/CD

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'
    - name: Build with Gradle
      run: ./gradlew build
    - name: Build Docker image
      run: |
        docker build -t my-springboot-app:latest .
        docker tag my-springboot-app:latest \
          $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-springboot-app:latest
    - name: Push to ECR
      run: |
        aws ecr get-login-password --region $AWS_REGION | \
          docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
        docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-springboot-app:latest
      env:
        AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
        AWS_REGION: ${{ secrets.AWS_REGION }}

: Maven 사용 시 ./mvnw clean package로 변경합니다. Dockerfile이 프로젝트 루트에 위치해야 합니다.

3. GitHub Secrets 설정

  • AWS 계정의 AWS_ACCOUNT_IDAWS_REGION을 Secrets에 등록
  • Azure App Service 사용 시 AZURE_WEBAPP_NAMEAZURE_CREDENTIALS 추가

트러블슈팅: CI/CD 실패 주요 사례

1. 빌드 실패 사례

  • Java 버전 불일치:
    Error: Java version "1.8.0_292" is not supported by Gradle
    
    setup-java 액션의 java-version을 프로젝트 요구사항에 맞춰 수정
  • Gradle wrapper 미포함:
    /bin/sh: ./gradlew: No such file or directory
    
    gradlew 바이너리 포함 여부 확인 (Gradle wrapper 사용 필수)
  • 의존성 다운로드 실패:
    Could not transfer artifact com.example:library:jar:1.0.0
    
    → 방화벽 설정 확인 또는 --no-daemon 플래그 추가

2. 배포 실패 사례

  • IAM 권한 문제:
    User is not authorized to perform ecr:PutImage
    
    → AWS ECR 접근 권한이 있는 IAM 역할 생성 후 Secrets에 자격 증명 등록
  • Docker 태그 충돌:
    manifest for my-springboot-app:latest not found
    
    docker pull로 기존 이미지 삭제 후 재시도
  • Helm chart 오류:
    failed: Invalid value: : invalid type for io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext
    
    → Helm 차트 버전 호환성 확인 및 helm dependency update 실행

3. 캐시 미적용 문제

GET https://jcenter.bintray.com/...

→ Gradle/Maven 의존성 캐시 추가:

- name: Cache Gradle packages
  uses: actions/cache@v3
  with:
    path: ~/.gradle/caches
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

문제 해결: 단계별 검증 방법

1. 로컬에서 Workflow 테스트

act CLI로 로컬에서 워크플로우를 시뮬레이션합니다.

brew install nektos/act/act
act --pull-request --pull-request-head-sha=$(git rev-parse HEAD)

2. 디버그 로그 활성화

워크플로우 단계에 set -x 추가:

- name: Debug Docker build
  run: |
    set -x
    docker build -t my-springboot-app:latest .

3. Self-hosted Runner 로그 분석

SSH로 러너 서버에 접속해 직접 로그 확인:

journalctl -u github-actions-runner.service -f

4. 품질 검증 도구 연동

  • JUnit 테스트 결과: gradle test jacocoTestReport 추가
  • SonarQube 분석:
- name: Run SonarQube Scanner
  uses: SonarSource/sonarqube-scan-action@master
  with:
    projectKey: my-springboot-project
    projectName: SpringBoot Demo

참고 문서

주의사항: 프로덕션 환경에서는 main 브랜치 외에 develop 브랜치에 대한 별도 워크플로우를 구성하는 것이 안전합니다. 이미지 태그 전략으로는 SHA 기반 태그를 권장합니다.