GitHub Actions으로 CI/CD

chancehee·2024년 9월 14일

DevOps

목록 보기
2/2

[ 개념 ]

공식홈페이지 소개에 따르면, GitHub Actions는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD(연속 통합 및 지속적인 업데이트)플랫폼이라고 한다.

즉, Git Repository에 pull request 또는 issue 생성 등 특정한 event가 발생했을 때, 자동으로 테스트를 수행하거나 병합된 코드를 자동으로 배포하는 워크플로를 만들 수 있다.

[ 목적 ]

만약 gradle, docker, ec2를 쓴다면
./gradlew clean build
docker build 이미지
docker push 도커허브
aws 접속
docker stop 컨테이너
docker pull 이미지
docker run 컨테이너

어떤 도구를 사용하든 코드를 통합하고 배포하는 노력이 필요하다.
그리고 수동으로 관리하는 것은 너무 귀찮다.

Jenkins, ArgoCD 등 다양한 CI/CD 자동화 도구 들이 있지만
쉽고 빠르게 해커톤 프로젝트에 CI/CD를 적용하기 위해서, GitHub Actions를 사용하기로 결정했다.

[ 적용 ]

name: CI-CD

on:
  push:
    branches: [ "main" ]

env:
  IMAGE_NAME: wtw-spring
  CONTAINER_NAME: wtw-spring-container

jobs:
  build-docker-image-and-push:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    # 1. Java 17 세팅
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'

    # 2. Spring Boot 환경변수 할당
    - name: Retrieve application properties
      env:
        APPLICATION_PROPERTIES: ${{ secrets.APPLICATION_PROPERTIES }} # 시크릿에 등록시킨 application.yml
      run: |
        touch ./src/main/resources/application.yml
        echo "${APPLICATION_PROPERTIES}" > ./src/main/resources/application.yml

    # 3. Spring Boot 애플리케이션 빌드
    - name: Build with Gradle
      run: ./gradlew clean build -x test

    # 4. DockerHub 로그인
    - name: DockerHub login
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_PASSWORD }}

    # 5. Docker 이미지 빌드
    - name: Build Docker image
      run: docker build -t chancehee/${{ env.IMAGE_NAME }}:latest .

    # 6. DockerHub 이미지 푸시
    - name: Push Docker image to DockerHub
      run: docker push chancehee/${{ env.IMAGE_NAME }}:latest

  pull-and-docker-deploy:
    runs-on: self-hosted
    needs: build-docker-image-and-push
    steps:
    - name: Pull Docker image from DockerHub
      run: sudo docker pull chancehee/${{ env.IMAGE_NAME }}:latest

    # 7. 기존 컨테이너 중지 및 삭제
    - name: Stop and remove existing container
      run: |
        if [ "$(sudo docker ps -q -f name=${{ env.CONTAINER_NAME }})" ]; then
          sudo docker stop ${{ env.CONTAINER_NAME }}
          sudo docker rm ${{ env.CONTAINER_NAME }}
        fi

    # 8. 새로운 컨테이너 실행
    - name: Run new Docker container
      run: |
        sudo docker run -d --name ${{ env.CONTAINER_NAME }} --network my-network -p 8080:8080 chancehee/${{ env.IMAGE_NAME }}:latest

    # 9. 오래된 도커 이미지 제거
    - name: Remove old Docker images
      run: |
        sudo docker image prune -f --filter "until=1h"
    

위 코드를 간단하게 해석하면 아래와 같다.

main 브랜치에 push event가 발생하면 workflow가 실행된다.
(on은 if문과 같은 조건문이라고 생각하면 된다.)

Job은 크게 2가지로 구성했다.
1. Docker Image Build & Docker Image Push
2. Docker Image Pull & Run Docker Container on EC2

[ CD ]

GitHub Actions를 사용할 때, 드는 의문이 있었다.
CD 작업은 어떻게 해야 하지?

찾아본 방법은 여러 가지가 있었다.

대표적으로 3가지 방법이 일반적이었다.
1. EC2 인스턴스 내에서 CD 작업을 하는 스크립트 작성 후 특정 시간 혹은 WebHooks 기반 실행
2. Jenkins와 같은 CD 도구 사용
3. GitHub Actions Runner를 이용한 인스턴스 접속 후 명령어 실행

필자는 설정이 가장 쉽고 빠르게 적용할 수 있는 3번 방법을 선택했다.

[ GitHub Actions Runner ]

Runner는 자동화된 작업을 처리하는 환경을 의미한다.
위에서 main 브랜치 event를 감지하고 docker image 파일을 만들고 EC2 인스턴스에서 명령어를 실행하는 것 모두 Runner 환경 위에서 동작한 것이다.

Runner도 크게 2가지 종류가 있었다.

  1. Hosted Runner
    • GitHub에서 제공하는 미리 구성된 환경에서 워크플로우 실행
    • 사용자는 별도로 서버를 구성할 필요가 없고, GitHub에서 관리 및 업데이트한다.
    • 비용 제한 존재 (public repo라면 무료 사용 가능)
    • ex) runs-on: ubuntu-latest
  2. Self-Hosted Runner
    • 사용자가 직접 서버를 관리하며, 원하는 환경에서 워크플로우를 실행할 수 있다.
    • 더 높은 유연성과 제어가 가능하지만, 사용자가 서버를 유지 관리해야 한다.

결론적으로 private repo를 사용하고 비용 절감을 원하는 나는 2번 방식을 사용했다.

Self-Hosted Runner 사용하려면 아래 순서로 작업을 수행하면 된다.

  1. Runner를 실행시킬 서버 준비 (필자의 경우에는 EC2 인스턴스)
  2. EC2 인스턴스에서 Runner 설치 (Linux, Windows, Mac OS 를 지원한다.)
  3. EC2 인스턴스에서 Runner 실행

정상 상태라면 아래와 같이 idle 상태를 확인 할 수 있다.

[ 결론 ]

Jenkins와 같은 CI/CD 도구 너무 좋다.
근데 설정 귀찮다.
권장 RAM도 4GB임..

GitHub Actions 설정 쉽다.
CI/CD Jar 파일만 EC2에 던져도 되고, EC2에서 Git Pull 해도 되고.. (다양한 방법 존재)
근데 Docker가 제일 편한 것 같다. (DB 등 여러 컨테이너랑 같이 쓸 때)

참고자료

0개의 댓글