프론트 개발자분과 함께 작업하면서 백엔드 api서버를 로컬에 띄워 작업하는 데 한계를 느껴

아직 개발 중이지만 지금까지 만들어 둔 것만 EC2에 올려두기로 했다.

 

그런데 이미 EC2에 올려놓은 코드를 수정해야 할 작업이 계속 생기고,

그때마다 배포를 하는 것은 말도 안된다 생각하여 자동배포를 하기로 결심! 

 

동료의 도움과 아래 잘 정리된 포스팅으로 생각보다 빠르게 (반나절) 끝이 났다.

 

 

https://twofootdog.tistory.com/37

 

AWS CodeBuild로 빌드 후 S3에 빌드 결과파일 업로드

이번 글에서는 AWS CodeCommit에 있는 스프링부트 소스코드를 AWS CodeBuild를 통해서 빌드를 수행한 후 빌드된 결과파일(아티팩트(JAR))을 S3에 업로드하는 실습을 진행해볼 것이다. 이 글의 순서는 다음과 같다...

twofootdog.tistory.com

https://jojoldu.tistory.com/281

 

1) AWS로 배포하기 시리즈 - 1. Code Deploy 사용하기

AWS로 전체 시스템 구축해야 할 일이 생겨 AWS 배포 환경 시리즈를 시작합니다. 시리즈 과정은 CodeDeploy -> Code Pipeline -> ELB & Auto Scaling Group -> Beanstalk 으로 진행될 예정입니다. Code Pipeline vs..

jojoldu.tistory.com

일단 돌아가게는 만들었지만, 다시 정리할 필요를 느껴 짧게 내 방식대로 정리해보려 한다. 

 

 

 

 

 

AWS에서 배포하는 데 필요한 서비스

 

  • Code Commit
    • 깃허브와 같은 코드 저장소의 역할
  • Code Build
    • 빌드용 서비스, 규모가 있는 데에선 젠킨스/팀시티 등 이용
    • 소스코드 컴파일, 단위테스트, 배포 준비된 artifact file 생성
  • Code Deploy
    • 배포 서비스, 위 2개의 서비스는 대체재가 있으나 CodeDeploy는 대체재가 없다.
    • 오토 스케일링 그룹 배포, 블루 그린 배포, 롤링 배포, EC2 단독 배포의 기능을 지원한다. 

 

내가 이해한 Code Pipeline이 빌드 및 배포하는 과정 

 

Code Commit에 올린 내 소스가 업데이트(커밋)되면 파이프라인이 실행된다. (커밋 = 트리거)

소스 단계의 artifact가(빌드 준비가 완료된 파일)이 S3에 저장된다.  (빌드 준비가 완료된 파일)

CodeBuild는 이 artifact를 빌드한 다음, 빌드된 jar파일을 다시 S3에 저장하고, CodeDeploy에게 배포 명령을 내림

CodeDeploy는 CodeBuild가 빌드한 jar파일을 가져와서 애플리케이션(EC2)에 배포한다. 

 

 

 

 

자동배포 작업순서 

 

  • Code Commit에 내 스프링부트 소스 올려두기
  • AWS S3 버킷 생성하기
  • AWS CodeBuild 프로젝트 생성 
    • 소스공급자 - CodeCommit
    • 리포지토리 - CodeCommit 내 나의 프로젝트 
    • 브랜치 - master
    • 운영체제 - Amazon Linux 2
    • 아티팩트 - Amazon S3 (버킷 연결)
      • 패키징 : zip 
      • 캐시 : 빌드에 필요한 의존성들을 캐시하는 건데, 빌드할 때마다 새로 받는게 아니라 S3에 올려놓고 이미 있는 건 새로 받지 않도록 하는 것
  • 프로젝트 Root 디렉토리에 buildspec.yml 파일 생성
    • artifacts작성하면서 jar파일 어디에 저장하고 Deploy때 필요한 appspec.yml과 배포스크립트 파일 어디있는지 작성하기
  • commit & push 후 CodeBuild에서 빌드 시작 클릭해서 잘 되는지 테스트
  • AWS CodeDeploy용 IAM 역할 생성 (AWSCodeDeployRole)
  • AWS EC2 인스턴스에서 S3 접근을 위한 IAM 역할 생성 (AmazonEC2RoleforAWSCodeDeploy)해서 EC2에 역할주기
  • EC2 인스턴스에 CodeDeployAgent 설치
$ 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
 

최신 버전의 CodeDeploy 에이전트를 설치하려면 다음을 수행합니다.

