아무거나

[springboot] gradle 개발환경별 버저닝 빌드&배포 본문

Infra/DevOps

[springboot] gradle 개발환경별 버저닝 빌드&배포

전봉근 2019. 8. 21. 10:36
반응형

​[springboot gradle 개발환경별 버저닝 빌드&배포]

 

개발환경 기준 : dev, stage, master(=live)

사용툴 : jenkins + s3 + codedeploy

 

[빌드]

 

1. build.gradle에 저장될 jar이름 설정(안하면 jenkins item이름으로 기본정의됨)

jar {
	archivesBaseName = "test"
}

 

 

2. build 부분에서 Add build step -> Invoke Gradle script 선택

 

 

3. jekins item 설정에서 Build 부분에서 Use Gradle Wrapper 버튼 클릭하고 설정

- Make gradlew executable 체크

- Wrapper location: ${workspace}  // ${workspace}는 해당 item 경로

- Tasks: clean build

 

 

4. 빌드하고 해당 프로젝트 경로에 /build/libs 를 확인해보면 jar파일이 생성되어있다.​ 

 

5. jenkins쪽 build시 실행될 script파일을 생성하자.

   [springboot_build.sh]   

#!/bin/bash

if [ "$#" -ne 3 ];
then
echo "Bad Not Request Parameters"
else
# parameters check
if [ $2 = "dev" -o $2 = "stage" -o $2 = "master" ];
then
# aws define
jenkinsDir="/var/lib/jenkins/workspace"
jenkinsProjectDir="$jenkinsDir/$1"
jenkinsBuildDir="$jenkinsProjectDir/build/libs"

# s3 define
s3Buckets="s3://ws.bucket/$3"
s3Region="ap-northeast-2"

