BOOK 2 - 스프링부트와 AWS로 혼자 구현하는 웹 서비스(8)
스프링부트와 AWS로 혼자 구현하는 웹 서비스 - 8
Travis CI 배포 자동화
CI & CD
- CI (Continuous Integration) : 코드 버전 관리 시스템에 새로운 코드가 push되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
- 여러 개발자가 동시에 같은 프로젝트를 개발하면서 각자의 코드를 병합하고 빌드를 수행해야 하는 과정이 계속해서 발생하게 된다.
- 이러한 과정을 수작업으로 진행하는 것은 비효율적이기 때문에 자동으로 코드가 병합되어 테스트 코드와 빌드를 수행하는 환경을 구축하게 되었다.
- CD (Continuous Deployment) : 프로젝트 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행하는 과정
- 서비스가 여러 대의 서버에서 운영되고 있을 경우 여러 대의 서버에 수동으로 동시에 배포를 진행하기는 매우 어렵기 때문에 무중단 배포를 진행하는 환경을 구축하게 되었다.
CI의 4가지 규칙
- 모든 소스 코드가 살아 있고(현재 실행되고) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것
- 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
- 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것
- 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할 것
Travis CI 연동
- github에서 제공하는 무료 CI 서비스
- https://travis-ci.org 에서 github 계정으로 로그인하여 프로젝트를 연동할 수 있다.
프로젝트 설정
-
build.gradle파일과 같은 위치에.travis.yml파일을 생성한다.language: java jdk: - openjdk8 branches: only: - master # Travis CI 서버의 Home cache: directories: - '$HOME/.m2/repository' - '$HOME/.gradle' script: "./gradlew clean build" # CI 실행 완료시 메일로 알람 notifications: email: recipients: - hsdeb11@gmail.combranches- CI를 어느 브랜치가 푸시될 때 수행할 지 지정
- 오직
master브랜치에 푸시될 때만 수행하도록 지정했다.
cache: gradle을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여 다음 배포때부터는 같은 의존성은 다시 받지 않도록 설정한다.scriptmaster브랜치에 푸시되었을 때 수행하는 명령어 지정- 프로젝트 내부에 둔
gradlew을 통해clean& ` build` 를 수행한다.
notifications: CI 실행 완료 시 해당 메일로 알람이 가도록 설정
-
위 변경사항을 master에 push 한 후 travis CI 저장소 페이지를 확인하면 다음과 같이 빌드가 진행중인 것을 확인할 수 있다.


Travis CI와 AWS S3 연동
-
S3 : AWS에서 제공하는 일종의 파일 서버
- 이미지 파일을 비롯한 정적 파일을 관리하거나 배포 파일들을 관리하는 등의 역할을 한다.
-
다음과 같은 구조로 travis CI와 S3를 연동하여 사용하도록 한다.
- Travis CI는 build 결과인 jar 파일을 S3에 저장하고, CodeDeploy 서비스에 배포를 요청한다.
- CodeDeploy 서비스는 S3로부터 jar 파일을 전달받아 EC2에 배포를 진행한다.
-
CodeDeploy는 저장 기능이 없기 때문에 빌드 결과를 저장할 S3를 연동하여 S3에서 jar 파일을 가져오도록 하는 것이다.
AWS Key 발급
- 일반적으로 AWS 서비스에 외부 서비스가 접근할 수 없다.
- 접근 가능한 권한을 가진 key를 생성해서 사용해야 한다.
- AWS에서는 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management) 이 있다.
-
IAM을 통해 Travis CI가 AWS의 S3와 CodeDeploy에 접근할 수 있도록 해야 한다.
-
AWS 웹 콘솔에서 IAM 서비스의 사용자 > 사용자 추가 를 클릭하여 사용자를 추가한다.




-
발급된 key를 Travis CI 설정에서 environment variables로 추가한다.

