Github Action 적용

민선규·2024년 7월 12일

기타

목록 보기
14/16
post-thumbnail

이 전 프로젝트에서는 CI/CD를 구축하기 위해 Jenkins와 Github Action 중에 무엇을 사용할 지 많이 고민했었고 결국 Jenkins를 사용해서 구축했었다.

새로 시작한 프로젝트에서는 Github Action으로 구축을 해보았고 그 과정을 정리해보겠다. 먼저 간단하게 Jenkins와 Github Action를 정리해보겠습니다.

Jenkins : 별도의 서버가 필요, 고도의 커스터마이징 가능, 무한한 확장성, 강력한 커뮤니티와 다양한 온라인 리소스 등

Github Action : 별도의 서버가 필요 X, GitHub 환경 내에서 제한된 확장성, GitHub 공식 지원 및 포럼 제공 등

Workflow

목표

간단하게 아키텍처를 설명해보겠습니다.

현재 AWS에 EC2와 ECR을 생성한 상태이고 EC2에서는 Docker를 사용해서 Spring이 돌아가고 있습니다.

그래서 Workflow를 작성할 때 레포지토리에서 코드를 가져와서 빌드를 하고 빌드한 결과를 이미지로 생성하고 이미지를 ECR에 저장한 뒤에 EC2에서 ECR에 있는 이미지를 가져와서 컨테이너로 실행하는 것이 목표입니다.

다음으로는 각 단계별 코드와 내용을 설명해보겠습니다.

Checkout repository

      - name: Checkout repository
        uses: actions/checkout@v4

이 단계에서는 현재 레포지토리의 코드를 체크아웃합니다. GitHub Actions에서 Workflow가 실행될 때, 이 단계가 있어야 이후 단계에서 코드베이스에 접근할 수 있습니다.

Set up JDK 17

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

JDK 17을 설치합니다. 이 단계는 애플리케이션을 빌드하고 실행하는 데 필요한 Java 개발 키트를 설정합니다.

Create application.yml

      - name: Create application.yml
        run: |
          mkdir -p be/src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" > be/src/main/resources/application.yml     

application.yml 파일을 생성합니다. 이 파일은 애플리케이션의 설정 파일로, GitHub Secrets에 저장된 값을 사용하여 생성합니다. 보안 문제로 인해 민감한 설정 정보는 GitHub Secrets에 저장하고 여기서 사용합니다.

Grant execute permission for gradlew

      - name: Grant execute permission for gradlew
        run: chmod +x be/gradlew

gradlew 파일에 실행 권한을 부여합니다. 이를 실행 가능하게 만들어야 빌드를 진행할 수 있습니다.

Build with Gradle

      - name: Build with Gradle
        run: cd be && ./gradlew build

Gradle을 사용하여 애플리케이션을 빌드합니다. 이 단계에서는 소스 코드를 컴파일하고, 테스트를 실행하며, 최종적으로 패키징된 JAR 파일을 생성합니다.

Configure AWS credentials

      - 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: ${{ secrets.AWS_REGION }}

AWS 자격 증명을 설정합니다. 이 단계는 AWS CLI를 사용하여 ECR에 로그인하고 이미지를 푸시하기 위해 필요한 AWS 자격 증명을 설정합니다. 자격 증명은 GitHub Secrets에 저장되어 있습니다.

Login to Amazon ECR

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

Amazon ECR에 로그인합니다. ECR은 Docker 이미지를 저장하는 AWS 서비스입니다. 이 단계는 AWS CLI를 사용하여 ECR에 로그인합니다

Build and push Docker image to ECR

      - name: Build and push Docker image to ECR
        env:
          ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY  }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPOSITORY }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          cd be && docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

Docker 이미지를 빌드하고 ECR에 푸시합니다. 이 단계에서는 애플리케이션을 Docker 이미지로 패키징하고, 이를 ECR에 푸시합니다. IMAGE_TAG는 현재 커밋의 SHA로 설정하여 고유하게 식별할 수 있습니다.

Set up SSH key

      - name: Set up SSH key
        uses: webfactory/ssh-agent@v0.5.3
        with:
          ssh-private-key: ${{ secrets.EC2_KEY }}

