미운 오리 새끼의 우아한 개발자되기

[CI/CD] Github Action 을 이용하여 EC2에 무료로 Spring Boot 프로젝트 빌드, 배포하기 본문

Containerization

[CI/CD] Github Action 을 이용하여 EC2에 무료로 Spring Boot 프로젝트 빌드, 배포하기

Serina_Heo 2022. 12. 29. 14:08

개인 Spring Boot 프로젝트를 하면서 최저 비용으로 개발 서버를 구성하기 위한 방법을 모색중에 처음으로 Github Action을 사용해보았다. 나와 비슷한 상황의 분들도 아래 방법을 고려해보면 좋을 것 같아서 기록으로 남겨본다.

1. AWS Freetier 를 이용하여 EC2 t2.micro 를 생성한다. (이미 Freetier 기간이 지난 계정은 t2.micro 생성 시 과금이 되므로 새로 AWS 계정을 생성한다.)

2. Spring Boot 소스 코드를 Commit 할 때 마다 빌드, 배포를 자동화하고 싶은데 이 때 사용되는 Tool 에는 Jenkins, AWS Code Series 등이 있다. Jenkins의 경우에는 무료 오픈 소스이나, Jenkins web을 띄울 서버가 필요하며 이는 관리포인트가 하나 더 늘어남을 의미한다. AWS Code Series 는 Git 저장소인 Code Commit 와 Build 툴인 Code Build, Deploy 툴인 Code Deploy 삼총사를 일컫는 서비스이다. 세 서비스 모두 Freetier 경우에는 과금이 되지 않는 것으로 나와있는데, Code Build 할 때 Build Artifact를 S3 에 저장하고, 데이터 전송이 일어나기 때문에 이 때 과금이 될 수 있다. 정확히 어느 포인트에서 과금이 발생하는지 알 수 없는 부분이 있어서 나는 무료인 Github Action 을 알아보게 되었다.

3. Github Action 의 경우에는 Github Web Console 의 해당 소스코드 Repository 에서 쉽게 integration 할 수 있다. 

4. 나는 AWS EC2 에 Docker Daemon 을 띄워 Spring Boot 소스를 Docker Image로 만들어 구동하고 있다. 그래서 해당 EC2 에 Java를 깔 필요가 없다. 하나 주의할 점은 Docker Image의 경우에는 Image 를 만드는 서버 종류와 해당 Image 를 실행하는 서버의 종류가 같아야 한다. Mac 에서 만든 docker image를 aws linux 2 (ec2) 에서 돌릴려니까 안되더라...!!!

5. 그래서 Github Action 의 gradle.yml 에 job build run on 을 내가 배포할 EC2 종류와 동일하게 맞춰준다.

6. 배포할 서버의 IP 와 Pem key 의 경우에는 기밀이므로, 반드시 Repository > Setting > Secret 에 등록하여, gradle.yml 에 기밀이 누출되지 않도록 주의한다. 

아래는 내가 사용중인 gradle.yml 이다.

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: Java CI with Gradle

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'

    - name: Build with Gradle
      run: ./gradlew bootJar

    - name: Build Docker image and Push it to ECR
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      run : |
        aws ecr get-login-password --region ap-northeast-2 | sudo docker login --username AWS --password-stdin ${{ secrets.AWS_ECR_REPO_URL }}
        sudo docker build -t hooonk-api -f Dockerfile .
        sudo docker tag hooonk-api:latest ${{ secrets.AWS_ECR_REPO_URL }}:latest
        aws ecr batch-delete-image --region ap-northeast-2 --repository-name hooonk-api-dev --image-ids imageTag=latest
        sudo docker push ${{ secrets.AWS_ECR_REPO_URL }}:latest

    - name : Pull docker image and Deploy it
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.HOST }}
        username: ubuntu
        key: ${{ secrets.KEY }}
        script: |
          cd ~
          echo `pwd`
          sh ./dockerStop.sh
          docker rmi `docker images|awk '$1 ~/hooonk-api/{print$3}'`
          sh ./dockerPull.sh
          sh ./dockerRun.sh
          docker system prune

AWS private ECR 은 Freetier 계정에 500MB 용량만큼은 무료이다. 그래서 ECR 에 있던 latest image 를 삭제하는 Command 가 있다. 

상용에 적용할 때는 비용 보다는 안정성이므로 추구하는 목표를 고려하여 gradle.yml 을 구성하면 되겠다.

 

How to 는 아래 포스팅을 참고하여 진행하였다.

https://velog.io/@rmswjdtn/Spring-Docker-Github-Action-Spring-Boot-자동배포환경-만들기