이번 글에서는 AWS CodeDeploy와 S3를 활용하여 EC2 인스턴스에 스프링부트 서비스를 배포할 것이다.
글의 순서는 다음과 같다.
- AWS CodeDeploy란?
- 사전조건
- AWS CodeDeploy 만들기
- AWS CodeDeploy 테스트
1. AWS CodeDeploy란?
CodeDeploy는 Amazon EC2 인스턴스, 온프레미스 인스턴스, 서버리스 Lamda 함수 또는 Amazon ECS 서비스로 애플리케이션 배포를 자동화하는 배포서비스다. CodeDeploy를 활용하면 Amazon S3 버킷, GitHub 레파지토리 또는 Bitbucket 레파지토리에 저장된 code, 서버리스 AWS Lamda 함수, 웹 및 구성파일, 실행파일, packages, 스크립트, 멀티미디어 파일 등을 거의 무제한으로 배포가 가능하다. CodeDeploy는 Amazon EC2나 AWS Lamda에 코드를 배포하는 경우 추가 비용이 부과되지 않는다(온프레미스에 배포할 경우만 배포당 0.02USD 요금 부과).
2. 사전조건
- AWS S3 생성(https://twofootdog.tistory.com/36 참고)
- AWS CodeCommit 생성 후 로컬PC와 Git 연동(https://twofootdog.tistory.com/33 참고)
- AWS CodeBuild 생성(https://twofootdog.tistory.com/37 참고)
추가로 만약 위 링크대로 AWS CodeBuild를 생성했다면 AWS CodeBuild 옵션 변경이 필요하다.
AWS 홈페이지에서 [콘솔에 로그인] -> [CodeBuild] -> [프로젝트 빌드] -> [본인이 생성한 프로젝트]를 선택한 후 [아티팩트]로 들어간다.
[아티팩트 편집]에서 [아티팩트 패키징]을 [Zip]으로 변경한다. Zip으로 변경하는 이유는 곧 구축할 CodeDeploy가 아티팩트 파일을 S3에서 가져와서 EC2 인스턴스에 배포할 때 zip이나 tar등 압축된 형태로 가져오기 때문에 CodeDeploy로 배포하기 위해선 아티팩트 패키징이 필요하다(해당 내용은 CodeDeploy를 만들다 보면 이해가 될 것 같다).
3. AWS CodeDeploy 만들기
이제 AWS CodeDeploy를 만들어보자. CodeDeploy 만드는 순서는 다음과 같이 진행될 것이다.
- AWS CodeDeploy용 IAM 역할 생성
- AWS EC2 인스턴스에서 S3 접근을 위한 IAM 역할 생성
- EC2 인스턴스 생성 및 CodeDeploy Agent 설치
- AWS CodeDeploy 만들기
- 소스코드에 appspec.yml 생성
3-1. AWS CodeDeploy용 IAM 역할 생성
AWS CodeDeploy를 만들기 위해서는 총 2개의 IAM 역할 생성이 필요하다. 우선 AWS CodeDeploy에서 CodeDeploy를 위한 역할 1개가 필요하며, EC2 인스턴스에서 CodeDeploy Agent를 활용하여 S3에 있는 아티팩트(배포파일)를 가져오기 위한 S3 접근 가능 역할 1개가 필요하다.
첫번째로 AWS CodeDeploy에서 사용할 역할 한개를 만들어보자. [콘솔에 로그인] -> [IAM] -> [역할] -> [역할 만들기]를 선택한다.
다음과 같이 [CodeDeploy]를 선택한다.
연결된 정책 확인이 [AWSCodeDeployRole]인지 확인 하고 넘어가자.
역할명은 codedeploy로 만들고 생성해보자.
3-2. AWS EC2 인스턴스에서 S3 접근을 위한 IAM 역할 생성
다음으로 EC2인스턴스에서 CodeDeploy Agent를 통해 S3로 접근을 위한 IAM 역할을 생성해보자. S3로 접근을 해야 하는 이유는 다시 한번 말하지만 S3에 아티팩트파일(배포파일)이 존재하기 때문이다. [콘솔에 로그인] -> [IAM] -> [역할] -> [역할 만들기]를 선택한 다음 [일반 사용 사례]에서 [EC2]를 선택한다.
[권한 정책 연결]에서 "AmazonEC2RoleforAWSCodeDeploy" 를 선택한다. 해당 정책을 열어보면 S3를 접근하는 내용의 정책인 걸 확인할 수 있다.
역할명은 ec2-s3-deploy로 작성하고 역할을 생성하자.
3-3. EC2 인스턴스 생성 및 CodeDeploy Agent 설치
다음으로 아티팩트 파일이 배포될 EC2 인스턴스를 생성하고 해당 EC2 인스턴스에 CodeDeploy Agent를 설치해보자.
EC2인스턴스 생성하는 방법은 https://twofootdog.tistory.com/27 에서 확인 가능하다. 단 생성할 때 역할을 조금 전 생성했던 ec2-s3-deploy(S3에 접근 가능한 권한)을 주면 된다. 또한 CodeDeploy에서 해당 EC2 인스턴스를 배포 인스턴스로 선택할 때 태그 입력하는 내용이 있기 때문에 5. 태그추가에서도 태그를 추가해주도록 하자(필자는 name : ec2-instance1으로 태그를 추가했다)
생성한 EC2 인스턴스로 접근하여 jdk를 설치하고(jar파일을 실행시키기 위함), build 디렉토리를 생성하고(S3에서 가져온 아티팩트 파일을 넣기 위함), codedeploy agent 설치파일을 다운받은 후 설치를 진행할 것이다. agent 설치를 하기 위해서는 ruby도 필요하기 때문에 ruby도 설치해준다.
# sudo yum install -y java-1.8.0-openjdk-devel.x86_64
# mkdir build
# wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
# chmod +x ./install
# sudo yum install -y ruby
# sudo ./install auto
# sudo service codedeploy-agent status
설치가 완료된 후 sudo service codedeploy-agent status 명령어를 수행해보면 codedeploy agent가 수행되는 것을 확인할 수 있다.
3-4. AWS CodeDeploy 만들기
CodoDeploy Agent도 설치를 완료했으니 이제 AWS CodeDeploy를 만들어보자. AWS 홈페이지에서 [콘솔에 로그인] -> [CodeDeploy] -> [애플리케이션] -> [애플리케이션 생성]을 선택한다. 애플리케이션 구성에서 이름과 컴퓨팅 플랫폼을 선택한다. 필자는 EC2에 배포할 것이기 때문에 컴퓨팅 플랫폼은 EC2/온프레미스를 선택했다.
애플리케이션이 생성된 후 해당 애플리케이션을 선택한 후 [배포 그룹 생성]을 선택한다.
[배포 그룹 이름]에는 원하는 배포그룹명을 넣어주고, [서비스 역할]에서는 맨 처음에 만들어준 IAM역할 중 codedeploy 용으로 만들어준 역할(이 글에선 역할명이 codedeploy 임)을 넣어주고, [배포 유형]은 [현재 위치]를 선택한다.
배포에 추가할 조합에는 EC2 인스턴스에만 배포할 것이므로 [Amazon EC2 인스턴스]를 선택하고, 배포될 인스턴스에 해당하는 키-값 태그를 선택한다(이 글에선 EC2 인스턴스에 키:값을 name : ec2-instance1으로 지정했으므로 해당 정보를 기입한다). 또한 [로드 밸런서]는 체크해제하고 [배포 그룹 생성]을 클릭한다.
그러면 다음과 같이 배포그룹이 생성이 된다. 해당 배포그룹을 선택한 후 [배포]를 생성하면 배포가 시작된다. 하지만 배포를 시작하기 전 해야 할 일이 있다. 바로 appspec을 만드는 일이다.
3-5. 소스코드에 appspec.yml 생성
AWS CodeDeploy는 appspec.yml을 통해서 어떤 파일들을, 어느 위치에 배포하고, 이후 어떤 스크립트를 실행시킬 것인지를 관리한다. 따라서 CodeDeploy를 수행하기 위해선 appspec.yml파일이 꼭 필요하며 다음과 같은 순서로 appspec.yml을 활용하여 CodeDeploy로 배포할 것이다.
- 배포하려는 스프링부트 소스코드(로컬)에 appspec.yml 및 배포 후 스크립트(start.sh) 생성
- buildspec.yml파일의 artifacts.files 부분에 appspec.yml 및 start.sh를 추가(아티팩트 부분에 추가 시 build후 패키징 할 때 jar파일에 appspec.yml과 start.sh도 포함시킴)
- 해당 소스 CodeCommit으로 업로드 후 CodeBuild하게 되면 jar파일, appspec.yml, start.sh가 .zip으로 패키징되어 S3에 업로드 됨
- CodeDeploy 시 S3에 있는 .zip 파일을 unzip을 한 후 appspec.yml 파일을 참고하며 서비스 배포 실행
그럼 4를 수행하기 위해 1 ~ 3 과정을 순서대로 수행해보도록 하자.
3-5-1. appspec.yml 및 start.sh 생성
배포하려는 스프링부트 소스코드(로컬소스)에 appspec.yml과 start.sh를 생성해준다. appspec.yml은 프로젝트 root디렉토리, start.sh는 scripts/ 밑에 추가해준다. appspec.yml에는 배포 될 위치(/home/ec2-user/build/)와 권한(ec2-user), 그리고 배포 후 실행될 스크립트(start.sh)를 작성한다. start.sh에서는 동일한 jar파일명으로 실행중인 프로세스를 죽인 후EC2 인스턴스에 새로 생성된 jar파일을 실행시킨다.
appspec.yml :
version: 0.0
os: linux
# destination에 아티팩트가 unzip된 결과가 생성될 디렉토리명을 넣어준다.
files:
- source: /
destination: /home/ec2-user/build/
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
# 주의 할 점은 빈칸 yml파일 특성상 빈칸 개수를 중시해야하고 Tab을 쓰면 안된다는점
# AfterInstall은 배포를 완료한 후 실행되는 스크립트를 명시하며
# ApplicationStart나 ValidateService 등을 대신 쓸 수 있다.
AfterInstall:
- location: start.sh
timeout: 60
runas: ec2-user
scripts/start.sh :
#!/bin/bash
BUILD_JAR=$(ls /home/ec2-user/build/*.jar)
JAR_NAME=$(basename $BUILD_JAR)
echo "> build 파일명: $JAR_NAME" >> /home/ec2-user/deploy.log
echo "> build 파일 복사" >> /home/ec2-user/deploy.log
DEPLOY_PATH=/home/ec2-user/
cp $BUILD_JAR $DEPLOY_PATH
echo "> 현재 실행중인 애플리케이션 pid 확인" >> /home/ec2-user/deploy.log
CURRENT_PID=$(pgrep -f $JAR_NAME)
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_JAR 배포" >> /home/ec2-user/deploy.log
nohup java -jar $DEPLOY_JAR >> /home/ec2-user/deploy.log 2>/home/ec2-user/deploy_err.log &
3-5-2. buildspec.yml 수정
CodeBuild시 생성했던 buildspec.yml을 수정해준다. artifacts.files에 appspec.yml과 scripts/**(start.sh 위치)만 추가해준다.
buildspec.yml :
version: 0.2
phases:
build:
commands:
- echo Build Starting on `date`
- chmod +x ./gradlew
- ./gradlew build
post_build:
commands:
- echo $(basename ./build/libs/*.jar)
- pwd
artifacts:
files:
- build/libs/*.jar
- appspec.yml # CodeDeploy 적용 시 추가
- scripts/** # CodeDeploy 적용 시 추가
discard-paths: yes
cache:
paths:
- '/root/.gradle/caches/**/*'
appspec.yml, scripts/start.sh, buildspec.yml 위치 :
3-5-3. CodeCommit에 소스 업로드 후 CodeBuild 수행
로컬소스를 변경하였으니 CodeCommit에 소스 업로드 후 CodeBuild를 수행해보자.
Git-Bash 수행 후 CodeCommit으로 업로드 :
# cd [프로젝트 root 디렉토리]
# git add .
# git commit -m "[주석]"
# git push origin master
# Enter passphrase for key '/c/Users/minkyu/.ssh/codecommit_rsa.pem': [RSA 비밀번호 입력]
프로젝트 빌드 :
프로젝트 빌드 완료 시 S3 버킷에 .zip파일이 생성된다.
4. AWS CodeDeploy 테스트
배포 준비가 완료되었으니 CodeDeploy 테스트를 수행해보자.
AWS홈페이지에서 [콘솔에 로그인] -> [CodeDeploy]에서 조금 전 생성한 애플리케이션을 선택하고 조금 전 생성한 배포그룹을 선택한다. 그리고 [배포 생성] 버튼을 클릭한다.
배포 설정의 [배포 그룹]은 조금 전 생성한 배포그룹을 선택하고, [개정 유형]은 [애플리케이션을 Amazon S3에 저장]을 선택한다(S3에 저장된 아티팩트 파일을 가져올 것이기 때문). [개정 위치]는 아티팩트 파일이 저장된 위치를 적고(.zip 확장자는 빼준다), [개정 파일 형식]은 .zip으로 패키징 했기 때문에 [.zip]을 선택한다.
그리고 그 밑에 [롤백 구성 재정의]에서는 롤백 비활성화를 체크해준다(우선 테스트니깐). 다 설정했으면 [배포 만들기]를 클릭해서 배포 결과를 확인해보자.
배포가 완료되면 다음과 같이 배포상태가 [성공]이 된다.
참고
https://jojoldu.tistory.com/282
https://senticoding.tistory.com/90
https://github.com/aws/aws-codedeploy-agent/issues/118
https://aws.amazon.com/ko/codedeploy/
'IT > AWS' 카테고리의 다른 글
AWS CloudFront + S3 + React 를 활용한 정적 웹페이지 만들기 (1) | 2020.02.18 |
---|---|
AWS CodePipeline과 S3를 활용한 스프링부트 서비스 배포 (0) | 2020.02.18 |
AWS CodeBuild로 빌드 후 S3에 빌드 결과파일 업로드 (3) | 2020.02.11 |
AWS S3 버킷 생성 후 파일 업로드/다운로드 (1) | 2020.02.10 |
AWS CodeCommit으로 소스코드 관리하기(Git & SSH) (3) | 2020.02.07 |
댓글