DevOps

AWS 자동 배포하기 (2) - CodeDeploy : 무중단배포

팅리엔 2021. 3. 18. 22:26

[이전 글]

GitLab pipeline 빌드된 Jar를 AWS S3에 저장하기

AWS 자동 배포하기 (1) - EC2, Auto Scaling, Load Balancing

 

 

이 글에선

Code Deploy를 통해 무중단 배포 자동화 하는 방법에 대해 알아본다.

 

훑어보기

소스를 수정하고 배포할 때마다 서비스가 중단되면 정기 점검날을 정해두고 배포를 진행해야 할 것이다.

사용자가 서비스를 끊김 없이 사용하도록 하기 위해 무중단 배포를 진행하는 것이 좋다.

(하지만 애플리케이션 코드나 데이터베이스 스키마의 구, 신 버전이 동시에 서비스되면 안 되는 경우 등에는 중단 배포를 하거나 별도의 처리가 있어야 한다.)

  1. 애플리케이션 코드를 AWS S3에 업로드 한다.
  2. CodeDeploy에게 배포를 요청한다.
  3. CodeDeploy는 EC2에 설치된 CodeDeploy Agent에게 배포를 요청한다.
  4. CodeDeploy Agent는 애플리케이션 코드를 코드 저장소에서 서버에 내려받고, AppSpec.yml 파일에 기재된 절차대로 배포를 진행한다.

 

무중단 배포 기법

먼저 배경 지식으로 무중단 배포 기법에 대해 알아본다.

현재 위치 배포 (in-place deployment)

  • 4대의 서버에 배포를 한다고 치면, 서버 앞에 로드밸런서를 두고 2대의 서버로만 요청이 가게 한 후 나머지 2대에 배포를 진행한다. 2대에 배포가 끝나면 이 서버들로 요청이 가도록 바꾼 후 다른 2대에 배포를 진행한다.
  • 서버를 새롭게 생성하거나 줄이지 않는다.
  • 배포하는 중에는 클라이언트의 요청을 받는 인스턴스의 수가 줄어든다는 것을 유의해야 한다.
  • 롤백해야 하는 경우 이전 버전으로 다시 배포를 진행해야 한다.

서버 단위의 블루/그린 배포

  • v1 버전이 배포되어 있는 서버들(블루 그룹)과 똑같은 수의 서버 인스턴스를 만들고 이 새로운 서버들(그린 그룹)에 v2 버전을 배포한다. 배포가 완료되면 그린 그룹을 로드 밸런서에 등록하고 블루 그룹을 로드 밸런서에서 제외한다.
  • 구, 신 버전이 동시에 서비스되는 시간을 짧게 처리할 수 있다.
  • 롤백은 로드밸런서 등록, 해제만 하면 되므로 빠르게 처리할 수 있다.

서버 내 블루/그린 배포

  • 위의 서버 단위로 블루/그린 배포를 할 수도 있지만 하나의 서버 내에서 웹 서버를 이용하여 블루/그린 배포를 진행할 수도 있다.
  • v1 버전을 서버 내의 10001번 포트를 리스닝한다. v2 버전을 배포하고 10002번 포트를 리스닝하도록 한다. 클라이언트 요청을 10001번 포트가 아니라 10002번 포트로 전달되도록 변경한다.
  • nginx는 reload 명령어를 사용하여 새로운 프로세스를 생성하여 새로운 요청을 받도록 한다. restart 하면 종료하고 다시 실행되기까지의 요청은 실패할 것이다.

 


 

CodeDeploy로 배포하기

이전 글에서 Auto Scaling을 설정했었다. 자동으로 인스턴스가 추가되지만 애플리케이션은 배포하지 않았다.

이 때 최신 애플리케이션이 배포되도록 하려면? 

 

다음과 같이 해볼 수 있다. git으로 최신 코드를 내려받고, AMI를 생성하고, 시작 템플릿을 생성하고, 이 시작템플릿으로 설정한 Auto Scaling 그룹을 만들어 최신 애플리케이션에 배포된 인스턴스들을 만들고, 로드밸런서에 등록한다.

이런 일련의 작업을 일일히 하기엔 힘들다. CodeDeploy는 이 작업들을 자동으로 진행해준다.

 

CodeDeploy Agent

배포가 진행될 EC2 인스턴스에 CodeDeploy Agent가 설치되어 있어야 한다.