- environment variables로 등록된 변수들은
.travis.yml파일에서$변수명으로 사용할 수 있다.
- environment variables로 등록된 변수들은
S3 Bucket 생성
-
S3 (Simple Storage Service)는 순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할을 한다.
-
S3 > 버킷 만들기 를 클릭하여 Travis CI에서 생성된 build 파일을 저장할 저장소를 만든다.


- 버킷의 모든 퍼블릭 액세스는 차단한다.
- 퍼블릭 액세스를 차단하지 않을 경우 Jar 파일을 누구나 내려받을 수 있어 코드나 설정값, 주요 키값들이 탈취될 수 있기 때문이다.
- 버킷의 모든 퍼블릭 액세스는 차단한다.
.travis.yml 설정 수정
...
before_deploy:
- zip -r all-review *
- mkdir -p deploy
- mv all-review.zip deploy/all-review.zip
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: all-review-springboot-build
region: ap-northeast-2
skip_cleanup: true
acl: private
local_dir: deploy
wait-until-deployed: true
before_deploydeploy명령어가 실행되기 전에 수행된다.- CodeDeploy는 Jar 파일은 인식하지 못하므로
jar + 기타 설정 파일들을 모아 압축한다. zip -r all-review *- 현재 위치의 모든 파일을
all-review이름으로 압축한다. - 명령어의 마지막 위치는 프로젝트 이름이어야 한다.
- 현재 위치의 모든 파일을
mkdir -p deploy:deploy라는 디렉토리를 Travis CI가 실행중인 위치에서 생성한다.mv all-review.zip deploy/all-review.zip: zip 파일을deploy디렉토리로 이동시킨다.
deploy: S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언한다.local_dir: deploy- 앞에서 생성한
deploy디렉토리를 지정한다. - 해당 위치의 파일들만 S3로 전송한다.
- 앞에서 생성한
-
해당 파일 변경 사항을 github에 push하면 Travis CI 빌드가 수행되어 S3 버킷에 zip파일이 업로드된 것을 확인할 수 있다.

CodeDeploy 연동
EC2에 IAM Role 추가
-
EC2가 CodeDeploy를 연동 받을 수 있도록 IAM Role을 추가한다.
사용자와 역할의 차이점이 무엇일까?
- 사용자 : AWS 서비스 외에 사용할 수 있는 권한
- 로컬 PC, IDC 서버 등
- 역할 : AWS 서비스에만 할당할 수 있는 권한
- EC2, CodeDeploy 등
- 사용자 : AWS 서비스 외에 사용할 수 있는 권한
-
IAM 서비스의 역할 > 역할 만들기 를 클릭하여 역할을 추가한다.



-
생성한 역할을 EC2 인스턴스에 IAM Role로 설정한다. EC2 서비스에서 인스턴스 설정 > IAM 역할 수정 에서 설정한다.

-
IAM Role 설정 후에는 재부팅을 해야 적용되므로 재부팅을 해준다.
CodeDeploy 에이전트 설치
-
EC2 인스턴스에 접속 후 다음 명령어를 실행한다.
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2chmod +x ./install sudo ./install auto -
설치가 끝났으면 Agent가 정상적으로 실행되고 있는지 상태 검사를 한다.
sudo service codedeploy-agent status
CodeDeploy IAM Role 생성
-
CodeDeploy에서 EC2에 접근하기 위해 IAM Role을 생성한다.
-
IAM 서비스 역할 만들기에서 AWS 서비스 > CodeDeploy 를 선택하여 생성한다.

CodeDeploy 생성
-
CodeDeploy 서비스의 애플리케이션 > 애플리케이션 생성 을 클릭하여 생성한다.

-
어플리케이션 생성 후 배포 그룹을 생성한다.



