*모든 내용은 책에 있는 내용을 기반으로 작성하였습니다.
9장 ----
코드 버전 관리를 하는 VCS 시스템(Git, SVN등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정을 CI(Continuous Integration - 지속적 통합)이라고 하며, 이 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정을 CD(Continuous Deployment - 지속적인 배포) 라고 한다.
일반적으로 CI만 구축되어 있지는 않고, CD도 함꼐 구축된 경우가 대부분이다.
현대의 웹 서비스 개발에서는 하나의 프로젝트를 여러 개발자가 함께 개발을 진행한다. 그러다 보니 각자가 개발한 코드를 합쳐야 할 때마다 나을 지정하여 병합일을 지정하여 개발을 했다.
하지만 이런 환경에서는 코드가 통합되는 환경(CI)를 구축하였다.
개발자 각자가 웒격 저장소로 푸시가 될때마다 코드를 병합하고, 테스트 코드와 빌드를 수행하면서 자동으로 코드가 통합되어 더는 수동으로 코드를 통합할 필요가 없어졌다. -> 개발에만 집중이 가능해짐CD역시 마찬가지이다. 한 두 대의 서버에 개발자가 수동으로 배포를 하는건 가능할 수 있지만 수백대의 서버에 배포플 해야하거나 긴박하게 당장 배포를 해야하는 상황이 오면 수동으로 배포를 할 수가 없게 되었고 이를 자동화 하게된다. -> 개발에만 집중이 가능해짐
- 모든 소스 코드가 살아 있고(현재 실행되는) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것
- 빌드 프로세스를 자동화해서 누그든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
- 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실해할 수 있게 할 것
- 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할 것
가장 중요한 것: 테스팅 자동화 -> 이 프로젝트가 완전한 상태임을 보장하기 위해서 테스트 코드가 구현 되어야 한다.
language: java
jdk:
-openjdk8
branches: //(1)
only:
-master
#Travis CI 서버의 Home
cache: //(2)
directories:
- '$HOME/.m2/repository/;
- '$HOME/.m2/gradle'
script: "./gradle clean build" //(3)
# CI 실행 완료 시 메일로 알람
notifications: //(4)
email:
recipiens:
-본인 메일 주소
Travis CI를 어느 브랜치가 푸시될 때 수행할지 지정한다.
-> 현재 옵션은 오직 master branch에 push될 때만 수행한다.
그레이들을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 같은 의존성은 다음 배포 때부터 다시 받지 않도록 설정한다.
master 브랜치에 푸시되었을 때 수행하는 명령어이다.
여기서는 프로젝트 내부에 둔 gradlew를 통해 clean & build를 수행한다.
Travis CI 실행 완료 시 자동으로 알람이 가도록 설정한다.
S3란 AWS엣 제공하는 일종의 파일 서버입니다. 이미지 파일을 비롯한 정적 파일들을 간리하거나 지금 진행하는 것처럼 배포 파일들을 관리하는 등의 기능을 지원합니다. 보통의 이미지 업로드를 구현한다면 이 S3를 이용하여 구현하는 경우가 많다. S3을 비롯한 AWS 서비스와 Travis CI를 연동하게 되면 전체 구조는 다음과 같다.
GitHub -> Travis CI -> (1. jar 전달) -> AWS S3 ->(3. jar 전달) -> AWS CodeDepoy
-> Travis CI -> (2. 배포 요청) -> AWS CodeDeploy -> (4. 배포) AWS EC2
첫번쨰로 Travis CI와 S3을 연동해야한다. 실제 배포는 AWS CodeDeploy라는 서비스를 이용한다. 하지만, S3연동이 먼저 필요한 이유는 Jar 파일을 전달하기 위해서입니다.
CodeDeploy는 저장 기능이 없습니다. 그래서 Travis CI가 빌드한 결과물을 받아서 CodeDeploy가 가져갈 수 있도록 보고나할 수 있는 공간이 필요합니다. 보통은 이럴 때 AWS S3를 이용합니다.
일반적으로 AWS서비스에 외부 서비스가 접근할 수 없다. 그러므로 접근 가능한 권한을 가진 Key를 생성해서 사용해야한다. AWS에서는 이러한 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management)이 있다.
IAM은 AWS에서 제공하는 서비스의 접근 방식과 권한을 관리한다. 이 IAM을 통해 Travi CI가 AWS의 S3와 CodeDeploy에 접근할 수 있도록 해야한다.
책보고 진행...
S3(Simple Storeage Service) : 일종의 파일 서버이다. 순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할
보통 게시글을 쓸 때 나오는 첨부파일 등록을 구현할 때 많이 이용한다.
Travis CI에서 생성된 Build 파일을 저장한다.
책보고 진행...
9.2의 yml에 추가한다.
...
before_deploy: //(1)
- zip -r freelec-springboo2-webservice * //(2)
- mkdir -p deploy //(3)
- mv freelec-springboot2-webservice.zip deploy/freelec-springboot2-webservice.zip //(4)
deploy: //(5)
- provider : s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: freelec-springboot-build # S3 버킷
region: ap-northeast-2
skip_cleanup: true
acl: privae # zip 파일 접근을 private으로
local_dir: deploy # before_deploy에서 생성한 디렉토리 //(6)
wait-until-deployed: true
deploy 명령어가 실행되기 전에 수행되며, CodeDeploy는 Jar파일은 인식하지 못하므로 Jar+기타 설정 파일들을 모아 압축한다.
현재 위치의 모든 파일을 해당 이름으로 압축하여야하며, 명령어의 마지막 위치는 자신의 프로젝트 이름이여야 한다.
deploy라는 디렉토리를 Travis CI가 실행중인 위치에서 생헌한다.
freelec-springboot2-webservice.zip 파일ㅇ르 deploy/freelect-springboot2-webservice.zip
S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언합니다.
앞에서 생성한 deploy 디렉토리르 지정, 해당 위치의 파일들만 S3로 전송한다.
완료하고 push
책보고 진행...
EC2에 접속해서 다음 명령어 입력
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install .--region ap-northeast-2
install 파일에 실행권한 추가
chmod +x ./install
install 파일로 설치를 진행
sudo ./install auto
설치가 끝났으면 Agent가 정상적으로 실행되고 있는지 상태 검사를 한다.
sudo service codedeploy-agent status
Code Build
CodeDeploy
먼저 S3에서 넘겨줄 zip 파일을 저장할 디렉토리를 하나 생성한다. EC2 서버에 접속해서 다음과 같이 디렉토리를 생성한다.
mkdir ~/app/step2 && mkdir ~/app/step2/zip
Travis CI의 Build가 끝나면 S3에 zip 파일이 전송되고, 이 zip 파일은 /home/ec2-user/app/step2/zip으로 복사되어 압축을 푼다.
Travis CI의 설정은 .travis.yml로 진행
AWS CodeDeploy는 appspec.yml로 진행한다.
version: 0.0 //(1)
os: linux
files:
-source: / //(2)
destination: /home/ec2-user/app/step2/zip/. //(3)
overwrite: yes //(4)
deploy:
...
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: springboot-webservice-deploy-mk # S3 버킷
key: freelec-springboot2-webservice.zip # 빌드 파일을 압축해서 전달
bundle_type: zip
application: springboot-webservice # 웹 콘솔에서 등록한 CodeDeploy 어플리케이션
deployment_group: springboot-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
#wait-until-deployed: true 오류가 생긴다면 주석처리
git에 푸쉬를 하면 자동으로 배포가 수행된다.
cd /home/ec2-user/app/step2/zip
파일 목록을 확인.
ll
step2에 deploy.sh 생성
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=freelec-springboot2-webservice
echo "> Build 파일 복사"
cp $REPOSITORY/zip/*.jar $REPOSITORY/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl freelec-springboot2-webservice | grep jar | awk '{print $1}') //(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 //(2)
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 & //(3)
현재는 프로젝트의 모든 파일을 zip으로 만드는데, 실제로 필요한 파일들은 Jar, appspec.yml, 배포를 위한 스크립트들이다. 이 외 나머지는 배포에 필요하지 않으니 포함하지 않는다.
before_deploy:
- mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성 //(1)
- cp scripts/*.sh before-deploy/ //(2)
- cp appspec.yml before-deploy/
- cp build/libs/*.jar before-deploy/
- cd before-deploy && zip -r before-deploy * # before-deploy로 이동후 전체 압축 //(3)
- cd ../ && mkdir -p deploy # 상위 디렉토리로 이동후 deploy 디렉토리 생성
- mv before-deploy/before-deploy.zip deploy/freelec-springboot2-webservice.zip # deploy로 zip파일 이동
permissions: //(1)
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks: //(2)
ApplicationStart:
-location: deploy.sh
timeout: 60
runas: ec2-user