CodeDeploy Agent는 CodeDeploy와 통신을 하며 배포 요청을 받으면 AppSpec.yml 파일에 기재된 절차대로 배포를 진행한다.

 

AppSpec.yml

 

CodeDeploy AppSpec File reference - AWS CodeDeploy

The tar and compressed tar archive file formats (.tar and .tar.gz) are not supported for Windows Server instances.

docs.aws.amazon.com

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app/my-demo/
    overwrite: yes
permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user
hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 180
      runas: ec2-user
  ValidateService:
    - location: scripts/health.sh
      timeout: 30
      runas: ec2-user

 

참고로, 스크립트 파일은

[stop.sh]

더보기

#!/usr/bin/env bash

CURRENT_PID=$(pgrep -fl demo | grep java | 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

 

[start.sh]

더보기

#!/usr/bin/env bash

 

REPOSITORY=/home/ec2-user/app/my-demo

JAR_NAME=$(ls -tr $REPOSITORY/*jar | tail -n 1)

 

echo ">>> JAR_NAME: $JAR_NAME"

 

chmod +x $JAR_NAME

 

echo ">>> $JAR_NAME 실행"

 

nohup java -jar \

         -Dspring.profiles.active=$MY_DEMO_ACTIVE_PROFILE \

         -Dspring.config.additional-location=/home/ec2-user/app/application-prod-db.properties \

         $JAR_NAME > $REPOSITORY/nohub.out 2>&1 &

+ 여기서 $MY_DEMO_ACTIVE_PROFILE를 사용하였는데, CodeDeploy는 .bashrc에 있는 환경변수를 읽어들이지 못하므로 /etc/.profile.d/codedeploy.sh에 환경 변수를 등록한다.

 

[health.sh]

더보기

#!/usr/bin/env bash

 

for RETRY_COUNT in {1..15}

do

    RESULT=$(curl --silent --output /dev/null --write-out "%{http_code}" http://127.0.0.1:8080/health)

    if [[ "$RESULT" -eq "200" ]]

    then

        echo "App is healthy"

        exit 0

    else

        echo "App is not healthy or unknown: ${RESULT}"

    fi

 

    echo "Retry checking health..."

    sleep 10

done

 

echo "App is not healthy..."

exit 1

 

CodeDeploy 설정하기

AMI 생성을 위한 EC2 인스턴스 설정

CodeDeploy Agent를 설치한다.

wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto

 

애플리케이션이 배포될 경로에 저장되어 있는 파일들 제거 (파일이 있으면 CodeDeploy가 에러로 인식)

 

AMI, 시작템플릿 생성

위 EC2 인스턴스로 AMI와 시작템플릿을 생성한다.

Auto Scaling 그룹의 시작템플릿을 생성한 시작템플릿으로 지정한다.

 

CodeDeploy 애플리케이션 생성

  1. [애플리케이션] 메뉴 - [애플리리케이션 생성] 버튼
  2. [배포 그룹 생성] 버튼
    하나의 애플리케이션은 여러개의 배포 그룹을 가진다. (테스트 환경/운영 환경 나누기, 배포 방식 나누기)
  3. CodeDeploy를 위한 역할을 추가한다. (기본적으로 AWSCodeDeployRole 정책이 있다 - Auto Scaling, CloudWatch, EC2, ELB 권한을 포함)
  4. [환경 구성] - [Auto Scaling 그룹] 선택
  5. [로드밸런서] - [Target 그룹] 선택

Auto Scaling을 통하여 인스턴스가 자동으로 생성될 때 인스턴스가 inService 되기 전에 Auto Scaling 그룹 생명주기 후크(autoscaling:EC2 INSTANCE LAUNCHING)가 실행된다. 이에 CodeDeploy 배포가 실행되어 해당 배포 그룹에서 맨 마지막으로 배포에 성공한 버전을 이 새로운 인스턴스에 배포를 진행한다.

 

배포 생성

[배포 그룹] - [배포 생성] 버튼

git(매번 빌드를 한다) / s3(빌드된 실행 파일을 가져온다) 선택 가능

 

배포 로그 확인하기

CodeDeploy 배포에 문제가 생기는 경우 확인할 로그

  • CodeDeploy Agent 로그
    /var/log/codedeploy-agent/codedeploy-agent.log
  • 배포 스크립트 로그
    /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log