EC2 인스턴스에 SSH로 접속하기 위해 SSH 키를 설정합니다. GitHub Secrets에 저장된 개인 키를 사용합니다.

Install SSH client

      - name: Install SSH client
        run: sudo apt-get install openssh-client -y

SSH 클라이언트를 설치합니다. SSH를 통해 EC2 인스턴스에 접속하기 위해 필요합니다.

Add host key to known hosts

      - name: Add host key to known hosts
        run: |
          mkdir -p ~/.ssh
          touch ~/.ssh/known_hosts
          ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts        

EC2 호스트 키를 known_hosts 파일에 추가하여 SSH 접속 시 호스트 키 확인을 자동으로 처리합니다.

Deploy to EC2 via SSH

      - name: Deploy to EC2 via SSH
        env:
          EC2_HOST: ${{ secrets.EC2_HOST }}
          ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY  }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          ssh -o StrictHostKeyChecking=no ubuntu@${EC2_HOST} << EOF
            echo "Logging into ECR..."
            aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
            echo "Stopping and removing existing container..."
            docker stop sharefit-server || true
            docker rm sharefit-server || true
            echo "Removing Docker image..."
            docker images -a | grep "sharefit" | awk '{print \$3}' | xargs docker rmi -f || true
            echo "Pulling Docker image..."
            docker pull $ECR_REGISTRY/sharefit:$IMAGE_TAG
            echo "Running new container..."
            docker run --restart always --name sharefit-server -d -p 8080:8080 $ECR_REGISTRY/sharefit:$IMAGE_TAG
          EOF

ECR에 로그인하고, 기존 컨테이너를 중지 및 제거하고 이미지를 삭제한 후 최신 이미지를 가져와 새로운 컨테이너를 실행합니다.

시크릿 값

APPLICATION_YML : Spring Boot 애플리케이션의 설정 파일입니다.

AWS_ACCESS_KEY_ID :AWS 계정의 액세스 키 ID입니다.

AWS_SECRET_ACCESS_KEY : AWS 계정의 비밀 액세스 키입니다.

AWS_REGION : AWS 서비스가 실행되는 리전입니다.

AWS_ECR_REGISTRY : AWS ECR 레지스트리 URI입니다.

AWS_ECR_REPOSITORY : AWS ECR 내의 저장소 이름입니다.

EC2_HOST : AWS EC2 인스턴스의 공인 도메인 이름 또는 IP 주소입니다.

EC2_KEY : EC2 인스턴스에 접속하기 위한 SSH 키입니다. 프라이빗 키 내용을 넣어야 합니다.

전체

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Create application.yml
        run: |
          mkdir -p be/src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" > be/src/main/resources/application.yml         
      - name: Grant execute permission for gradlew
        run: chmod +x be/gradlew
        
      - name: Build with Gradle
        run: cd be && ./gradlew build
        
      - 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: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push Docker image to ECR
        env:
          ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY  }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPOSITORY }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          cd be && docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
      - name: Set up SSH key
        uses: webfactory/ssh-agent@v0.5.3
        with:
          ssh-private-key: ${{ secrets.EC2_KEY }}

      - name: Install SSH client
        run: sudo apt-get install openssh-client -y
        
      - name: Add host key to known hosts
        run: |
          mkdir -p ~/.ssh
          touch ~/.ssh/known_hosts
          ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts        
          
      - name: Deploy to EC2 via SSH
        env:
          EC2_HOST: ${{ secrets.EC2_HOST }}
          ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY  }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          ssh -o StrictHostKeyChecking=no ubuntu@${EC2_HOST} << EOF
            echo "Logging into ECR..."
            aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
            echo "Stopping and removing existing container..."
            docker stop sharefit-server || true
            docker rm sharefit-server || true
            echo "Removing Docker image..."
            docker images -a | grep "sharefit" | awk '{print \$3}' | xargs docker rmi -f || true
            echo "Pulling Docker image..."
            docker pull $ECR_REGISTRY/sharefit:$IMAGE_TAG
            echo "Running new container..."
            docker run --restart always --name sharefit-server -d -p 8080:8080 $ECR_REGISTRY/sharefit:$IMAGE_TAG
          EOF

0개의 댓글