AWS CodeDepoly, Github Actions를 이용한 배포자동화

이호석·2022년 10월 12일
0

기존 AWS EC2를 이용해서 배포했던 스프링부트 프로젝트가 있는데 이 프로젝트에 CI & CD를 적용하려고 한다. Travis CI를 사용했던 경험이 있지만 유료이기도 하며(가입시 일정 크레딧을 주는데 전부 사용하면 요금을 내야한다), 새로운 경험을 쌓고 싶어서 AWS CodeDepoly, Github Actions를 사용해보기로 했다.

이번 포스트에서 사용하는 것들

  • Github Actions
  • AWS EC2(여기서 생성은 다루지 않음)
  • AWS S3
  • AWS CodeDeploy

Github Actions

먼저 Github Actions에 들어간다.

그다음 Or skip this and set up a workflow yourself을 눌러준다.

name : Ai parrot

on:
  push:
    branches: [ main ]
    
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2
    
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: '11'
        distribution: 'temurin'
        
    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
    
    - name: Build with Gradle
      run: ./gradlew clean build

그럼 main.yml을 생성하는 페이지가 나올텐데 거기에 위 내용을 입력한다.

빌드가 완료되면 성공했다는 커밋을 볼 수있다. 첫번째 커밋이 실패한 이유는 jobs-build-steps-with에서 distribution을 설정하지 않아서 오류가 발생했다.

그리고 저 X build를 클릭하면 어디서 오류가 발생했는지 에러메시지까지 확인가능하다.

AWS IAM

AWS IAM에서 새로운 사용자 생성

이름을 입력하고 액세스 유형을 선택한다.

여기서 AmazonEC2FullAccess, AmazonS3FullAccess, AWSCodeDeployFullAccess를 선택해준다.


태그는 추가하지않아줘도 되고 사용자를 만들어주면

액세스 키 ID와 비밀 액세스 키를 얻을수 있다. 이 창을 아직 닫지 말고

Github Repository로 돌아와서 Settings -> Secrets -> Actions에서 New repository secret 클릭

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY를 입력해주면 된다.

AWS S3

버킷 이름을 입력해준다. 모든 퍼블릭 액세스 차단을 하는 이유는 Github의 repository가 public이면 상관이 없지만, private이거나 실제 서비스에서 사용한다면 zip파일을 누구나 사용할 수 있기때문에 접근을 막아야한다. 우리는 IAM이용해서 접근 권한을 얻었으니 상관없다.

name : ai parrot

on:
  push:
    branches: 
      - master

env:
  S3_BUCKET_NAME: ai-parrot-build
    
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2
    
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: '11'
        distribution: 'temurin'
        
    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
    
    - name: Build with Gradle
      run: ./gradlew clean build

    - name: Make zip file
      run: zip -r ./$GITHUB_SHA.zip .

    - 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: ap-northeast-2

    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip

새로 추가된 부분을 설명하자면
env : 변수 설정이다. 쉘 스크립트에서 설정하는 것과 같은 느낌이다. $GITHUB_SHA는 Github Actions에서 제공하는 기본 환경 변수이고 값은 커밋 ID이다. S3파일은 파일 이름을 지정해서 덮어쓰기를 사용하는 것을 추천한다. AWS 프리티어 S3의 용량은 5GB인데 필자같은 경우 zip파일 하나가 150메가 정도였다. env를 이용해서 원하는 파일이름을 설정하고 $GITHUB_SHA를 단어바꾸기를 통해서 전부 변경하면 된다.
그리고 ${{ secrets.AWS_ACCESS_KEY_ID }} 이부분은 위 secrets에서 설정을 했기 때문에 그냥 납두면 된다. 만약 IAM에 나온 값으로 수정하고 repository가 public이라면 AWS에서 이메일 한통이 날라온다.

S3에 가보면 zip파일이 잘 올라간것을 확인할 수 있다.

AWS EC2

AWS EC2에서 CodeDeploy Agent를 설치해야한다. 기본적으로 프로젝트를 EC2에서 실행을 한번 해본, 즉 자바 버전 오류 등 프로젝트 실행에 아무런 문제가 없는 것을 가정하고 진행한다.

aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2

chmod +x ./install
sudo ./install auto

# 아래 코드로 설치 확인
sudo service codedeploy-agent status

마지막 명령어 실행후 The AWS CodeDeploy agent is running as PID 11720와 같은 문구가 나오면 설치완료

AWS CodeDeploy

먼저 IAM으로 돌아가서 CodeDeploy역할을 생성해주어야한다.

역할 -> 역할만들기에서 위 그림과 같이 CodeDeploy를 선택해주면 된다. 그 뒤에 CodeDeploy로 돌아가서

애플리케이션을 생성해주고

배포그룹 생성을 클릭해준다.

배포 그룹 이름 입력후 서비스 역할에서 방금 생성한 IAM 역할을 선택해준다.

Amazon EC2를 선택해주고 태그에는 EC2에 적용되어 있는 태그를 클릭한다.

로드 밸런서는 체크를 해제해준다.

쉘 스크립트 추가

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

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

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

appspec.yml을 스프링부트폴더 최상단에 추가해야한다.


REPOSITORY=/home/ec2-user/parrot/project
PROJECT_NAME=parrot

echo "> Build 파일 복사"

cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/

echo "> 현재 구동중인 애플리케이션 pid 확인"

CURRENT_PID=$(pgrep -f ${PROJECT_NAME}.*.jar)

echo "> 현재 구동중인 애플리케이션 pid: $CURRENT_PID"

if [ -z "$CURRENT_PID" ]; then
    echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
    echo "> kill -9 $CURRENT_PID"
    kill -9 $CURRENT_PID
    sleep 2
fi

echo "> 새 애플리케이션 배포"

JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1)

echo "> JAR Name: $JAR_NAME"

nohup java -jar \
        -Dspring.config.location=classpath:/application.properties,/home/ec2-user/parrot/application-db.properties,/home/ec2-user/parrot/application-mail.properties,classpath:/application-real.properties \
        -Dspring.profiles.active=real \
        $REPOSITORY/$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

deploy.sh 파일도 같은 위치에 추가했다. nohup java -jar 부분은 사람마다 설정이 다를것이다. 그렇지만 $REPOSITORY/$JAR_NAME > $REPOSITORY/nohup.out 2>&1 & 이부분은 확실히해야 한다. nohup 사용시 CodeDeploy는 무한대기하므로 이 문제를 해결하기 위해서 nohup.out 파일을 표준 입출력용으로 별도로 사용하기 때문이다.
해당 sh파일은 [스프링부트와 aws로 혼자 구현하는 웹서비스]책을 참고하였습니다.

(성공시키기위한 처참한 흔적들.. deploy의 nohup 부근에서 파일위치 때문에 계속 실패했다.)
아래 명령어는 CodeDeploy log를 볼 수 있는 명령어이다.

#모든 배포에 대한 로그를 한번에 볼 수 있다.
vi /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log

#배포 그룹의 배포별로 로그를 확인할 수 있다. 배포 ID는 위 사진에서 확인 가능하다.
vi /opt/codedeploy-agent/deployment-root//{deployment-group-ID}/{deployment-ID}/logs/scripts.log

배포를 완료했으면 netstat -lnp | grep 8080(포트번호) 또는 페이지 접속을 통하여 CI & CD 성공을 확인할 수 있다.

0개의 댓글