Hanbit the Developer

AWS와 Docker를 활용한 Spring + React.JS CI/CD 구축: GitHub Actions CI(1) 본문

Back-end

AWS와 Docker를 활용한 Spring + React.JS CI/CD 구축: GitHub Actions CI(1)

hanbikan 2024. 8. 11. 00:55

배경

처음에는 간단하게 EC2에 코드를 푸시하고, 수동으로 빌드하고, 배포를 하려고 했습니다. 수동 배포로 날리는 시간보다 관련 공부를 하고 적용하는 시간이 훨씬 길 것이라고 생각했기 때문입니다. 하지만 다시 생각해보니 수동 배포는 시간을 버리는 것인데 비해, CI/CD 도입 과정은 저에게 도움이 되는 유용한 시간이라고 생각하게 되어 이 여정을 시작하게 되었습니다.

GitHub Actions CI 도입

먼저 github에 PR을 올리면 테스트 코드를 자동으로 돌릴 수 있도록 CI(Continuous Integration)를 도입하기로 했습니다. GitHub Actions에 CI를 도입하기 위해선, .github/workflows/ci.yml 파일을 추가하고 remote에 푸시해야 합니다.

 

다음은 ci.yml의 코드입니다.

name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - develop

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Add secrets to application-local.properties
        run: echo "${{ secrets.APPLICATION_LOCAL }}" >> ./server/src/main/resources/application-local.properties
        
      - name: Add secrets to application-test.properties
        run: echo "${{ secrets.APPLICATION_TEST }}" >> ./server/src/main/resources/application-test.properties
      
      - name: Add secrets to .env
        run: echo "${{ secrets.ENV }}" >> ./server/.env

      - name: Server execute permission for Gradle wrapper
        run: chmod +x ./server/gradlew
      
      - name: Server build
        working-directory: ./server
        run: ./gradlew build -x test

      - name: Server test
        working-directory: ./server
        run: ./gradlew test -i

 

 

1. on 트리거 설정

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - develop
  • push 트리거로 main 브랜치에 푸시가 발생할 때마다 이 워크플로우가 실행됩니다.
  • pull_request 트리거로 develop 브랜치에 대한 PR이 생성되거나 업데이트될 때 실행됩니다.

위 조건을 충족하면 나머지 코드를 실행합니다. 이때 백지 상태의 컴퓨터에서 모든 세팅을 마친 후 스프링 테스트 코드를 돌리는 것이 목적입니다.

2. 코드 체크아웃

steps:
  - name: Checkout code
    uses: actions/checkout@v4
  • GitHub Actions에서는 자주 쓰이는 작업을 actions로 공유합니다. actions/checkout은 repository의 코드를 클론하는 작업을 대신 해줍니다.

3. JDK 설정

  - name: Set up JDK 17
    uses: actions/setup-java@v4
    with:
      distribution: 'zulu'
      java-version: '17'
  • 자바 개발환경을 설정하는 액션입니다.
  • with는 액션에 매개변수를 전달하는 방법입니다. 프로그래밍으로 비유하면 setupJava("zulu", "17");를 호출한 것과 유사합니다.

4. 깃에 추가되지 않은 비밀 파일 설정

저는 application-local.properties에 공개되어선 안 되는 중요한 값들을 넣고 깃에는 추가하지 않고 사용합니다. 앞서 체크아웃 해주었지만 이 비밀 파일은 추가되지 않으므로 수동으로 추가해야 합니다.

  - name: Add secrets to application-local.properties
    run: echo "${{ secrets.APPLICATION_LOCAL }}" >> ./server/src/main/resources/application-local.properties
  • run: 여러 명령줄을 실행합니다.
  • echo hello >> A.txt: A.txt 파일에 "hello"를 추가합니다.
  • ${{ secrets.MY_SECRET }}: repository의 secrets 값을 사용합니다.
  • GitHub Repository Secrets 추가 방법: github repository 웹 사이트 방문 -> Settings -> Security -> Secrets and variables -> Actions -> Secrets -> New repository secret: Name에 MY_SECRET 등 시크릿의 이름을 입력하고 Secret에 값을 입력하면 됩니다.
주의: run에서 여러 줄을 수행하는 경우 아래처럼 run 뒤에 '|'를 붙여야 합니다.
run: |
  echo 1
  echo 2

5. 권한 부여, 빌드, 테스트

  - name: Server execute permission for Gradle wrapper
    run: chmod +x ./server/gradlew

  - name: Server build
    working-directory: ./server
    run: ./gradlew build -x test

  - name: Server test
    working-directory: ./server
    run: ./gradlew test -i
  • chmod +x: gradlew 파일에 실행 권한을 부여합니다.
  • working-directory: 작업 디렉토리를 지정하면 run을 해당 디렉토리에서 수행합니다. gradlew를 다른 디렉토리에서 호출하면 프로젝트 루트 디렉토리가 현재 디렉토리로 인식되어 빌드가 되지 않기 때문에 이렇게 해주었습니다.(대안: ./server/gradlew build --project-dir ./server)
  • ./gradlew build -x test: 빌드를 하되 테스트는 하지 않습니다.
  • ./gradlew test -i: info 수준의 로그 출력으로 테스트를 진행합니다.

 

마무리

CI 덕분에 코드 푸시 전에 테스트를 돌릴 필요가 없어졌습니다! 테스트 코드가 자동으로 실행되니 코드의 신뢰성을 확보할 수 있었고, 자연스럽게 도커나 CD로 확장하고 싶은 욕구가 생겼습니다.