Travis CI, S3, CodeDeploy 연동
-
EC2 서버에 S3에서 받은 zip 파일을 저장할 디렉토리를 생성한다.
mkdir ~/app/step2 && mkdir ~/app/step2/zip- Travis CI의 build가 끝나면 S3에 zip 파일이 전송되고, 이 zip 파일은
home/ec2-user/app/step2/zip디렉토리로 복사되어 압축을 풀 예정이다.
- Travis CI의 build가 끝나면 S3에 zip 파일이 전송되고, 이 zip 파일은
appspec.yml
-
CodeDeploy 설정 파일인
appspec.yml파일을 추가한다.version: 0.0 os: linux files: - source: / destination: /home/ec2-user/app/step2/zip/ overwrite: yes-
version: 0.0: CodeDeploy 버전 -
source- CodeDeploy에서 전달해준 파일 중
destination으로 이동시킬 대상을 지정한다. /로 지정하면 전체 파일을 지정하는 것이다.
- CodeDeploy에서 전달해준 파일 중
-
destinationsource에서 지정된 파일을 받을 위치를 지정한다.- 이후 jar 파일을 실행하는 등은
destination에서 옮긴 파일들로 진행된다.
-
overwrite: 기존에 파일들이 존재할 때 덮어쓸지를 결정한다.
-
.travis.yml
-
기존
.travis.yml파일에 CodeDeploy 내용을 추가한다.... deploy: ... - provider: codedeploy access_key_id: $AWS_ACCESS_KEY secret_access_key: $AWS_SECRET_KEY bucket: all-review-springboot-build key: all-review.zip bundle_type: zip application: all-review deployment_group: all-review-group region: ap-northeast-2 wait-until-deployed: true
배포 자동화 구성
- 연동된 Travis CI, S3, CodeDeploy를 기반으로 실제로 jar 파일을 배포하여 실행하는 것까지 구현한다.
deploy.sh 파일 추가
-
step2 환경에서 실행될
deploy.sh를 생성한다.#! /bin/bash REPOSITORY=/home/ec2-user/app/step2 PROJECT_NAME=all-review echo "> Copy Build File" cp $REPOSITORY/zip/*.jar $REPOSITORY/ echo "> Check Running Application PID" CURRENT_PID=$(pgrep -fl all-review | grep jar | awk '{print $1}') echo "Running Application PID : $CURRENT_PID" if [ -z "$CURRENT_PID" ]; then echo "> There's no running application." else echo "> Kill $CURRENT_PID" kill -15 $CURRENT_PID sleep 5 fi echo "> New Application Deployment" JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) echo "> Jar Name : $JAR_NAME" chmod +x $JAR_NAME echo "> Execute $JAR_NAME" nohup java -jar \-Dspring.config.location=classpath:/application.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-prod-db.properties \-Dspring.profiles.active=production \ $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &nohup실행시 CodeDeploy는 무한 대기한다.- 이 이슈를 해결하기 위해
nohup.out파일을 표준 입출력용으로 별도로 사용한다.
.travis.yml 파일 수정
-
실제 배포에 필요한 파일들만 zip 하기 위해서
before_deploy부분을 수정한다.before_deploy: - mkdir -p before-deploy - cp scripts/*.sh before-deploy/ - cp appspec.yml before-deploy/ - cp build/libs/*.jar before-deploy/ - cd before-deploy && zip -r before-deploy * - cd ../ && mkdir -p deploy - mv before-deploy/before-deploy.zip deploy/all-review.zip- 배포에 필요한 jar 파일들(라이브러리 파일 포함),
appspec.yml, 배포 스크립트 파일들을before-deploy디렉토리에 복사하여before-deploy디렉토리 전체를 압축한다. - 압축한 파일은
deploy디렉토리에all-review.zip이라는 이름으로 복사하여 이동시켜 놓는다.
- 배포에 필요한 jar 파일들(라이브러리 파일 포함),
appspec.yml 파일 추가
...
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
ApplicationStart:
- location: deploy.sh
timeout: 60
runas: ec2-user
permissions: CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두ec2-user권한을 갖도록 한다.hooks- CodeDeploy 배포 단게에서 실행할 명령어를 지정한다.
ApplicationStart라는 단계에서deploy.sh를ec2-user권한으로 실행하게 한다.
해당 변경 사항을 github에 push하면 Travis CI를 통해 Build 되고, build된 파일은 압축되어 S3를 통해 CodeDeploy로 EC2에 배포되게 된다.