$ sudo ./install auto

서비스가 실행 중인지 확인하려면 다음 명령을 실행합니다.

$ sudo service codedeploy-agent status

"error: No AWS CodeDeploy agent running"와 같은 메시지가 표시되면 서비스를 시작하고 다음 두 명령을 한 번에 하나씩 실행합니다.

$ sudo service codedeploy-agent start
$ sudo service codedeploy-agent status

 

출처 : https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html

 

  • AWS CodeDeploy 애플리케이션 생성
    • AWS CodeDeploy용 IAM 역할 붙여주기
    • 애플리케이션 배포 방법 선택 (현재위치, 블루/그린)
    • 연결할 ec2를 tag를 입력하여 알려주기
  • 프로젝트 Root 디렉토리에 appspec.yml 파일 생성
    • 어떤 파일을 어느 위치에 배포하고 어떤 스크립트 실행할 건지 관리한다.
  • 배포스크립트 start.sh 생성 (아래 참고)
  • commit & push 후 CodeDeploy에서 배포 생성해서 잘 되는지 테스트해보기

+ deploy할 때 에러가 발생할 때는 ? 

  • cd /var/log/aws/codedeploy-agent 로 가서 codedeploy-agent.log 파일을 확인해보자.

 

 

CI/CD 흐름

설정한 배포 프로세스

 

작성파일 

 

  • buildspec.yml
version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      - echo starting build stage
      - mvn package
  post_build:
    commands:
      - pwd
artifacts:
  files:
    - target/*.jar
    - appspec.yml
    - scripts/**
  discard-paths: yes
 cache:
  paths:
    - '/root/.m2/**/*'

artifacts는 빌드된 빌드된 WAR/JAR를 보관할 위치를 나타낸다.

artifacts 파일에 있는 appspec.yml과 scripts/** 는 CodeBuild가 .zip으로 패키징 할 때 jar파일에 appspec.yml, start.sh를 포함시킨다. CodeDeploy는 S3에 있는 .zip파일 압축을 풀어서 appspec.yml파일을 참고해서 배포한다. 

cache 경로에 있는 파일들이 S3 캐시파일로 등록된다.

 

 

  • appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/target/
permissions:
  - object : /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  AfterInstall:
    - location: start.sh
      timeout: 60
      runas: ec2-user

 

  • 배포스크립트 (.sh)
#!/bin/bash
BUILD_JAR=$(ls /home/ec2-user/target/*.jar)
JAR_NAME=$(basename $BUILD_JAR)
echo "> build 파일명: $JAR_NAME" >> /home/ec2-user/deploy.log
echo "> debugging : $BUILD_JAR"    >> /home/ec2-user/deploy.log

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

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

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

DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo "> DEPLOY_PATH, JAR_NAME : $DEPLOY_PATH$JAR_NAME"    >> /home/ec2-user/deploy.log

echo "> DEPLOY_JAR 배포"    >> /home/ec2-user/deploy.log
nohup java -Xms1024m -Xmx2048m -XX:NewRatio=2 -server -Dspringi.profiles.active=product -jar $DEPLOY_JAR >> /home/ec2-user/deploy.log 2>/home/ec2-user/deploy_err.log &

 

Code Pipeline으로 배포환경을 구축할 때 발생했었던 에러

  • 평소 Maven Wrapper을 사용해서 ./mvnw로 빌드했는데, 이게 안먹는거 아닌가;
    • ./mvnw은 안되는 걸로... (아무리 검색해봐도 관련 자료가 없다 ㅠㅠ)
    • mvn package로 하자..
  • '기본 manifest 속성이 없습니다' 오류
    • Code Pipeline에서는 모든 과정이 오류 없이 Success가 떴는데, 서버가 실행되지 않았다.
    • 문제는  jar파일이 처음부터 잘못 만들어진 것인데
    • 원인은 'spring-boot-maven-plugin' 플러그인 추가를 하지 않았던 것
      • spring-boot-maven-plugin
        • 실행 가능한 jar 파일을 만들어 준다. 
          • 실행가능한 jar파일
            • 컴파일된 클래스 뿐만 아니라 코드 실행에 필요한 모든 jar dependency들을 포함하여 압축한다. 
        • 의존하고 있는 라이브러리 들을 추가해준다. 
        • BOOT-INF에 컴파일된 class 파일을 저장하는데, JarLauncher는 이 BOOT-INF 구조에 있는 class파일과 .jar파일을 로딩한다. 

 

 

+ Recent posts