프론트 개발자분과 함께 작업하면서 백엔드 api서버를 로컬에 띄워 작업하는 데 한계를 느껴
아직 개발 중이지만 지금까지 만들어 둔 것만 EC2에 올려두기로 했다.
그런데 이미 EC2에 올려놓은 코드를 수정해야 할 작업이 계속 생기고,
그때마다 배포를 하는 것은 말도 안된다 생각하여 자동배포를 하기로 결심!
동료의 도움과 아래 잘 정리된 포스팅으로 생각보다 빠르게 (반나절) 끝이 났다.
https://twofootdog.tistory.com/37
https://jojoldu.tistory.com/281
일단 돌아가게는 만들었지만, 다시 정리할 필요를 느껴 짧게 내 방식대로 정리해보려 한다.
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
- 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들을 포함하여 압축한다.
- 실행가능한 jar파일
- 의존하고 있는 라이브러리 들을 추가해준다.
- BOOT-INF에 컴파일된 class 파일을 저장하는데, JarLauncher는 이 BOOT-INF 구조에 있는 class파일과 .jar파일을 로딩한다.
- 실행 가능한 jar 파일을 만들어 준다.
- spring-boot-maven-plugin
'스프링' 카테고리의 다른 글
Spring Data JPA / Dynamic DataSource 설정 (0) | 2022.03.28 |
---|---|
OSIV / @Transactional / Multi Datasource (0) | 2022.03.08 |
Spring vs Spring Boot 차이점 (0) | 2021.08.09 |
SpringBoot i18n - 다국어 설정 DB/ehcache/CookieLocaleResolver (0) | 2020.10.21 |
Spring의 기본개념과 동작원리 + 자기반성 (0) | 2020.04.29 |