이 글은 '스프링부트와 AWS로 혼자 구현하는 웹 서비스 - 이동욱(jojoldu)'을 공부하며 작성한 글로 생략된 내용은 책을 구매해서 확인하는 것을 권장합니다.
참고 소스코드 깃허브 https://github.com/jojoldu/freelec-springboot2-webservice
http://www.yes24.com/Product/Goods/83849117
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - YES24
가장 빠르고 쉽게 웹 서비스의 모든 과정을 경험한다. 경험이 실력이 되는 순간!이 책은 제목 그대로 스프링 부트와 AWS로 웹 서비스를 구현한다. JPA와 JUnit 테스트, 그레이들, 머스테치, 스프링
www.yes24.com
이 책의 9장에 해당하는 Travis CI 배포 자동화 과정 중 Travis CI와 AWS S3, CodeDeploy 연동 과정을 정리한 글이다.
Travis CI와 AWS S3, CodeDeploy 연동
AWS의 배포 시스템인 CodeDeploy 이용하기 전 배포 대상인 EC2가 CodeDeploy를 연동받을 수 있도록 하기 위해 IAM 역할을 생성해줘야 한다.
EC2에 IAM 역할 추가
1. IAM 검색 -> 왼쪽에서 역할 -> 오른쪽 상단에 역할 만들기
IAM 사용자와 역할 차이
사용자: AWS 서비스 외에 사용할 수 있는 권한 ex) 로컬 PC, IDC 서버 등
역할: AWS 서비스에서만 할당할 수 있는 권한 ex) EC2, CodeDeploy, SQS 등
-> 지금만드는 역할은 EC2 서비스에서 사용할 것이기 때문에 역할로 생성
2. AWS 서비스 선택 -> EC2 선택 -> 다음
3. AmazonEC2RoleforAWSCodeDeploy 선택 -> 다음
4. 역할 이름 등록 및 태그 추가(선택사항) -> 역할 생성
6. EC2 -> 해당 인스턴스 ID 오른쪽 마우스 클릭 -> 보안 -> IAM 역할 수정 -> 생성한 역할 선택 -> 인스턴스 재부팅
Codedeploy 에이전트 설치
Codedeploy의 요청을 받을 수 있도록 에이전트를 설치한다.
1. EC2 접속
아래 명령어 실행
리전은 꼭 맞춰주도록 하자!
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2
2. install 파일에 실행권한 추가 및 install 파일로 설치
# 실행권한 추가
chmod +x ./install
# 설치
sudo ./install auto
설치를 시도하니
위처럼 /usr/bin/env: No such file or directory라고 뜨면 ruby가 설치가 안된 상태라 발생하는 문제다.
#루비 설치
sudo yum install ruby
루비 설치후 다시 install파일로 설치 진행
설치가 완료되면 Agent가 정상적으로 실행되는 지 상태 검사
sudo service codedeploy-agent status
Codedeploy를 위한 권한 생성
Codedeploy에서 EC2 접근하기 위한 권한 필요!
이것도 AWS 서비스이므로 IAM 역할 생성
1. IAM 검색 -> 왼쪽에서 역할 -> 오른쪽 상단에 역할 만들기
2. AWS 서비스 -> CodeDeploy
3. 권한 추가는 권한이 하나뿐이므로 바로 다음으로
4. 역할 이름 등록 및 태그 추가(선택사항) -> 역할 생성
Codedeploy 생성
지금 프로젝트에서 Code Commit의 역할은 깃허브, Code Build는 Travis CI가 하고 있기에 CodeDeploy 서비스 사용만 추가적으로 필요
1. Codedeploy -> 왼쪽에 시작하기 -> 애플리케이션 생성 -> 애플리케이션 이름 및 플랫폼 선택 -> 생성
2. 배포그룹생성 -> 배포그룹이름 및 서비스 역할 선택 -> 배포유형 현재위치
- 서비스역할: 이전에 생성한 CodeDeploy IAM 역할 선택
- 배포유형: 현재위치, 만약 배포할 서비스가 두대이상이라면 블루/그린 선택
3. 환경 구성 Amazon EC2 인스턴스 선택 -> 태그 추가(선택사항)
4. 배포 구성 CodeDeployDefault.AllAtOnce -> 로드밸런싱 체크 해제 -> 배포그룹생성
CodeDeploy 설정 완료!
Travis CI, S3, CodeDeploy 연동
지금 프로젝트에서 Code Commit의 역할은 깃허브, Code Build는 Travis CI가 하고 있기에 CodeDeploy 서비스 사용만 추가적으로 필요
1. S3에서 넘겨줄 zip 파일을 저장할 디렉토리 생성
mkdir ~/app/step2 && ~/app/step2/zip
2. Travis CI, S3, CodeDeploy 연동위한 설정 작성
Travis CI의 Build가 끝나면 S3 zip 파일이 전송되고 전송된 zip파일이 home/ec2-user/app/step2/zip로 복사되어 압축이 풀리도록 한다.
2-1. appspec.yml를 생성해 AWS CodeDeploy 설정 작성
파일 생성 위치는 .travis.yml과 동일하다.
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/app/step2/zip/
overwrite: yes
- version: 0.0
- CodeDeploy 버전을 의미, 프로젝트 버전이 아니기에 0.0 외에 다른 버전을 사용하면 오류 발샐
- source: CodeDeploy에서 전달해준 파일 중 destination으로 이동시킬 대상을 지정한다. 위처럼 루트 경로(/)는 전체파일을 의미한다.
- destination: source에서 지정한 파일을 받을 위치, Jar를 실행하는 것 등은 destination에서 옮긴 파일들로 진행
- overtime: 기존에 파일들이 있다면 덮어쓸지 결정
2-2. .travis.yml로 Travis CI 설정 작성
...
deploy:
- provider: s3
...
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: springbootweb-build # S3 버킷
key: springboot-webservice.zip # 빌드 파일을 압축해서 전달
bundle_type: zip
application: springboot-webservice # 웹 콘솔에서 등록한 CodeDeploy 어플리케이션
deployment_group: springboot-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
#처음에 아래 코드 작성안해서 배포내역이 기록안되었다.
on:
branch: main # main branch 가능하도록 추가
...
3. 작성한 파일 깃허브로 푸시
Travis CI 시작
완료가 된후 CodeDeploy를 보면 배포내역이 나와야 하는데 나오지 않았다..
s3에 zip파일은 잘 올라와있어 codedeploy 전달에서 오류가 생긴 것으로 추정
s3에만 올라오는 이유가 뭘까보니까 이전 작업에서 travis CI 기본 설정으로 master branch만 받아서 main도 허용하도록 따로 코드를 작성했었는데,
그 부분이 codedeploy 사용을 위해 추가로 작성한 부분에는 적혀있지 않았다.
#처음에 아래 코드 작성안해서 배포내역이 기록안되었다.
on:
branch: main # main branch 가능하도록 추가
코드 추가해서 작성하니
배포 내역에 배포 성공이 기록되었다.
4. 만든 폴더에 프로젝트 파일이 잘 도착했는지 확인
cd /home/ec2-user/app/step2/zip
ll
Travis CI, S3, CodeDeploy 연동완료!
배포 자동화 구성
Travis CI, S3, CodeDeploy 연동을 기반으로 Jar 배포 및 실행하기
1. deploy.sh 파일 추가
프로젝트의 scripts 디렉토리를 생성해 step2 환경에서 실행될 deploy.sh를 생성한다.
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=springboot-webservice
echo "> Build 파일 복사"
cp $REPOSITORY/zip/*.jar $REPOSITORY/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl springboot-webservice | grep jar | awk '{print $1}')
echo "현재 구동중인 어플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -15 $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
echo "> 새 어플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)
echo "> JAR Name: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행"
nohup java -jar \
-Dspring.config.location=classpath:/application.properties,classpath:/application-real.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.properties \
-Dspring.profiles.active=real \
$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
- CURRENT_PID: 현재 수행중인 스프링 부트 어플리케이션의 프로세스 ID 찾는다. 실행중일 경우 종료시키기 위해서
- 스프링부트 애플리케이션 이름인 springboot-webservice로 된 다른 프로그램들이 있을 수 있어 springboot-webservice로 된 jar 프로세스를 찾은 뒤에 ID를 찾는다.
- chmod +x $JAR_NAME: jar파일에게 nohup으로 실행할 수 있는 권한 부여
- $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
- nohup 실행 시 CodeDeploy는 무한대기 -> 이 이슈 해결을 위해 nohup.out 파일을 표준 입출력용으로 별도로 사용
- 이렇게 안하면 nohup.out 파일이 생기지 않고 CodeDeploy 로그에 표준 입출력이 출력
- nohup이 끝나기전까지 CodeDeploy도 끝나지 않기 때문에 설정 필요
- nohup 실행 시 CodeDeploy는 무한대기 -> 이 이슈 해결을 위해 nohup.out 파일을 표준 입출력용으로 별도로 사용
2. .travis.yml 파일 수정
지금 작성한 설정은 모든 파일을 압축하고 있는데, 이 중 실제로 필요한 파일은 Jar, appspec.yml, 배포를 위한 스크립트들이다. 나머지는 zip에 포함하지 않도록 수정한다.
.travis.yml 파일의 before_deploy 수정
before_deploy:
- mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성
- cp scripts/*.sh before-deploy/
- cp appspec.yml before-deploy/
- cp build/libs/*.jar before-deploy/
- cd before-deploy && zip -r before-deploy * # before-deploy로 이동후 전체 압축
- cd ../ && mkdir -p deploy # 상위 디렉토리로 이동후 deploy 디렉토리 생성
- mv before-deploy/before-deploy.zip deploy/springboot-webservice.zip # deploy로 zip파일 이동
- Travis CI는 s3로 특정 파일만 업로드 불가능 -> 디렉토리 단위로 업로드해야하기 때문에 before-deploy 폴더 항상 생성
- before-deploy에는 zip 파일에 포함시킬 파일들을 저장
- zip -r 명령어를 통해 before-deploy 디렉토리 전체 파일 압축
3. appspec.yml 파일 수정
아래 코드 추가
version: 0.0
...
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
ApplicationStart:
- location: deploy.sh
timeout: 60
runas: ec2-user
4. 작성한 파일 깃허브로 커밋, 푸시
푸시할 때, deploy.sh만 올리지 말고 scripts 폴더 채로 푸시해야한다.
Travis CI 시작
codedeploy로 배포후 EC2 도메인(퍼블릭 주소)으로 접속을 시도하니 로딩이 걸리거나 접속이 거부되었다.
codedeploy 로그를 확인하니
pid를 제대로 못 찾는것 같다.
구글링해보니
https://github.com/jojoldu/freelec-springboot2-webservice/issues/586
[오류] p.358 deploy.sh 프로세스 ID 조회 · Issue #586 · jojoldu/freelec-springboot2-webservice
기존에 올라온 질문이 아닌지 먼저 검색해주세요! 가장 자주 나온 제보 P.105 @PutMapping("/api/v1/posts") P.111 Posts.update 어떤 @오류인가요? 오류설명: p.358 ~359 deploy.sh 내 프로세스 아이디(CURRENT_PID)를 조
github.com
책에서는 Amazon Linux1 AMI를 사용했는데, 현재는 Amazon Linux2 AMI만 있기 때문에 이를 선택했는데, 이 차이로 발생하는 문제일수도 있다고 한다.
책에서는 애플리케이션 프로세스를 조회할 때 jar로 검색했는데, java로 검색해야 조회가 된다! 그래서 log에서 PID가 제대로 나오지 않는 거였다..!!
scripts/deploy.sh 수정
jar -> java로 변경
변경하고 푸시하면 접속이 아주 잘된다.
5. 배포자동화 테스트
확인을 위해 일부 코드 수정
build.gradle에서 프로젝트 버전 변경
index.mustache 수정
변경하고 Travis CI 로그에서 메인페이지_로딩 테스트가 실패한다고 떴다.
그 테스트에서 어떤 문장이 포함되어있는지를 테스트했는데 그 문장이 배포자동화 테스트를 위해 바뀌면서 포함되지 않는 문장이 되어서 발생한 문제였다.
페이지에 있는 문장으로 바꿔주니 통과했다.
CodeDeploy 로그 확인
서버에 접속해서 아래 명령어 실행
cd /opt/codedeploy-agent/deployment-root/deployment-logs
sudo vi codedeploy-agent-deployments.log
현재 문제
이제 main 브랜치에 푸시만 하면 자동으로 EC2에 배포가 된다.
하지만 배포하는 동안 스프링 부트 프로젝트는 종료 상태가 되어 서비스를 이용할 수 없다.
이를 해결하기 위해 무중단 배포를 구현할 필요가 있다.
'스프링부트와 AWS로 혼자 구현하는 웹서비스' 카테고리의 다른 글
24시간 365일 중단 없는 서비스 - 무중단 배포 (0) | 2023.04.17 |
---|---|
Travis CI 배포 자동화 - Travis CI와 프로젝트, Travis CI와 AWS S3 연동 (0) | 2023.04.06 |
EC2 서버에 프로젝트 배포하기 - 스프링부트 프로젝트로 RDS 접근 및 EC2에서 소셜 로그인 (0) | 2023.03.29 |
EC2 서버에 프로젝트 배포하기 - EC2에 프로젝트 Clone 및 배포 스크립트 작성(외부 Security 파일 등록) (0) | 2023.03.27 |
AWS에 데이터베이스 환경 구축 - 내 PC에서 RDS 접속과 RDS와 EC2의 연동 확인 (0) | 2023.03.15 |
댓글