[CI/CD 구축] Github Action, S3, CodeDeploy 이용해서 CI/CD 파이프라인 구축하기

hyelim·2023년 9월 23일
2
post-thumbnail

아키텍쳐

VPC 내부에 인스턴스만 위치 시켰는데 맞는지는 모르겠다,, 조금 더 aws를 공부해보고 수정해보겠다!!!!

  1. 특정 브랜치에 Push, 또는 Merge 동작을 수행한다.
  2. Github Actions에서 push 혹은 merge를 감지하고 정해진 Action을 수행한다.
  3. Update된 코드를 바탕으로 Build와 (Test) 를 수행한다.

    아직 테스트 코드를 작성하지 않아서 test 는 제외하고 build 만 진행했다.
    CI 의 목적이 Continuous Integration 이라 지속적으로 테스트코드도 검사해가며 통합해야하지만 테스트 코드가 아직 준비되지 않았기에 임시적으로 제외했다 😇

  4. 코드를 압축하여 zip파일을 생성한다.
  5. S3에 zip파일을 업로드한다.
  6. Code Deploy에 배포를 요청한다. - main.yml 에서 수행
  7. S3로부터 zip파일을 받는다 - appspec.yml 에서 수행
  8. 지정한 EC2 인스턴스에 애플리케이션 파일을 전달한다. - appspec.yml 에서 수행
  9. EC2 인스턴스에서 쉘 스크립트를 실행함으로써 배포를 완료한다. - deploy.sh 에서 수행

1. IAM 설정

1-1 유저 생성

Github Action(aws 외부) 에서 s3와 code deploy 에 접근가능하게 하도록 유저 생성

step1. IAM > 사용자 > 사용자 추가 버튼 클릭

step2. 사용자 세부 정보 지정

step3. 권한설정

step4. 사용자>보안자격증명>엑세스 키 발급 : 엑세스키 및 시크릿 키 복사 후 깃허브 시크릿 변수로 등록

1-2. EC2(aws 내부) 역할생성

이전에 만들었던 사용자는 AWS 서비스 외에 사용할 수 있는 권한이고, 역할은 AWS 서비스에만 할당할 수 있는 권한이다. 이번 스탭에서는 EC2 에서 사용할 권한이기에 역할을 이용한다.

EC2 가 CodeDeploy 를 연동받을 수 있게 하는 권한이므로 아래와 같이 정책을 선택한다

1-3. CodeDeploy 역할 생성

1-4. EC2 역할 부여

1-2에서 생성한 역할로 인스턴스 IAM 역할 수정

2. CodeDeploy

CodeDeploy 하기 전에 ec2에서 s3 에 업로드하기 위한 버킷을 미리 생성

2-1. S3 버킷 생성

S3: 일종의 파일 서버, 순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할

S3 에 저장된 Build 파일은 이후 AWS 의 CodeDeploy 에서 배포할 파일로 가져가도록 구성할 예정

step1. Amazon> S3>버킷> 버킷 만들기 클릭

step2. 버킷 이름 및 AWS 리전 설정

step3. 명령어로 CodeDeploy Application 생성

step4. S3 에 파일 업로드 후 아래 명령어 입력시 자동으로 해당 파일 업로드 진행

aws deploy push --application-name beginner-app --s3-location s3://awsbeginner/webapp.zip --ignore-hidden-files

step5. CodeDeploy 배포 그룹 생성 후 CodeDeploy 역할 등록

3. Github Action, S3, CodeDeploy 연동

IAM 과 S3, CodeDeploy 에 대해 알아봤으면 이제 Gihub Action 과 S3, CodeDeploy 를 연동해보자!

mkdir ~/app/step2 && mkdir ~/app/step2/zip 에 Github Action 의 빌드가 끝나면 S3 에 zip 파일이 전송되고, 이 zip 파일은 이 경로에 복사되어 압축을 풀 예정

Github Action 의 설정은 main.yml로, AWS CodeDeploy 설정은 appspec.yml 로 진행

main.yml

name: Build and Deploy to EC2

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

