RDS는 MariaDB를 사용하기 때문에
- 테이블 생성
- 프로젝트 설정
- EC2 설정이 필요하다.
JPA가 사용될 Entity테이블과 스프링 세션이 사용될 테이블 2가지 종류를 생성한다.
예제를 따라서 성공적으로 만들었다
MariaDB를 build.gradle에 등록한다.
compile('org.mariadb.jdbc:mariadb-java-client')
를 의존성에 추가한다.
src/main/resources에 application-real.properties
를 생성하고 다음과 같이 작성한다.
spring.profiles.include=oauth,real-db
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.session.store-type=jdbc
서버에서 구동될 환경을 구성하는 것이다.
profile=real인 환경이 구성된다. 실제 운영될 환경이기 때문에 보안/로그상 이슈가 될 만한 설정은 제거하고 RDS 환경 profile 설정이 추가된다.
OAuth과 마찬가지로 RDS 접속 정보도 보호해야 하므로, EC2 서버에 직접 설정 파일을 둔다.
app 디렉토리에
applicatio-real-db.properties
파일을 생성하고 다음과 같이 작성한다.
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mariadb://rds주소:포트명/database이름
spring.datasource.username=db계정
spring.datasource.password=db비번
spring.datasource.driver-class-name=org.mariadb.jdbc.driver
그리고 deploy.sh
를 수정한다.
-Dspring.profiles.active=real
application-real.properties
를 활성화 시킨다. 해당 파일 내의 spring.profiles.include=oauth,real-db 옵션 때문에 real-db역시 활성화 대상에 포함된다.
curl localhost:8080
을 SSH에 입력하여 html코드가 정상적으로 보인다면 성공!
코드가 푸시되면 Test & Build 를 자동화 해준다.
CI(Continuous Integration - 지속적 통합) : 코드 버전 관리를 하는 VCS 시스템에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
CI는 다음과 같은 규칙이 필요하다
- 모든 소스 코드가 현재 실행되고 누구든 현재의 소스에 접근할 수 있는 단일지점을 유지
- 빌드 프로세스 자동화를 통해 누구든 단일 명령어를 사용할 수 있게할 것
- 테스팅 자동화하여 언제든지 시스템에 건전한 테스트 수트를 실행할 수 있게할 것
- 누구나 현재 실행 파일을 얻을 때, 가장 완전한 파일이라고 확신하게 할 것
: 프로젝트가 완전한 상태임을 보장하기 위함이다.
CD(Continuous Deployment - 지속적 배포) : 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정
travis-ci.com에서 가입을 한뒤 깃허브 저장소를 활성화한다.
travis.yml
: travis CI의 상세 설정을 할 수 있다. 이를 생성한다. (아래 파일은 p.383까지 진행한 내용이다. 참고하지 않는게 좋습니다! )
language: java
jdk:
- openjdk8
branches:
only:
- master
# Travis CI 서버의 Home
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
script: "./gradlew clean build"
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/seung-springboot-webservice.zip # deploy로 zip파일 이동
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: seung-springboot-webservice
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private으로
local_dir: deploy # before_deploy에서 생성한 디렉토리
wait-until-deployed: true
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: seung-springboot-webservice
key: seung-springboot-webservice.zip # 빌드 파일을 압축해서 전달
bundle_type: zip
application: seung-springboot-webservice # 웹 콘솔에서 등록한 CodeDeploy 애플리케이션
deployment_group: seung-springboot-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
# CI 실행 완료 시 메일로 알람
notifications:
email:
recipients:
skud113@naver.com
- branches : master 브랜치에 푸시될 때만 travis-ci 수행
- cache : 그레이들을 통해 의존성을 받게되면 해당 디렉토리에 cache하여 같은 의존성은 다음 배포엔 받지 않음
- script : push되면 수행하는 명령어
gradlew clean build
- notifications : 자동으로 알람이 옴
IAM
에서 AWS key를 발급 받는다
일반적으로 AWS 서비스에 외부 서비스가 접근할 수 없기 때문.
travis-ci에 키를 등록한다.
S3 버킷을 생성한다.
버킷의 보안과 권한 설정에서 모든 차단을 해야한다. Jar 파일이 퍼블릭일 경우 누구나 내려받을 수 있어 중요한 정보가 탈취될 수 있다.
travis.yml에 다음 코드를 추가한다.
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/seung-springboot-webservice.zip # deploy로 zip파일 이동
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: seung-springboot-webservice
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private으로
local_dir: deploy # before_deploy에서 생성한 디렉토리
wait-until-deployed: true
CodeDeploy 연동글 작성 + Nginx 연동글 작성
자바 공부
CodeDeploy : AWS의 배포 시스템
그 외 배포 역할을 하는 서비스들
Code Commit
: 깃허브와 같은 코드 저장소의 역할, 프라이빗을 지원하는 강점이 있지만 깃허브에서 무료로 지원하고 있어서 거의 사용되지 않음
Code Build
: Travis CI와 마찬가지로 빌드용 서비스, 멀티 모듈을 배포하는 경우 사용해 볼만하지만 규모가 있는 곳에선 젠킨스, 팀시티등을 이용하여 거의 사용되지 않음
사용자
- AWS 서비스 외에 사용할 수 있는 권한
- 로컬 PC, IDC 서버 등
역할
- AWS 서비스에만 할당할 수 있는 권한
- EC2, CodeDeploy, SQS 등
서비스 선택에서 AWS 서비스 ▶ EC2
탭을 차례대로 클릭
정책에서는 AmazonEC2RoleforAWSCodeDeploy
를 선택
태그네임은 원하는대로 지어주면 된다. 난 예제를 따라 똑같이 Name이라고 지었다.
이제 생성된 역할을 적용할 차례다.인스턴스 우클릭 ▶ IAM 역할 연결/바꾸기
를 선택하여 방금 생성한 역할을 적용한 뒤, 재부팅을 해준다.
재부팅을 해야만 역할이 정상적으로 작동된다.
- CodeDeploy의 요청을 받을 수 있게 EC2 서버에 접속하여 다음 명령어를 차례로 입력한다.
# 에이전트 설치 aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/instatll . --region ap-northeast-2 # 설치 완료시 출력문 > download: s3://aws-codedeploy-ap-northeast-2/latest/instatll to ./install # insatll 파일 실행 권한 추가 chmod +x ./install # install 파일로 설치 진행 sudo ./install auto # Agent 정상 실행 상태 확인 sudo service codedeploy-agent status # 아래와 같이 출력되면 정상 ! > The AWS CodeDeploy agent is running as PID XXX
- 난 Ruby가 설치되어있지 않아
sudo yum install ruby
를 통해 ruby를 설치했다. 안되는 사람은 참고!
- EC2에 접근하려면 마찬가지로 권한이 필요하다. IAM 역할을 생성하자.
AWS서비스 ▶ CodeDeploy
선택- 서비스와 사용사례에서는 CodeDeploy를 선택한다.
- 태그 네임을 짓고 생성을 완료한다.
깃허브와 Travis가 각각 커밋, 빌드의 역할을 하고 있으니 배포를 위해 CodeDeploy를 생성한다.
애플리케이션 생성
▶ 컴퓨팅 플랫폼 - EC2/온프레미스
▶ 배포 그룹 생성
▶ 배포 그룹 이름 입력, 서비스 역할 - IAM 역할 선택
▶ 배포 유형 - 현재위치
▶ 환경구성 - Amazon EC2 인스턴스
▶ 생성완료
EC2 서버에 디렉토리를 생성한다. - mkdir ~/app/step2 && mkdir ~/app/step2/zip
Travis CI의 Build가 끝나면 S3에 zip 파일이 전송되고 이 zip파일을 위 디렉토리에 복사되어 압축을 풀 예정이다.
Travis의 설정은 travis.yml
, CodeDeploy의 설정은 appspec.yml
에서 진행한다.
appspec.yml
- 다음과 같이 작성
version: 0.0
# codedeploy의 버전, 프로젝트 버전이 아니므로 0.0 사용
os: linux
files:
- source: /
# codedeploy에서 전달해 준 파일 중 destination으로 이동시킬 대상 지정
destination: /home/ec2-user/app/step2/zip
# source에서 지정된 파일을 받을 위치, Jar를 실행하는 등을 여기서 옮긴 파일들로 진행
overwrite: yes
# 덮어쓰기 결정 Yes
.travis.yml
- 코드 추가 - provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: seung-springboot-webservice
key: seung-springboot-webservice.zip # 빌드 파일을 압축해서 전달
bundle_type: zip
application: seung-springboot-webservice # 웹 콘솔에서 등록한 CodeDeploy 애플리케이션
deployment_group: seung-springboot-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
S3의 옵션과 유사하다. 다른 부분은 CodeDeploy의 애플리케이션 이름과 배포 그룹명을 지정하는 것이다.
커밋 후 푸시한다.
cd /home/ec2-user/step2/zip
으로 이동하여 파일이 잘 왔는지 확인한다.
연동이 완료됐다
연동까지 구현되었으니, 실제로 Jar를 배포하여 실행까지 진행한다.
scripts/deploy.sh
추가하고 다음과 같이 작성한다. #!/bin/bash
REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=Spring_BootPJ_booboo
echo "> Build 파일 복사"
cp $REPOSITORY/zip/*.jar $REPOSITORY
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl Spring_BootPJ_booboo | grep jar | awk '{print $1}')
# 현재 수행 중인 스프링 부트 애플리케이션의 PID를 찾는다. 실행 중이면 종료
echo "현재 구동중인 애플리케이션 : $CURRENT_PID"
if [ -z "$CURRNET_PID" ]; then
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
# jar 파일에 nohup으로 실행할 수 있게 실행권한을 추가한다.
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 &
# nohup 실행시 CodeDeploy가 무한대기하는 이슈를 해결하기 위해 사용
.travis.yml
수정 - 다음과 같이 수정 before_deploy:
- mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성
# S3에서는 디렉토리 단위로만 업로드가 가능하기 떄문에 디렉토리를 항상 생성한다.
- cp scripts/*.sh before-deploy/
# zip 파일에 포함시킬 파일들을 저장한다.
- cp appspec.yml before-deploy/
- cp build/libs/*.jar before-deploy/
- cd before-deploy && zip -r before-deploy * # before-deploy로 이동 후 전체 압축
# zip -r 명령어를 통해 디렉토리 전체 파일을 압축한다.
- cd ../ && mkdir -p deploy # 상위 디렉토리로 이동 후 deploy 디렉토리 생성
- mv before-deploy/before-deploy.zip deploy/seung-springboot-webservice.zip # deploy로 zip파일 이동
appspec.yml
수정 - 다음과 같이 수정 permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
# CodeDeploy에서 실행할 명령어 지정 ApplicationStart에서 deploy.sh를 ec2-user 권한으로 실행하게함
ApplicationStart:
- location: deploy.sh
timeout: 12000
runas: ec2-user
난 노트북 사양이 안좋아서 timeout을 12000까지 늘렸다 ㅜㅜ.. 원랜 60이다
build.gradle에서 프로젝트 버전을 다음과 같이 변경한다.
version '1.0.1-SNAPSHOT'
변경된 사항을 알 수 있게
index.mustache
에서 h1태그에 Ver.2 텍스트를 추가하고 깃허브로 푸시해본다.
여기서 문제가 발생했다. 변경 사항이 적용이 안되는 것..
그러다가 EC2 인스턴스가 일치하지 않는다는 걸 알게됐다ㅜㅜ
현타는 자기 전에 오게 놔두고 일단 해결부터 했다. 결과는 성공
분명 15일에 진도를 나가기 전까지는 괜찮았다. 하지만
어떻게 해결할지 감이 안온다. 알고 싶다,, 지금 한 9시간 동안 잡고 있는거 같은데 거의 끝자락와서 이러니까 속상하다 ㅠㅠ