# bucket object check
s3BucketObj=$(aws s3 ls $s3Buckets/)
s3BucketObjLen=${#s3BucketObj}

if [ $s3BucketObjLen -gt 0 ];
then
buildFileName=$(cd $jenkinsBuildDir/ && ls -td1 *.jar)
echo "Output Build File Name"
echo $buildFileName

if [ -f $jenkinsBuildDir/$buildFileName ]
then
if [ $2 = "master" ];
then
echo "-------------------- MASTER -------------------"

current_version="0.0.0"
before_version="0.0.0"

# version file check
if [ -f "$jenkinsProjectDir/current_version.txt"  ]
then
before_version=$(cat $jenkinsProjectDir/current_version.txt)
echo "current version : $before_version"

if [ $before_version = "9.9.9" ]; then
echo "---------------------------ERROR-----------------------------"
echo "-----------------------version full.........................."
echo "---------------------------ERROR-----------------------------"
exit
fi
else
echo "0.0.0" > $jenkinsProjectDir/current_version.txt
fi

aws s3 cp $s3Buckets/$3_$2_$current_version.tar.gz $jenkinsProjectDir/$3_$2_$current_version.tar.gz --region $s3Region
aws s3 cp $s3Buckets/$3_$2_$before_version.tar.gz $jenkinsProjectDir/$3_$2_$before_version.tar.gz --region $s3Region

# versioning
if [ -f "$jenkinsProjectDir/$3_$2_0.0.0.tar.gz" ];
then
vn=$(cd $jenkinsProjectDir/ && ls -td1 *.gz | head -n 1)
vc=$(echo $vn | cut -f 5 -d '_')
vMajor=$(echo $vc | awk '{ split($0, vArr, "."); print vArr[1] }')
vMinor=$(echo $vc | awk '{ split($0, vArr, "."); print vArr[2] }')
vPatch=$(echo $vc | awk '{ split($0, vArr, "."); print vArr[3] }')

# version terms
# patch
if [ $vPatch -ge 9 ]
then
vPatch=0
vMinor=$(($vMinor+1))
else
vPatch=$(($vPatch+1))
fi

# minor
if [ $vMinor -ge 9 ]
then
vMinor=0
vMajor=$(($vMajor+1))
fi

# major
if [ $vMajor -ge 9 ]; then
echo "Major Version Max Error"
fi

current_version=$vMajor.$vMinor.$vPatch

rm -r $jenkinsProjectDir/current_version.txt
echo $current_version > $jenkinsProjectDir/current_version.txt
rm -r $jenkinsProjectDir/$3_$2_0.0.0.tar.gz
rm -r $jenkinsProjectDir/$3_$2_$before_version.tar.gz
fi

cd $jenkinsProjectDir && tar -zcvf $jenkinsProjectDir/$3_$2_latest.tar.gz .
cd $jenkinsProjectDir && tar -zcvf $jenkinsProjectDir/$3_$2_$current_version.tar.gz .
aws s3 cp $jenkinsProjectDir/$3_$2_latest.tar.gz $s3Buckets/ --region $s3Region
aws s3 cp $jenkinsProjectDir/$3_$2_$current_version.tar.gz $s3Buckets/ --region $s3Region
rm -r $jenkinsProjectDir/$3_$2_latest.tar.gz
rm -r $jenkinsProjectDir/$3_$2_$current_version.tar.gz
else
echo "--------------------DEV, STAGE-----------------"

version="0.0.0"
cd $jenkinsProjectDir && tar -zcvf $jenkinsProjectDir/$3_$2_$version.tar.gz .
aws s3 cp $jenkinsProjectDir/$3_$2_$version.tar.gz $s3Buckets/ --region $s3Region
rm -r $jenkinsProjectDir/$3_$2_$version.tar.gz
fi
else
echo "ERROR : Jar File Empty!!!!!"
fi

else
echo "S3Bucket Object empty!!!"
fi
else
echo "Bad Not Request Parameters( value = dev, stage, master )"
fi

echo "$2 build finish !! [jenkins item : $1 , version : $current_version ] "
fi

 

 

 

 

6. jenkins 빌드 아이템 설정에서 build의 순서를 지켜야된다

   - Execute shell(gradle build) -> Invoke Gradle script(gradle jar 생성) -> Execute shell(빌드 스크립트 + s3업로드)

 

---------------------------------------- 여기까지 빌드이다. -------------------------------------------------------

 

[배포]

 

1. 최상위 루트에 appspec.yml 추가 및 스크립트 폴더 추가 (codedeploy가 읽음)

   [appspec.yml]

version: 0.0
os: linux
files:
  - source:  /
    destination: /app/api/build/
hooks:
  AfterInstall:
    - location: scripts/execute-deploy.sh
      timeout: 180

 

 

   * 최상위 루트에 실행할 스크립트를 모아둘 폴더 생성 scripts/execute-deploy.sh

   [execute-deploy.sh]

#!/bin/bash
/home/ubuntu/app/api/deploy.sh > /dev/null 2> /dev/null < /dev/null &

 

2. 배포될 폴더 생성

   - mkdir /app

   - mkdir /app/api

   - mkdir /app/api/build

   - mkdir /app/api/jar

   - sudo chown -R ubuntu:ubuntu app

 

   [deploy.sh]

#!/bin/bash 

REPOSITORY=/home/ubuntu/app/api 

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

CURRENT_PID=$(pgrep -f ws_internal_api) 

echo "$CURRENT_PID" 

if [ -z $CURRENT_PID ]; then 
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." 
else 
echo "> kill -15 $CURRENT_PID" 
kill -15 $CURRENT_PID 
sleep 5 
fi 

echo "> 새 어플리케이션 배포" 

echo "> Build 파일 복사" 

cp $REPOSITORY/build/build/libs/*.jar $REPOSITORY/jar/ 
JAR_NAME=$(ls $REPOSITORY/jar/ |grep 'ws_internal_api' | tail -n 1) 

echo "> JAR Name: $JAR_NAME" 

nohup java -jar -Dspring.profiles.active=dev $REPOSITORY/jar/$JAR_NAME &

 

 

(1) CURRENT_PID=$(pgrep -f ws_internal_api)

    - 기존에 수행중이던 스프링부트 어플리케이션을 종료합니다.

    - pgrep은 process id만 추출하는 명령어입니다.

    - -f 옵션은 프로세스 이름으로 찾습니다.

    - 좀 더 자세한 옵션을 알고 싶으시면 공식 홈페이지를 참고하시면 좋습니다.

 

(2) if ~ else ~ fi

    - 현재 구동중인 프로세스가 있는지 없는지 여부를 판단해서 기능을 수행합니다.

    - process id값을 보고 프로세스가 있으면 해당 프로세스를 종료합니다.

 

(3) JAR_NAME=$(ls $REPOSITORY/ | grep 'ws_internal_api' | tail -n 1)

    - 새로 실행할 jar 파일명을 찾습니다.

    - 여러 jar파일이 생기기 때문에 tail -n로 가장 나중의 jar파일(최신 파일)을 변수에 저장합니다.

 

(4) nohup java -jar $REPOSITORY/$JAR_NAME &

    - 찾은 jar파일명으로 해당 jar파일을 nohup으로 실행시킵니다.

    - 스프링부트의 장점으로 특별히 외장 톰캣을 설치할 필요가 없습니다.

    - 내장 톰캣을 사용해서 jar 파일만 있으면 바로 웹 어플리케이션 서버가 실행할수 있습니다.

    - 좀 더 자세한 스프링부트의 장점을 알고 싶으시면 이전에 작성한 SpringBoot의 깨알같은 팁을 참고하시면 좋습니다.

    - 일반적으로 Java를 실행시킬때는 java -jar라는 명령어를 사용하지만, 이렇게 할 경우 사용자가 터미널 접속을 끊을 경우 어플리케이션도 같이 종료가 됩니다.

    - 어플리케이션 실행자가 터미널을 종료시켜도 어플리케이션은 계속 구동될 수 있도록 nohup명령어를 사용합니다.

 

 

* nohup은 실행시킨 jar파일의 로그 내용을 nohup.out 이란 파일에 남깁니다.

    - nohup java -jar /home/ubuntu/app/travis/build/build/libs/springboot_restapi-0.0.1.jar &

    - tail -f /home/ubuntu/nohup.out  // 잘 수행되었는지 확인.

    - chmod 755 /home/ubuntu/app/travis/deploy.sh  // 스크립트 실행을 위한 권한 부여

 

- /home/ubuntu/app/travis/deploy.sh  // 스크립트 작동 확인

- ps -ef | grep springboot_restapi  // 실행되어있는지 확인​ 

 

 

 

참고: https://jojoldu.tistory.com/

반응형
Comments