env:
  PROJECT_NAME: gradwork
  BUCKET_NAME: graduation-work-ci-cd-bucket
  CODE_DEPLOY_APP_NAME: gradwork_ci_cd
  DEPLOYMENT_GROUP_NAME: gradwork_instance

jobs:
  deploy:
    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: Grand execute permission for gradlew
        run: chmod +x gradlew

      - name: Build 
        run: ./gradlew clean -x test build
        
      - name: Generate deployment package
        run: |
          mkdir -p before-deploy/
          cp scripts/*.sh before-deploy/
          cp appspec.yml before-deploy/
          cp build/libs/*.jar before-deploy/
          cd before-deploy && zip -r before-deploy *
          cd ../ && mkdir -p deploy
          mv before-deploy/before-deploy.zip deploy/$PROJECT_NAME.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_PRIVATE_ACCESS_KEY}}
          aws-region: ap-northeast-2

      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./deploy/$PROJECT_NAME.zip s3://$BUCKET_NAME/$PROJECT_NAME/$PROJECT_NAME.zip

      - name: Code Deploy to EC2 instance
        run: aws deploy create-deployment
                --application-name $CODE_DEPLOY_APP_NAME
                --deployment-config-name CodeDeployDefault.AllAtOnce
                --deployment-group-name $DEPLOYMENT_GROUP_NAME
                --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$PROJECT_NAME.zip

appspec.yml

version: 0.0
os: linux

files:
  - source: /
    destination: /home/ubuntu/app/step2/zip/
    
permissions:
  - object: /home/ubuntu/app/step2/zip/
    owner: ubuntu
    group: ubuntu
hooks:
  AfterInstall:
    - location: ./deploy.sh
      timeout: 60
      runas: ubuntu

deploy.sh

#!/usr/bin/env bash

REPOSITORY=/home/ubuntu/app/step2
cd $REPOSITORY

JAR_NAME=$(ls $REPOSITORY/zip | grep 'SNAPSHOT.jar' | tail -n 1)
JAR_PATH=$REPOSITORY/zip/$JAR_NAME

CURRENT_PID=$(lsof -t -i:8080)
echo "현재 구동중인 애플리케이션 pid: $CURRENT_PID"

if [ -z $CURRENT_PID ]
then
  echo "> 종료할 애플리케이션이 없습니다."
else
  echo "> kill -15 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

echo "> 새 애플리케이션 배포"
echo ">JAR Path: $JAR_PATH"

echo ">JAR_PATH 에 실행권한 추가"
chmod +x $JAR_PATH

echo "> Deploy - $JAR_PATH"
nohup java -jar -Dspring.config.location=classpath:/application.yml,/home/ubuntu/app/application-oauth.yml,/home/ubuntu/app/application-prod.yml,/home/ubuntu/app/application-aws.yml,/home/ubuntu/app/application-api.yml,/home/ubuntu/app/application-jwt.yml $JAR_PATH > $REPOSITORY/nohup.out 2>&1 &

4. 트러블 슈팅

deploy.sh 에서 현재 열린 프로세스의 아이디를 잡고 해당 포트를 죽여야하는데 APP_NAME 에 해당하는 프로세스가 잡히지 않았고, 그냥 8080포트를 이용하는 것이기에 해당 포트의 pid 를 가져와 꺼주는 형식으로 해줬다.

code deploy 오류 확인 방법

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

열려있는 포트 확인 방법

netstat -tnlp
lsof -i -nP

AWS EC2 프리티어에서 메모리 부족현상 해결방법

빌드를 하다가 메모리 부족으로 서버가 뻗었다.
그럴때는 아래의 방법을 이용해보자!!

스왑 파일을 사용하여 Amazon EC2 인스턴스의 스왑 공간으로 메모리 할당

EC2 gradle build 시 무한 로딩 오류(메모리 문제)

참고

https://rachel0115.tistory.com/entry/Github-Actions%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-EC2-S3-CodeDeploy
https://wikidocs.net/198082

리눅스 로컬서버 열린 포트 확인 - 제타위키

profile
기록용

0개의 댓글