[Spring Boot] Travis CI 배포 자동화 (2)

2020. 9. 22. 16:07Spring/Spring Boot

1. CodeDeploy

1) CodeDeploy 생성

AWS 배포에는 3가지가 존재한다. CodeDeploy외에는 깃허브와 같은 코드 저장소의 역할을 수행하는 Code Commit, Travis CI와 동일한 빌드용 서비스인 Code Build가 있다. (현재까지 구현된 내용에서는 Code Commit의 역할은 깃허브가, Code Build의 역할은 Travis CI가 하고 있다.)

CodeDeploy 생성

2) 배포 그룹 생성

배포 유형에는 현재 위치를 선택하되, 배포할 서비스가 2대 이상일 경우 블루/그린을 선택해야한다. 환경 구성은 EC2 인스턴스로 선택하고, 로드밸런싱을 비활성화 해준다. 배포 구성은 한번 배포할 때 몇대의 서버에 배포를 할지에 대해 결정한다.

배포 그룹 생성

3) Travis CI 연동

CodeDeploy와 Travis CI를 연동하기 위해서, 먼저 EC2에 접속하여 S3에서 넘겨줄 압축파일을 저장할 디렉토리를 생성해준다. 이 후, Travis CI의 빌드가 끝나면 S3에 압축파일을 전달하도록 한다.

mkdir ~/app/step2 && mkdir ~/app/step2/zip

Travis CI의 설정은 .travis.yml으로 진행했다면, AWS CodeDeploy의 설정은 appspec.yml 파일을 생성하여 진행한다.

어노테이션 및 코드 설명
version: 0.0 CodeDeploy 버전을 명시한다. 프로젝트 버전이 아니기에 0.0 외에 다른 버전을 사용하면 오류가 발생한다.
source CodeDeploy에서 전달해준 파일 중 destination으로 이동시킬 대상을 지정한다. 루트 경로로 설정할 경우, 전체 파일을 뜻한다.
destination source에서 지정된 파일을 받을 위치이다.
overwrite 기존 파일이 있을 경우 덮어쓰도록 설정한다.
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app/step2/zip/
    overwrite: yes

CodeDeploy 설정이 완료되면, .travis.yml 파일에도 내용을 추가해준다. 마지막으로 프로젝트를 푸시하여 배포가 수행되는 것을 확인한다.

deploy :
  - provider : s3
  ...
  
  - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY
    secret_access_key: $AWS_SECRET_KEY
    bucket: springbootprojectbucket
    key: SpringbootProject.zip # 빌드 파일 압축하여 전달

    bundle_type: zip # 압축 확장자
    application: SpringbootProject # CodeDeploy 애플리케이션
    deployment_group: SpringbootProject-group # CodeDeploy 배포 그룹
    
    region: ap-northeast-2
    wait-until-deployed: true
    
  ...

Travis CI 연동

4) 배포 자동화 구성

Travis CI, S3, CodeDeploy 연동이 완료 후 JAR를 배포하여 실행한다. 프로젝트의 루트 디렉토리에서 scripts 디렉토리를 생성하고 그 하위에 deploy.sh 스크립트를 작성한다.

어노테이션 및 코드 설명
CURRENT_PID=$(pgrep -f SpringbootProject | grep jar | awk '{print $1}') 스프링 부트 애플리케이션 이름으로 된 다른 프로그램들이 존재할 수 있기에 프로젝트명인 JAR 파일을 찾고, 프로세스를 찾은 뒤 ID를 찾는다.
chmod +x $JAR_NAME JAR 파일을 실행할 수 있는 권한을 부여한다.
$JAR_NAME > $REPOSITORY/nohup.out 2>&1 & nohup 실행 시 CodeDeploy는 무한 대기를 한다. 이를 위해 nohup.out 파일을 표준 입출력용으로 별도로 사용하여 nohup.out 파일이 사라지지 않도록 하고 CodeDeploy 로그에 표준 입출력이 출력되지 않도록 한다. nohup이 끝나기 전까지 CodeDeploy도 끝나지 않기 때문에 반드시 이렇게 설정해주어야한다.
#!/bin/bash

REPOSITORY=/home/ec2-user/app/step2

echo "> Build 파일 복사"

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

echo "> 현재 구동중인 애플리케이션 pid 확인"

CURRENT_PID=$(pgrep -f SpringbootProject | grep jar | awk '{print $1}')

echo "$CURRENT_PID"

if [ -z $CURRENT_PID ]; then
    echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
    echo "> kill -2 $CURRENT_PID"
    kill -9 $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,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.properties,classpath:/application-real.properties \
        -Dspring.profiles.active=real \
        $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

※ 스크립트는 BashSupport 플러그인을 이용하면 편집을 편리하게 할 수 있다.

5) .travis.yml 수정

프로젝트의 모든 파일을 압축파일로 만드는데 실제로 필요한 파일은JAR, appspec.yml, 배포를 위한 스크립트들이다. 그 외에는 필요하지 않기에 포함시키지 않도록 수정한다.

어노테이션 및 코드 설명
mkdir -p before-deploy Travis CIsms S3로 특정 파일만 업로드가 안되고, 디렉토리 단위로 업로드하기에 deploy 디렉토리는 항상 생성한다.
cp scripts/*.sh before-deploy/ before-deploy에는 압축파일에 포함시킬 파일들을 저장한다.
zip -r before-deploy * zip -r 명령어로 before-deploy 파일내의 모든 파일을 압축한다.
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/SpringbootProject.zip # deploy로 압축 파일 이동

deploy:
  ...

6) appspec.yml 수정

들여쓰기에 신경쓰며 permission, hooks를 추가한다.

어노테이션 및 코드 설명
permissions CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 한다.
hooks CodeDeploy 배포 단계에서 실행할 명령어를 지정한다. ApplicationStart 단계에 deploy.sh를 ec2-user 권한으로 실행하도록한다. (60초가 지나면 실패한다.)
...

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user
    
hooks:
  ApplicationStart:
    - location: deploy.sh
      timeout: 60
      runas: ec2-user

7) 구현 화면

수정한 파일 모두 저장소에 푸시를 하여 Travis CI에서 성공 메시지를 확인하고 CodeDeploy에서도 배포가 성공한 것을 확인한다. 배포의 확인을 위해 build.gradle에서 프로젝트 버전 정보와 index.mustache 파일을 수정해주고 배포한다.

구현 화면

8) CodeDeploy 추가 기능

CodeDeploy에 관한 대부분 내용은 '/opt/codedeploy-agent/deployment-root'에 있다.

/opt/codedeploy-agent/deployment-root/* 설명
영문과 '-'로 구분되어진 영문 디렉토리명 CodeDeploy ID로 사용자마다 고유한 ID가 생성되어 각자 다른 ID가 발급이 된다. 해당 디렉토리에는 배포한 단위별로 배포 파일들이 있으며, 본인의 배포 파일이 정상적으로 왔는지 확인할 수 있다.
codedeploy-agent-deployments.log
deployment-logs 디렉토리 하위에 있는 파일로 CodeDeploy로 이루어지는 배포 내용 중 표준 입/출력 내용이 모두 담겨있다.

CodeDeploy 추가 기능


[참고] 프링 부트와 AWS로 혼자 구현하는 웹 서비스

728x90

'Spring > Spring Boot' 카테고리의 다른 글

[Spring Boot] 참고 서비스  (0) 2020.09.23
[Spring Boot] 무중단 서비스  (0) 2020.09.23
[Spring Boot] Travis CI 배포 자동화 (1)  (0) 2020.09.22
[Spring Boot] AWS 배포 (2)  (0) 2020.09.19