spring

springboot & AWS - Travis CI 배포 자동화

Jan 11, 2020

코드가 푸쉬되면 자동으로 배포해 보자

목차

1. Travis CI 배포 자동화
1.1 CI & CD 소개
1.2 Travis CI 연동하기
1.3 Travis CI와 AWS S3 연동하기
1.4 Travis CI와 AWS S3 CodeDeploy 연동하기
1.5 배포 자동화 구성
1.6 CodeDeploy 로그 확인

1. Travis CI 배포 자동화

여러 개발자의 코드가 실시간으로 병합되고, 테스트가 수행되는 환경, master 브랜치가 푸시되면 배포가 자동으로 이루어지는 환경을 구축하지 않으면 실수할 여지가 너무나 많다. 지속 가능한 통합 환경을 구축하고 배포해야 한다.

1.1 CI & CD 소개

CI(Continuous Integration - 지속적 통합) : VCS 시스템에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정

CD(Continuous Deployment - 지속적인 배포) : 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정

일반적으로 CI만 구축되어 있지는 않고, CD도 함께 구축된 경우가 대부분이다.

하나의 프로젝트를 여러 개발자가 개발하게되는데 예전에는 각자가 개발한 코드를 매주 병합일을 정해서 각자 개발한 코드를 합치기만 했다. 이런 수작업은 생산성이 좋지 않기 때문에 개발자들은 지속 가능한 통합 환경(CI)를 구축했다.

여기서 주의할 점은 단순히 CI 도구를 도입했다고 해서 CI를 하고 있는 것은 아니다. CI에 대하 4가지 규칙이 있다.

여기서 특히나 중요한 것은 테스팅 자동화다. 지속적으로 통합하기 위해서는 무엇보다 이 프로젝트가 완전한 상태임을 보장하기 위해 테스트 코드가 구현되어 있어야만 한다.

1.2 Travis CI 연동하기

Travis CI는 깃헙에서 제공하는 무료 CI 서비스다. 젠킨스는 설치형이기 때문에 이를 위한 EC2 인스턴스 하나가 더 필요하다. AWS에서 CI 도구로 CodeBuild를 제공하는데 빌드 시간만큼 요금이 발생한다.

1.3 Travis CI와 AWS S3 연동하기

S3란 AWS에서 제공하는 일종의 파일 서버다. 이미지 파일 등과 같은 정적 파일들을 관리하거나 배포 파일들을 관리하는 등의 기능을 지원한다. 보통 이미지 업로드를 구현한다면 이 S3를 이용하여 구현하는 경우가 많다.

첫 번째 단계로 Travis CI와 S3를 연동한다. 실제 배포는 AWS CodeDeploy라는 서비스를 이용한다. S3 연동이 먼저 필요한 이유는 Jar 파일을 전달하기 위해서다. CodeDeploy는 저장 기능이 없어서 S3를 이용한다.

CodeDeploy가 빌드도 하고 배포도 할 수 있으나 빌드 없이 배포만 할 때 대응이 어렵다. 웬만하면 빌드와 배포는 분리하는 것이 좋다.

1.4 Travis CI와 AWS S3 CodeDeploy 연동하기

version: 0.0
os: linux
files:
    - source:  /
        destination: /home/ec2-user/app/step2/zip/
        overwrite: yes
- deploy :
    ...
    - provider: codedeploy 
    access_key_id: $AWS_ACCESS_KEY 
    secret_access_key: $AWS_SECRET_KEY
    bucket: webservice-build
    key: springboot-webservice.zip
    bundle_type : zip
    application : springboot-webservice
    deployment_group: deployment-group
    region: ap-northeast-2
    wait-until-deployed: true

1.5 배포 자동화 구성

#!/bin/bash

REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=projcet name

echo "> Build 파일 복사"

cp $REPOSITORY/zip/*.jar $REPOSITORY/

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/*.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 &
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/seungui-springboot-webservice.zip # deploy로 zip파일 이동
- Travis CI는 S3로 특정 파일만 업로드가 안 된다.
    - 디렉토리 단위로만 업로드 할 수 있기 때문에 deploy 디렉토리는 항상 생성한다.
- before-deploy에는 zip 파일에 포함시킬 파일들을 저장한다.
- zip -r 명령어를 통해 before-deploy 디렉토리 전체 파일을 압축한다.
version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ec2-user/app/step2/zip/
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  ApplicationStart:
    - location: deploy.sh
      timeout: 60
      runas: ec2-user

1.6 CodeDeploy 로그 확인