CI & CD
CI(Continuous Integration) - 지속적인 통합?
VCS 시스템을 통해 새로운/변경된 Resource 에 대해 자동으로 테스트 또는 빌드 수행 후 안정적인 배포 파일을 생성하는 과정
CD(Continuous Deployment) - 지속적인 배포?
빌드 결과를 자동으로 운영 서버에 무중단 배포하는 과정
why? Travis CI?
- Github 와의 상호 연동(혹은 의존성)
- Slack, Mail .. 다양한 메신저 연동 가능
Travis CI 연동 과정
1. Travis CI 설정
- Travis CI Web Service 에서 Github 계정 로그인
- Travis Settins 에서 연동할 Github repository 활성화
2. 프로젝트 Travis CI 설정
travis.yml
추가
! build.gradle 동일한 위치에 추가 !
language: java
jdk: openjdk8
# Travis CI 를 어느 branch 가 push 될 때 수행할지 설정
branches:
only: master
# gradle 통해 의존서을 받게 되면 해당 디렉토리에 cache 하여,
# 같은 의존성은 다음 배포 때부터 받지 않도록 설정
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
before_install:
- chmod +x gradlew
# branch 에 push 되었을 때 수행하는 명령어
script: "./gradlew clean build"
# Travis CI 실행 완료 후 자동 알림 설정
notifications:
email:
recipients:
- [메일 주소]
3. Travis CI + AWS S3 연동
AWS S3?
- AWS에서 제공하는 파일 서버로서, 정적 파일 관리 또는 배포 파일 관리 기능 제공 서비스
AWS 와 Travis CI 연동 프로세스
IAM 사용자 만들기
- 사용자 세부 정보 설정
- 사용자 이름 >
jimmyberg-travis-deploy
- AWS 액세스 유형 선택 > 프로그래밍 방식 액세스
- 사용자 이름 >
- 권한 설정
- 기존 정책 직접 연결
AmazonS3FullAccess
AmazonCodeDeployFullAccess
- 기존 정책 직접 연결
- 태그 추가
- 키 :
Name
, 값 :jimmyberg-travis-deploy
- 키 :
Travis CI에 S3 액세스 키 등록
- 연동한 repository 의 settings 에서 키 등록
AWS_ACCESS_KEY
: 액세스 키AWS_SECRET_KEY
: 비밀 액세스 키
- .travis.yml 에서
$AWS_ACCESS_KEY
,$AWS_SECRET_KEY
으로 사용
S3 버킷 생성
- 버킷 이름 >
jimmyberg-rest-api
.travis.yml
수정
...
script: "./gradlew clean build"
# 수정 start
# deploy 가 실행되기 전에 수행
# CodeDeploy 는 Jar 파일 인식하지 못하므로
# 프로젝트를 압축한 zip 파일로 전달
before_deploy:
- zip -r rest-api ./*
- mkdir -p deploy
- mv rest-api.zip deploy/rest-api.zip
# 외부 서비스와 연동될 명령어 정의
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: jimmyberg-rest-api
region: ap-northeast-2
skip_cleanup: true
acl: private
local_dir: deploy # 지정한 위치의 파일들만 S3로 전송
wait_until_deployed: true
# 수정 end
notifications:
...
4. Travis CI + S3 + CodeDeploy
EC2 에 IAM 역할 추가
ec2-codedeploy-role
역할 만들기- EC2 > 인스턴스 설정 > IAM 역할 연결/바꾸기
ec2-codedeploy-role
역할 선택- EC2 인스턴스 재부팅
EC2 에 CodeDeploy agent 설치
$ aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install ./s3 --resion ap-northeast-2
# 설치 디렉토리 이동
$ cd s3
# 실행 권한 추가
$ chmod +x ./install
# install 파일 설치
$ sudo ./install auto
# CodeDeploy agent 상태 확인
$ sudo service codedeploy-agent status
CodeDeploy 권한 생성
- IAM 역할
CodeDeploy
선택
- 정책
AWSCodeDeployRole
선택
- 태그 추가
- 키 :
Name
, 값 :codedeploy-role
- 키 :
CodeDeploy 생성
- 애플리케이션 생성
- 애플리케이션 구성
- 애플리케이션 이름 :
rest-api
- 컴퓨팅 플랫폼 :
EC2/온프레미스
- 애플리케이션 이름 :
- 배포그룹 생성
- 배포그룹 이름 :
rest-api-group
- 서비스 역할 :
codedeploy-role
- 배포 유형 :
현재 위치
선택(배포할 서비스가 2대 이상이라면블루/그린
선택) - 환경 구성 :
Amazon EC2 인스턴스
- 태그 추가
- 키 :
Name
, 값 :Amazon Linux Web Server
- 키 :
- 배포그룹 이름 :
- 배포 설정
CodeDeployDefault.AllAtOnce
선택
- 로드 밸런서 해제
- 애플리케이션 구성
연동 설정 파일 추가 및 수정
- EC2 에 zip 파일 저장 디렉토리 생성
$ mkdir /home/ec2-user/s3/zip/rest-api
appspec.yml
추가
version: 0.0
os : linux
files :
# CodeDeploy 에서 전달해준 파일 중 destination 으로 이동시킬 대상 지정
- source : /
# source 에서 지정된 파일을 저장할 위치
destination: /home/ec2-user/s3/zip/rest-api/
# 덮어쓰기 여부
overwrite : yes
.travis.yml
수정
deploy:
...
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: jimmyberg-rest-api
key: rest-api.zip
bundle_type: zip
application: rest-api
deployment_group: rest-api-group
region: ap-northeast-2
wait_until_deployed: true
- EC2 에 저장된 zip 디렉토리 확인
5. 배포 자동화 구성
프로젝트에 deploy.sh
추가
# project > scripts > deploy.sh
#!/bin/bash
REPOSITORY=/home/ec2-user/apps
DEPLOY_DIRECTORY=/home/ec2-user/deploy
PROJECT_NAME=rest-api
echo "> Build 파일 복사"
cp $DEPLOY_DIRECTORY/$PROJECT_NAME/*.jar $REPOSITORY/$PROJECT_NAME/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl $PROJECT_NAME | 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/$PROJECT_NAME/*.jar | tail -n 1)
echo "> JAR Name: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행"
rm $REPOSITORY/$PROJECT_NAME/nohup.out
nohup java -jar -Dspring.profiles.active=alpha -Dfile.encoding=UTF-8 $JAR_NAME > $REPOSITORY/$PROJECT_NAME/nohup.out 2>&1 &
.travis.yml
수정
language: java
jdk:
- openjdk8
branches:
only:
- master
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
before_install:
- chmod +x gradlew
script: "./gradlew clean build"
before_deploy:
- echo $(pwd)
- 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/rest-api.zip
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: jimmyberg-rest-api
region: ap-northeast-2
skip_cleanup: true
acl: private
local_dir: deploy
wait-until-deployed: true
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: jimmyberg-rest-api
key: rest-api.zip
bundle_type: zip
application: rest-api
deployment_group: rest-api-group
region: ap-northeast-2
wait-until-deployed: true
notifications:
slack: [slack accesss key]
appspec.yml
수정
version: 0.0
os : linux
files :
- source : /
destination: /home/ec2-user/deploy/rest-api
overwrite : yes
# CodeDeploy 에서 EC2 로 넘겨준 파일 모두 ec2-user 권한 설정
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
# CodeDeploy 배포 단계에서 실행할 명령어 설정
# ApplicationStart 단계 : ec2-user 권한으로 deploy.sh 실행
hooks:
ApplicationStart:
- location: deploy.sh
timeout: 60
runas: ec2-user
배포 Log 확인 방법
CodeDeploy 관련 Log
$ cd /opt/codedeploy-agent/deploayment-root/
$ vi ./deployment-logs
프로젝트 관련 Log
$ cd ~/apps/rest-api/
$ vi ./nohup.out