Github Actions CI + CodeDeploy로 CI/CD 구현하기

Bluewind·2022년 5월 6일
5

서버 셋팅

목록 보기
2/6
post-thumbnail

CI 도구로 Github Actions를 사용하고 CD로는 AWS CodeDeploy를 사용하여 Spring Gradle 프로젝트 자동 배포를 구현해보겠습니다.
진행하고자 하는 아키텍쳐는 위의 그림과 같습니다.

  1. Github에 push 시, Github Action이 자동으로 실행 (build하여 jar 생성)
  2. jar 와 shell script 파일을 압축하여 S3로 upload.
  3. EC2에 설치되어 있는 CodeDeploy Agent가 S3에 업로드 된 zip 파일을 가져와서 배포를 진행.
  4. CodeDeploy Agent는 S3에서 zip 파일을 내려받고, appspec.yml을 읽어서 설정된 스크립트 파일을 실행시키면서 배포.

GitHub Actions 설정

배포하고자 하는 Github 페이지의 'Actions'에 들어가서 'set up a workflow yourself'를 클릭해보겠습니다.

아래와 같이 설정해야 하는 파일의 예시를 친절하게 설명해주고 있습니다.

이 예시에서 약간만 바꾸어서 진행해 보겠습니다.
의미는 주석으로 달아놓았으니 참고하시면 좋을 것 같습니다.

# workflow의 이름
name: github-action-test

# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정
on:
  # main branch에 대한 push 나 pull request 이벤트를 트리거로 지정
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  # 수동으로 해당 workflow 실행 지정
  workflow_dispatch:

# workflow는 한개 이상의 job을 가지며, 각 job은 여러 step에 따라 단계를 나눌 수 있습니다.
jobs:
  build:
    # 해당 workflow를 어떤 OS 환경에서 실행할 것인지 지정
    runs-on: ubuntu-latest

    # step은 작업의 일부로 실행될 일련의 작업을 나타냅니다.
    steps:
      # 작업에서 액세스할 수 있도록 $GITHUB_WORKSPACE에서 저장소를 체크아웃합니다.
      - name: Checkout
        uses: actions/checkout@v3

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash
      
      - name: Build with Gradle
        run: ./gradlew build
        shell: bash

그리고 'Start commit'을 누르면 아래와 같이 새로운 폴더와 파일이 생성된 것을 볼 수 있습니다.

S3 upload 설정

방금 생성한 main.yml에 들어가서 추가적으로 설정해 주겠습니다.

...
# 현재 스크립트에서 사용할 환경변수를 정의하여 사용
env:
  S3_BUCKET_NAME: S3 버킷 이름
  AWS_REGION: ap-northeast-2

jobs:
  build:
    ...
    steps:
      ...
      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}
      
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip
  • $GITHUB_SHA : Github Actions에서 제공하는 여러 기본 환경변수 중 하나이며, 현재 workflow를 실행시키는 커밋의 해쉬값을 나타냅니다.
  • ${{ secrets.~~~ }} : 보안을 위하여 밑에서 설정합니다.

위와 같이 yml파일을 설정한 다음, 해당 프로젝트의 GitHub 페이지로 돌아가겠습니다.
Setting > Secrets > Actions > New repository secret

위에서 설정하지 않았던 아래의 두 엑세스 키를 설정합니다.

- AWS_ACCESS_KEY_ID : IAM 사용자 엑세스 키 ID
- AWS_SECRET_ACCESS_KEY : IAM 사용자 Secret 엑세스 키

위와 같이 설정하였으면 이제 commit 후 push 해보겠습니다.

GitHub 페이지의 Actions 탭에서 위와 같이 build에 성공한 것을 볼 수 있습니다.

AWS S3 에도 성공적으로 zip 파일이 업로드 된 것을 볼 수 있습니다!


CodeDeploy Agent 설치

배포하고자 하는 서버에 접근하여 CodeDeploy Agent를 설치하도록 하겠습니다.

$ sudo yum update
$ sudo yum install ruby
$ sudo yum install wget
$ cd /home/ec2-user
$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto

