CI/CD, Spring github action 설정

CICD

CI(Continuous Integration)

한국어로 번역하면 지속적인 통합을 뜻한다. CI를 간단히 설명하면 개발자가 작성한 코드에 대한 빌드, 테스트 과정을 자동화하는 단계이다.
새로운 코드나 코드 변경사항이 정기적으로 빌드, 테스트되어 github와 같은 공유 레포지토리에 통합이 되게 된다. CI를 구성할 경우 여러명의 개발자가 동시에 개발을 진행할 때 서로 충돌하거나 다른사람의 변경사항에 의해 문제가 생기는 경우를 최소화 할 수 있다.
지속적 통합의 목표는 공동 작업, 자동화 및 짧은 피드백 주기를 촉진하여 소프트웨어 빌드와 릴리스에 대한 안정적인 접근 방식을 유지관리하는 것이다.
github action이나 jenkins를 사용할 때로 간단한 예를 들어보자. main에서 분기한 branch에서 작업 후 main으로 PR을 날리게 되면 CI 세팅에 따라 테스트, 빌드가 수행되고 코드 리뷰가 있다면 리뷰까지 통과하면 main에 머지가 되는 것 까지가 CI의 역할이라고 할 수 있다.
“지속”적인 통합 인 만큼 해당 과정은 자주 발생해야한다. 단순한 테스트, 빌드의 자동화가 아닌 짧은 PR 주기를 가지고 자주 통합을 진행하며 오류를 빠르게 잡아낼 수 있는 것이 CI의 장점이라고 생각한다. Commit이나 merge가 길어지면 길어질수록 큰 오류가 나중에 발견될 가능성이 높아진다. 짧은 통합이 가능하도록 해야하기 때문에 각 commit은 적용되었을 때 문제가 없도록 기능 단위로 진행되어야한다.

CD(Continuous Delivery & Deployment)

CI가 코드 병합, 빌드, 테스트 과정을 자동화 했다면 CD는 통합된 코드를 바탕으로 배포를 진행하는 과정이다. Delivery, deployment 두 가지 용어가 있는데 delivery는 코드의 릴리즈버전까지만 체크하고 실제 프로젝션 배포는 수동으로 진행하는 것을 말하고 deployment는 배포 과정까지 자동화한 것을 말한다.

Spring Boot CI/CD 구성(Github Action)

만들어놓은 Spring Boot 프로젝트에 CI/CD를 적용해보았다.
Github Action을 사용하여 코드를 main branch에 푸시하거나 PR을 하면 dockerfile로 도커 이미지를 빌드하고 최종적으로 AWS ECR에 푸시하도록 구성하였다.

Github action - gradle.yml

name: Spring Boot Gradle CI/CD  
  
on:  
  push:  
    branches: [ "main" ]  
  pull_request:  
    branches: [ "main" ]  
  
jobs:  
  build:  
    runs-on: ubuntu-latest  
    permissions:  
      contents: read  
  
    steps:  
      - uses: actions/checkout@v4  
      # AWS ECR 업로드를 위한 credential 설정  
      - name: Configure AWS credentials  
        uses: aws-actions/configure-aws-credentials@v4  
        with:  
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}  
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}  
          aws-region: ${{ vars.AWS_REGION }}  
      # AWS ECR에 로그인  
      - name: Login to Amazon ECR  
        id: login-ecr  
        uses: aws-actions/amazon-ecr-login@v2  
      - name: Set up JDK 21  
        uses: actions/setup-java@v4  
        with:  
          java-version: '21'  
          distribution: 'temurin'  
      - name: Run chmod to make gradlew executable  
        # 없으면 build에서 권한문제 발생  
        run: chmod +x ./gradlew  
      - name: Setup Gradle  
        uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0  
        # 빌드  
      - name: Build with Gradle Wrapper  
        run: ./gradlew build  
      - name: Build, tag, and push the image to Amazon ECR  
        id: build-image  
        env:   
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} # AWS ECR 로그인 시 받은 registry 정보  
          ECR_REPOSITORY: ${{ secrets.REPO_NAME }}  
          IMAGE_TAG: latest  
        # 미리 만들어놓은 Dockerfile로 이미지 빌드 후 ECR에 push        
        run: |  
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./   
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG 

중간에 변수처럼 사용한 secrets.AWS_ACCESS_KEY_IDvars.AWS_REGION는 아래 사진과 같이 github repo -> settings -> secrets and variables 에서 설정할 수 있다.

이미지 빌드시에 사용한 dockerfile은 아래와 같다.
Dockerfile

FROM amazoncorretto:21-alpine  
ARG JAR_FILE=build/libs/*.jar  
COPY ${JAR_FILE} app.jar  
ENTRYPOINT ["java","-jar","/app.jar","-Dspring.profiles.active=prod"]

세팅을 완료한 후 github action 탭을 보면 빌드가 진행되는 것을 볼 수 있다.

모든 작업이 완료되면 아래와 같이 초록색 체크표시로 바뀌며 정상적으로 모든 작업이 수행되었음을 알려준다.

최종적으로 AWS ECR를 확인했을 때 이미지가 잘 빌드되어 올라와 있는 것을 확인할 수 있었다.