Github Actions로 스프링 자동 배포(1)

크리링·2024년 10월 9일
0

실무 트러블 슈팅

목록 보기
5/5
post-thumbnail

본인은 비교적 짧은 일정 동안 프로젝트를 진행하고 있다.
초기 환경 설정을 하면서 EC2도 생성한 김에 자동 배포를 진행해보고 기록해보려고 한다.



왜 Github Actions?

필자는 다양한 배포 툴을 써봤다. 내가 생각한 장단점이 있다.

  • 개인 프로젝트를 진행할 때 무료라서 사용한 Travis CI
    • 무료 아님
  • 회사에서 남는 EC2가 있어서 사용한 Jenkins
    • 배포하는데 EC2가 개입
  • 크레딧이 여유로워서 사용한 AWS Pipeline, AWS CodeBuild
    • 좋지만 좀 느리고, 크레딧은 이제 이전만큼 여유롭지 못함

그래서 이번에는 Github Actions로 사용하려고 한다.
필자는 되도록이면 여러가지의 툴을 하나로 보고 싶어한다. 그래서 MySQL workbench와 같은 DB 툴을 따로 사용하지 않고, Intellij DB를 사용하고 있으며 다른 팀원들에게 업무 관리를 Github Project를 사용하자고 제안했었다.(다른 직무의 팀원들은 Github가 익숙치 않아 현재는 그냥 JIRA를 사용하고 있다.)

Github Actions의 장점은 내가 생각했을때
1. 서버 리소스 불필요
2. 설정 yaml 파일로 구성해서 편리
3. 비동기 CI/CD
4. Github와의 접근성
5. 체감상 빠름

이러한 이유로 이번 프로젝트는 Github Actions로 정했다!




환경설정

본격적으로 Github Actions 자동 배포를 할 준비를 해보자
(EC2는 올려놓았고, IAM을 부여한 상태이다.)

참고 : AWS를 이용한 Spring Boot 서버 배포 - 자동. 배포를 위한 S3, CodeDeploy 연결



CodeDeploy Agent 설치

일단 EC2에 접속해서

sudo apt update
sudo apt install ruby-full
sudo apt install wget
wget https://aws-codedeploy-ap-northeast-2.3.ap-northeast-2.amazonaws.com/latest/install

를 차례로 입력해주었고

chmod +x ./install
sudo ./install auto

그리고 권한을 주고 설치해주었다.

설치가 됐는지 확인해주고

systemctl status codedeploy-agent

결과는

잘 설치되어 동작하는걸 확인할 수 있었다.



CodeDeploy 생성

이제 CodeDeploy를 생성해보자
1. 애플리케이션 생성
2. 배포 그룹 생성
3. 서비스 역할 IAM
4. 환경 구성(EC2 인스턴스 추가)

5. 배포 설정에 규칙을 제외한 나머지 디폴트로 배포 그룹 생성

완료 화면에서 위와 같은 문제가 있어보이지만 CodeDeploy-agent 생성 문제인것 같아
EC2에서 CodeDeploy-agent가 돌아가는지 확인해보니 문제가 없어 그냥 이후 진행




Github Workflow 작성

Github 리포지토리에 들어가 Actions -> new Workflow -> set up a workflow yourself

deploy.yml을 수정해주자

deploy.yml
name: Build and Deploy for miri_mart release server to AWS EC2

on:
  push:
    branches: [ develop ]

env:
  # 버킷에 저장할 폴더 이름
  PROJECT_NAME: project_name
  # S3 버킷 이름
  BUCKET_NAME: bucket_name
  # CodeDeploy의 애플리케이션 이름
  CODE_DEPLOY_APP_NAME: code_deploy_app_name
  # CodeDeploy의 배포그룹 이름
  DEPLOYMENT_GROUP_NAME: deploy_group_name