sudo service codedeploy-agent status 명령어로 CodeDeploy Agent가 실행되고 있는지 확인합니다.

CodeDeploy 생성

AWS Developer > CodeDeploy에 진입하여 새로운 CodeDeploy를 생성하겠습니다.

배포 그룹을 생성합니다.

스크립트 추가

appspec.yml 파일을 작성하여 각 배포 단계에서 어떤 스크립트 파일을 실행할 것인지 설정하겠습니다.
프로젝트 최상단에 appspec.yml 파일을 생성합니다.

version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ec2-user/action
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  ApplicationStart:
    - location: scripts/deploy.sh
      timeout: 60
      runas: ec2-user

최종 프로젝트 main.yml은 아래와 같습니다.

name: github-action-test

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

  workflow_dispatch:

env:
  S3_BUCKET_NAME: S3 버킷 이름
  AWS_REGION: ap-northeast-2
  CODEDEPLOY_NAME: CodeDeploy 이름
  CODEDEPLOY_GROUP: CodeDeploy 배포 그룹 이름

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash
      
      - name: Build with Gradle
        run: ./gradlew build
        shell: bash
        
      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}
      
      - name: Upload to S3
        run: aws s3 cp --region ${{ env.AWS_REGION }} ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip

      - name: Code Deploy
        run: aws deploy create-deployment --application-name $CODEDEPLOY_NAME --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name $CODEDEPLOY_GROUP --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$GITHUB_SHA.zip

deploy.sh 파일은 아래와 같습니다.

#!/bin/bash

BUILD_JAR=$(ls /home/ec2-user/action/build/libs/*.jar)
JAR_NAME=$(basename $BUILD_JAR)
echo ">>> build 파일명: $JAR_NAME" >> /home/ec2-user/action/deploy.log

echo ">>> build 파일 복사" >> /home/ec2-user/action/deploy.log
DEPLOY_PATH=/home/ec2-user/action/
cp $BUILD_JAR $DEPLOY_PATH

echo ">>> 현재 실행중인 애플리케이션 pid 확인" >> /home/ec2-user/action/deploy.log
CURRENT_PID=$(pgrep -f $JAR_NAME)

if [ -z $CURRENT_PID ]
then
  echo ">>> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ec2-user/action/deploy.log
else
  echo ">>> kill -15 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo ">>> DEPLOY_JAR 배포"    >> /home/ec2-user/action/deploy.log
nohup java -jar $DEPLOY_JAR >> /home/ec2-user/deploy.log 2>/home/ec2-user/action/deploy_err.log &

배포 테스트

위의 변경사항을 저장한 뒤 push 하여 배포 테스트를 해보겠습니다.

GitHub Actions와 CodeDeploy는 성공하였습니다.
하지만 EC2에 java가 설치되어있지 않아서 배포가 실패했네요.

저는 java 11 버전으로 프로젝트를 빌드하였기 때문에 java 11 버전을 설치하겠습니다.

sudo yum install java-11-amazon-corretto.x86_64

배포까지 성공했습니다...!


CodeDeploy 에러 해결법 🐞

AWS Developer의 CodeDeploy 페이지에서 아래와 같이 오류 코드가 명시되지 않는 경우가 있습니다. 이럴땐 해당 서버로 접속해서 로그를 확인하면 됩니다.

cat /var/log/aws/codedeploy-agent/codedeploy-agent.log

로그를 확인하면 아래와 같이 오류 로그가 뜬 것을 볼 수 있습니다.

InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials - please check if this instance was started with an IAM instance profile

해결방법

EC2의 인스턴스에서 IAM 역할을 연결하지 않아서 생기는 문제였습니다.

위와 같이 연결해 준 뒤 해당 인스턴스 터미널에서 아래의 명령어로 서비스를 재시작 해주면 해결됩니다.

sudo service codedeploy-agent restart

Nginx를 통한 무중단 배포 구현에서 이어집니다.


참조 📖

profile
NO EFFORT, NO RESULTS

0개의 댓글