[Docker] Docker, ELB, 스프링부트 무중단 배포 구성하기

Docker, ELB, Spring Boot를 활용하여 무중단 배포 환경을 구축하는 방법과 간단한 배포 스크립트를 소개합니다.

 

프로젝트를 진행하다가, (Docker, ELB, Spring Boot) 를 이용하여 무중단 배포 환경을 구성하는 업무를 맡게 되었다.

젠킨스를 통해서 작업을 진행하였으며, 다음은 젠킨스에서 실행될 Shell Script 이다.


#!/bin/bash

## Jenkins build file
$WORKSPACE/mvnw clean package -DskipTests

APP_URL="https://member-api.wiselycompany.com"
BASE_PATH=$WORKSPACE
BUILD_PATH=$(ls $BASE_PATH/target/*.jar)
JAR_NAME=$(basename $BUILD_PATH)
APP_NAME="whale-member-api"
JENKINS_URL="deploy.wiselyshave.com"
APP_01_IP="13.124.117.87"
APP_02_IP="54.180.42.63"
KEYFILE_PATH="/var/jenkins_home/aws-keys/wisely-db.pem"
DEPLOY_USER="deploy"
SERVER_LOG_PATH="/data/logs/WHALE-MEMBER-API"
CONTAINER_LOG_PATH="/app/logs"
DOCKER_PORT=8081

AWS_LISTNER_ARN=arn:aws:elasticloadbalancing:ap-northeast-2:401745125627:listener/app/WS2-ELB-MEMBER-API/02768760c721a10f/e3bf56008804b46e
AWS_BLUE_TARGETGROUP_ARN=arn:aws:elasticloadbalancing:ap-northeast-2:401745125627:targetgroup/WS2-ELB-MEMBER-API-8080/d2cc1d3ad8ee0c5c
AWS_GREEN_TARGETGROUP_ARN=arn:aws:elasticloadbalancing:ap-northeast-2:401745125627:targetgroup/WS2-ELB-MEMBER-API-8081/1c884bbe32a65374


echo "> 현재 구동중인 Set 확인"
CURRENT_PROFILE=$(curl -s $APP_URL/profile.do)
echo "> $CURRENT_PROFILE"


if [ $CURRENT_PROFILE == blue ]
then
  IDLE_PROFILE=green
  IDLE_PORT=8081
elif [ $CURRENT_PROFILE == green ]
then
  IDLE_PROFILE=blue
  IDLE_PORT=8080
else
  echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE"
  echo "> blue를 할당합니다. IDLE_PROFILE: blue"
  CURRENT_PROFILE=green
  IDLE_PROFILE=blue
  IDLE_PORT=8080
fi


docker build -t $APP_NAME -f ./docker-files/$IDLE_PROFILE/Dockerfile .
docker tag $APP_NAME localhost:5000/$APP_NAME
docker push localhost:5000/$APP_NAME
docker image prune -f

ssh -tt -i $KEYFILE_PATH $DEPLOY_USER@$APP_01_IP <<ENDSSH

  echo '$APP_01_IP에 $IDLE_PROFILE 배포'
    docker pull $JENKINS_URL:5000/$APP_NAME:latest
    docker stop \$(docker ps -a -q --filter "name=$APP_NAME-$IDLE_PROFILE")
    sleep 5
    docker image prune -f
    sleep 5
    docker run --name="$APP_NAME-$IDLE_PROFILE" \
               -v $SERVER_LOG_PATH:$CONTAINER_LOG_PATH:rw \
               --rm -d \
               -p $IDLE_PORT:$DOCKER_PORT $JENKINS_URL:5000/$APP_NAME:latest

  exit;

ENDSSH

ssh -tt -i $KEYFILE_PATH $DEPLOY_USER@$APP_02_IP <<ENDSSH

    echo '$APP_01_IP에 $IDLE_PROFILE 배포'
    docker pull $JENKINS_URL:5000/$APP_NAME:latest
    docker stop \$(docker ps -a -q --filter "name=$APP_NAME-$IDLE_PROFILE")
    sleep 5
    docker image prune -f
    sleep 5
    docker run --name="$APP_NAME-$IDLE_PROFILE" \
               -v $SERVER_LOG_PATH:$CONTAINER_LOG_PATH:rw \
               --rm -d \
               -p $IDLE_PORT:$DOCKER_PORT $JENKINS_URL:5000/$APP_NAME:latest

  exit;

ENDSSH


## AWS ELB 의 Target Group 을 변경
## blue : 8080 / green : 8081

if [ $IDLE_PROFILE == blue ]
then
    aws elbv2 modify-listener --listener-arn $AWS_LISTNER_ARN --default-actions Type=forward,TargetGroupArn=$AWS_BLUE_TARGETGROUP_ARN
elif [ $IDLE_PROFILE == green ]
then
    aws elbv2 modify-listener --listener-arn $AWS_LISTNER_ARN --default-actions Type=forward,TargetGroupArn=$AWS_GREEN_TARGETGROUP_ARN
else
  echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE"

fi

 


 

만약, 무중단 배포가 필요 없는 상황이라면, 다음과 같은 단순 배포 스크립트를 구성할 수 있다.

 

#!/bin/bash

## Jenkins build file
$WORKSPACE/mvnw clean package -DskipTests

BASE_PATH=$WORKSPACE
BUILD_PATH=$(ls $BASE_PATH/target/*.jar)
JAR_NAME=$(basename $BUILD_PATH)
APP_NAME="whale-transaction-reconcile"
JENKINS_URL="deploy.wiselyshave.com"
APP_IP_01="172.31.25.214"

KEYFILE_PATH="/var/jenkins_home/aws-keys/wisely-web.pem"
DEPLOY_USER="ec2-user"
SERVER_LOG_PATH="/data/logs/WHALE-TRANSACTION-RECONCILE"
CONTAINER_LOG_PATH="/app/logs"
DOCKER_PORT=8080


IDLE_PROFILE=prod 
IDLE_PORT=8090

docker build -t $APP_NAME -f ./docker-files/$IDLE_PROFILE/Dockerfile .
docker tag $APP_NAME localhost:5000/$APP_NAME
docker push localhost:5000/$APP_NAME
docker image prune -f

ssh -tt -i $KEYFILE_PATH $DEPLOY_USER@$APP_IP_01 <<ENDSSH

  echo '$APP_01_IP에 $IDLE_PROFILE 배포'
    docker pull $JENKINS_URL:5000/$APP_NAME:latest
    docker stop \$(docker ps -a -q --filter "name=$APP_NAME-$IDLE_PROFILE")
    docker run --name="$APP_NAME-$IDLE_PROFILE" \
               -v $SERVER_LOG_PATH:$CONTAINER_LOG_PATH:rw \
               -v /etc/localtime:/etc/localtime:ro -v /usr/share/zoneinfo/Asia/Seoul:/etc/timezone:ro \
               --rm -d \
               -p $IDLE_PORT:$DOCKER_PORT $JENKINS_URL:5000/$APP_NAME:latest
    docker image prune -f
  exit;

ENDSSH

 


이것도 읽어보세요