jobs:
  build:
    # 실행 환경 설정
    runs-on: ubuntu-latest

    steps:
    - name: checkout
      uses: actions/checkout@v2
	
    # 버전에 맞는 SDK 버전 설치 (필자는 17)
    - name: Set up JDK 17
      uses: actions/setup-java@v1
      with:
        java-version: '17'

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

    - name: Build with Gradle no Test
      run: ./gradlew clean build -x test

    # 압축 파일 만들기
    - name: Make Zip File
      run: zip -qq -r ./$GITHUB_SHA.zip .
      shell: bash
      
    # AWS 인증
    - 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
      
    # S3 버킷으로 파일을 업로드
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

    # S3 버킷에 업로드 된 파일을 대상으로 codeDeploy에서 배포 요청
    - name: Code Deploy
      run: aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name $DEPLOYMENT_GROUP_NAME --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

Github Actions secretsAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY를 각각 등록

EC2에서 실행될 appspec.yml을 추가

# appspec.yml
version: 0.0 # version은 반드시 0.0이어야 함
os: linux

files:
  - source: /
    destination: /home/ec2-user
    overwrite: yes

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

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ec2-user

scripts/stop.sh 추가

PROJECT_ROOT="/home/ec2-user/app"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"

DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)

# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
  echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
  echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
  kill -15 $CURRENT_PID
fi

``scripts/start.sh 추가

PROJECT_ROOT="/home/ec2-user"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"

APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
source ~/.bashrc
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG



배포 시도

IAM 권한 문제1

바로 실패

S3에 업로드 확인

s3에는 잘 올라기있는 것 확인

codeDeploy의 오류 내용은


An error occurred (AccessDeniedException) when calling the CreateDeployment operation: User: arn:aws:iam::***:user/s3_access_account is not authorized to perform: codedeploy:CreateDeployment on resource: arn:aws:codedeploy:ap-northeast-2:***:deploymentgroup:{CodeDeploy-name}/{CodeDeploy-group-name} because no identity-based policy allows the codedeploy:CreateDeployment action
Error: Process completed with exit code 254.

AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY의 권한이 S3까지만 있는 것으로 추정되는데 EC2, CodeDeploy 접근 권한 동시 필요

IAM S3, CodeDeploy 권한 부여로 빌드 문제 해결



IAM 권한 문제2

이후 CodeDeploy 확인 결과 배포 상태 무한 진행중

이벤트 로그

CodeDeploy agent log 확인

# vim /var/log/aws/codedeploy-agent/codedeploy-agent.log

InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error polling for host commands: Aws::Errors::MissingCredentialsError - unable to sign request without credentials set

구글링 결과 원인은
IAM 역할을 지정하지 않고 인스턴스를 실행
이때 설치된 CodeDeploy에는 해당 역할을 실행 할 수 있는 자격증명이 없기에 위와 같은 에러 발생

codedeploy-agent 재시작

sudo systemctl stop codedeploy-agent
sudo systemctl start codedeploy-agent

그래도 무한로딩

EC2 IAM 역할 확인
역할이 비어있음 -> IAM 권한 (test_ec2_codedeploy(AmazonEC2RoleforAWSCodeDeploy)) 부여

Codedeploy- agent 재시작 -> 무한로딩 해결



can't find user for ec2-user codedeploy 에러

확인 결과 SCRIPT 경로 오류

경로를 다시 설정해주고 동작 재시작시

모두 성공



jdk17 설치

로그 확인 결과

3개의 로그 모두 잘 생성

error.log 확인 결과

생각해보니 ubuntu에 java를 설치를 안했으니 버전에 맞는 jdk17을 설치

- $ sudo apt update
- $ sudo apt install openjdk-17-jdk

그리고 CodeDeploy 배포 재시도

하지만
application.ymlgitignore 처리했기 때문에

뒤에는 다음과 같은 에러가 발생한다

해당 프로젝트는 로컬, 테스트, 운영 profile 별 자동 배포 처리를 다르게 하는 이슈가 있기 때문이다.

깃액션은 이 문제를 어떻게 처리할까?

0개의 댓글