Github Actions +S3 + CodeDeploy + Docker + Nginx + Slack을 활용한 무중단 자동 배포 환경 구축기(with Blue/Green)

이상훈·2023년 8월 29일
0

Project

목록 보기
2/6
post-thumbnail

전체 아키텍쳐

  이전 아키텍쳐에서는 EC2 인스턴스에 빌드 파일을 수동으로 배포했었다. 따라서 아래와 같은 불편사항이 있었다.

  • 매번 코드를 깃허브에 커밋/푸시 할때마다 개발자가 일일이 배포 작업을 수행 해야함.
  • 배포 작업을 수행하는 동안 서버가 다운됨.

위와 같은 이유로 나는 CICD와 함께 무중단 배포를 프로젝트에서 구현하기로 했다. Prod, Deb 서버를 따로 구축하고 싶었으나 이건 다음 기회에....
아래는 CICD를 구축하면서 했던 주요 기술적 의사결정들이다.

Github Actions VS Jenkins

  • Github Actions : Github Actions은 Github에서 직접 제공해주는 CI/CD 도구다. Github 저장소에서 발생하는 build, test, package, release, deploy 등 다양한 이벤트를 기반으로 직접 원하는 Workflow를 만들 수 있다.

  • Jenkins : Jenkins는 거의 모든 언어의 조합과 소스코드 리포지토리(Repository)에 대한 지속적인 통합(CI)과 지속적인 배포(CD)를 제공한다. Jenkins는 다른 일상적인 개발 작업을 자동화할 뿐 아니라 파이프라인(Pipeline)을 사용해 거의 모든 언어의 조합과 소스코드 리포지토리에 대한 지속적인 통합과 지속적인 전달 환경을 구축하도록 도와준다.

💡 Jenkins를 사용하면 별도의 서버를 띄워야 하며 현재 프로젝트 규모가 작기 때문에 상대적으로 가볍고 구축하기 쉬운 Github Actions면 충분하다고 판단했다.

무중단 배포 방식

  • Rolling : 새로 배포되어야 하는 버전을 하나씩 순차적으로 적용시키면서 배포하는 방식이다. 한 번에 모두 배포되는 게 아니기 때문에 배포가 되는 과정에서 옛날 버전과 새로운 버전이 공존한다. 그렇기 때문에 잘못하면 배포하는 과정 중에 호환성 문제가 생길 수 있다.

  • Blue/Green : Blue 혹은 Green 버전 둘 중 하나로 배포되어 있는 상태에서 새로운 버전을 동시에 띄우고 로드밸런서를 통해서 스위칭하는 방식이며, 한 번에 두 개의 버전을 동시에 띄우기 때문에 시스템 자원이 두배로 든다는 단점이 있다.

  • Canary : 카나리 배포는 위험을 빠르게 감지할 수 있는 배포전략으로 지정한 서버 또는 특정 User 에게만 배포해서 서비스를 운영하다가, 버그가 없고 정상적이라고 판단되면 전체에게 배포하는 방식이다.

💡 Blue 1대, Green 1대를 구성하므로 자원 소모가 크지 않다는 점과 레퍼런스가 많아 상대적으로 쉽고 구축이 빠르다는 점에 입각해 Blue/Green 배포 방식을 선택했다.


1. EC2

 가장 먼저 Spring Boot 애플리케이션과 CodeDeploy Agent와 같은 배포를 위한 도구들을 설치할 메인 인스턴스를 하나 만들어준다.

  1. AWS에서 EC2 탭에 들어가서 "인스턴스 시작" 클릭
  2. 인스턴스 설정
    2-1 EC2 이름 설정
    2-2 애플리케이션 및 OS 이미지 "Ubuntu" 설정
    2-3 인스턴스 유형을 프리티어인 t2.micro로 설정
    2-4 인스턴스 접속에 필요한 키 페어를 설정
    • RSA 암호화 방식의 .pem 파일을 사용
  3. EC2 접속 및 연결 확인

    $ ssh -i [pem 키] username@[ip 주소]


2. S3 버킷

  Github Actions를 통해 빌드된 파일을 업로드하기 위한 S3 버킷을 하나 만들어야 한다.

  1. AWS에서 S3 탭에 들어가서 "버킷 생성" 클릭
  2. 버킷 설정
    2-1. 버킷 이름 설정
    2-2. 나머지는 모두 default 값으로 두고 "버킷 만들기" 클릭
    • 퍼블릭 엑세스 차단 설정에서 "모든 퍼블릭 엑세스 차단" 확인
  3. AWS의 IAM 탭에 들어가서 "사용자 생성" 클릭
  4. 사용자 설정
    4-1. 사용자 이름 설정
    4-2. 권한 정책 설정
    • AWSCodeDeployFullAccess, AmazonS3FullAccess를 선택
  5. 사용자의 보안 자격증명 메뉴에서 "액세스 키 만들기" 클릭
  6. 생성된 액세스키와 비밀 액세스키를 보관

3. Code Deploy

3-1. Code Deploy 설정하기

 CodeDeploy는 Source Code를 운영환경에 자동 배포하는 역할을 수행하는 AWS Service로 CD, 즉 지속적인 배포 서비스다. CodeDeploy의 배포 대상에는 EC2, ECS, Lambda 등 여러 가지가 존재하지만, EC2에 배포하는 방법을 알아본다.

  1. AWS에서 IAM 탭에 들어가서 "역할 만들기" 클릭

  2. 역할 설정
    2-1. 일반 사용 사례 "EC2" 선택
    2-2. 역할 이름 설정
    2-3. 권한 정책 설정

    • AmazonEC2RoleforAWSCodeDeploy
  3. 만든 역할을 EC2에서 사용하도록 설정

  4. 역할 변경 후 인스턴스 재부팅

  5. EC2 접속

    $ ssh -i [pem 키] username@[ip 주소]

  6. EC2에 CodeDeploy Agent 설치하기

    $ sudo apt update
    $ sudo apt install ruby-full
    $ sudo apt install wget
    $ cd /home/ubuntu
    $ wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
    $ chmod +x ./install
    $ sudo ./install auto

  7. CodeDeploy Agent 상태 확인

    $ sudo service codedeploy-agent status

  1. CodeDeploy 서비스에서 사용할 IAM 역할 생성
    8-1. 일반 사용 사례 "CodeDeploy" 선택
    8-2. 역할 이름 설정

  2. AWS에서 CodeDeploy탭에 들어가서 "애플리케이션 생성" 클릭

  3. 생성된 애플리케이션을 선택하고 배포 그룹을 생성


3-2. appspec.yml 작성하기

 appspec.yml 파일은 AWS CodeDeploy의 애플리케이션 스펙 파일로 yaml 또는 Json 형식의 파일이다. 이 파일은 배포 프로세스를 정의하고 AWS CodeDeploy가 어떻게 애플리케이션을 배포해야 하는지를 정의한다. deploy.sh는 바로 아래서 설명한다.

version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ubuntu
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: deploy.sh
      timeout: 60
      runas: ubuntu

3-3. deploy.sh 작성하기

 deploy.sh 파일은 배포를 위해 실행되는 파일이다. 간단히 flow를 설명하자면 아래와 같다. 먼저 green 버전이 현재 실행 중이라 가정한다.

  1. green 버전이 현재 실행 중인지 확인
  2. green 버전이 현재 실행 중이라면 blue 버전 up
  3. 30초간 blue, green 버전 동시 실행
  4. 30초 후 blue 버전 확인
    4-1. if blue 버전 실행 O, -> green 버전 종료
    4-2. if blue 버전 실행 X, -> blue 버전에 런타임 에러 발생했으므로 slack 알람 전송

blue 버전을 실행하려 하다가 런타임 에러가 발생해 blue 버전이 내려가고 기존 green 버전이 남아있는 상황이 발생할 수 있다. 따라서 이 경우에는 slack으로 알림을 전송하도록 했다.

deploy.sh

# 작업 디렉토리를 /home/ubuntu으로 변경
cd /home/ubuntu

# 환경변수 DOCKER_APP_NAME을 seniors로 설정
DOCKER_APP_NAME=seniors

# 실행 중인 blue가 있는지 확인
# 프로젝트의 실행 중인 컨테이너를 확인하고, 해당 컨테이너가 실행 중인지를 EXIST_BLUE 변수에 저장
EXIST_BLUE=$(sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)

# 배포 시작한 날짜와 시간을 기록
echo "배포 시작 일자 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log

# green이 실행 중이면 blue up
# EXIST_BLUE 변수가 비어있는지 확인
if [ -z "$EXIST_BLUE" ]; then

  # 로그 파일(/home/ubuntu/deploy.log)에 "blue up - blue 배포 : port:8081"이라는 내용을 추가
  echo "blue 배포 시작 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log

	# docker-compose.blue.yml 파일을 사용하여 seniors-blue 프로젝트의 컨테이너를 빌드하고 실행
	sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d --build

  # 30초 동안 대기
  sleep 30

  # blue가 문제없이 배포되었는지 현재 실행 여부를 확인
  BLUE_HEALTH=$(sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)

  # blue가 현재 실행 중이지 않다면 -> 런타임 에러 또는 다른 이유로 배포가 되지 못한 상태
  if [ -z "$BLUE_HEALTH" ]; then
    # slack으로 알람을 보낼 수 있는 스크립트를 실행
    sudo ./slack_blue.sh
  # blue가 현재 실행되고 있는 경우에만 green을 종료
  else

    # /home/ubuntu/deploy.log: 로그 파일에 "green 중단 시작"이라는 내용을 추가
    echo "green 중단 시작 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log

    # docker-compose.green.yml 파일을 사용하여 seniors-green 프로젝트의 컨테이너를 중지
    sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml down

    # 사용하지 않는 이미지 삭제
    sudo docker image prune -af

    echo "green 중단 완료 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
  fi

# blue가 실행중이면 green up
else
	echo "green 배포 시작 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
	sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d --build

  sleep 30

  GREEN_HEALTH=$(sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml ps | grep Up)

  if [ -z "$GREEN_HEALTH" ]; then

      sudo ./slack_green.sh
  else

      # /home/ubuntu/deploy.log: 로그 파일에 "blue 중단 시작"이라는 내용을 추가
      echo "blue 중단 시작 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log

      # docker-compose.blue.yml 파일을 사용하여 seniors-green 프로젝트의 컨테이너를 중지
      sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml down

      # 사용하지 않는 이미지 삭제
      sudo docker image prune -af

      echo "blue 중단 완료 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
  fi
fi

4. Docker

4-1. Docker, Docker compose 설치하기

EC2에 Docker와 Docker-Compose를 설치한다.

  1. docker 설치

    $ sudo apt update
    $ sudo apt install docker.io

  2. docker 시작

    $ sudo systemctl start docker

  3. docker-compose 설치

    $ sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

  4. docker-compose 권한 부여

    $ sudo chmod +x /usr/local/bin/docker-compose

  5. docker-compose 권한 확인

    $ docker-compose version


4-2. docker-compose.yml 작성하기

 Docker compose는 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 해서, 관리를 간단히 하는 기능이다. 나는 blue, green 무중단 배포를 구성하므로 docker-compose.blue.yml와 docker-compose.green.yml 파일을 따로 작성했다. blue 버전은 8081, green 버전을 8082로 설정했다.

  • docker-compose.blue.yml

    version: '3'
    services:
     backend:
       build: .
       ports:
         - "8081:8080"
       container_name: seniors-blue
  • docker-compose.green.yml

    version: '3'
    services:
     backend:
       build: .
       ports:
         - "8082:8080"
       container_name: seniors-green

4-3. dockerfile 작성하기

 dockerfile은 image를 빌드하기 위한 파일이며 이 image를 기반으로 컨테이너가 실행된다. 아래 코드는 Java 17을 기반으로 하는 애플리케이션을 컨테이너 내에서 실행하기 위한 것으로, 빌드된 애플리케이션 JAR 파일을 Docker 이미지 안에 포함하고 그 JAR 파일을 실행하는 구성을 하고 있다.

FROM openjdk:17
ARG JAR_FILE=seniors-0.0.1-SNAPSHOT.jar
COPY $JAR_FILE app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

5. Github Actions

 이제 github action의 workflow를 작성한다. 프로젝트를 업로드한 Repository의 Actions에 들어가 "java with Gradle"를 선택한다.

나는 develop 브랜치에 push시 build가 되고 main 브랜치에 push시 build & deploy가 되도록 workflow를 분리했다.

build workflow

name: Seniors CICD(build)

on:
  push:
    branches: ["develop"]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v3

      # JDK를 17 버전으로 세팅
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      # Gradle 캐싱-> 빌드 속도 UP
      - name: Gradle caching
        uses: actions/cache@v3
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-    

      # application.yml 파일 생성
      - name: make application.yaml
        run: |
          cd ./src/main/resources
          touch ./application.yml
          echo "${{ secrets.APPLICATION }}" > ./application.yml
        shell: bash

      # Gradle로 빌드 실행
      - name: Build with Gradle
        uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
        with:
          arguments: build

      # 빌드 결과 Slack 알람 전송
      - name: Send Slack Alarms
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_ICON: https://github.com/rtCamp.png?size=48
          SLACK_MESSAGE: 빌드 결과 => ${{ job.status }}
          SLACK_TITLE: 빌드 결과 알람
          SLACK_USERNAME: Notification-Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: always()

deploy workflow

name: Seniors CICD(deploy)

on:
  push:
    branches: [ "main"]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v3
        
      # JDK를 17 버전으로 세팅
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      # Gradle 캐싱-> 빌드 속도 UP
      - name: Gradle caching
        uses: actions/cache@v3
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-    

      # application.yml 파일 생성
      - name: make application.yaml
        run: |
          cd ./src/main/resources
          touch ./application.yml
          echo "${{ secrets.APPLICATION }}" > ./application.yml
        shell: bash

      # Gradle로 빌드 실행
      - name: Build with Gradle
        uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
        with:
          arguments: build  

      # AWS에 연결
      - name: Connect to AWS
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      # 빌드파일을 ZIP 파일로 생성
      - name: Make zip file
        run: |
          mkdir deploy
          cp ./appspec.yml ./deploy/
          cp ./Dockerfile ./deploy/
          cp ./deploy.sh ./deploy/
          cp ./build/libs/*.jar ./deploy/
          zip -r -qq -j ./seniors-build.zip ./deploy

      # S3에 zip 파일 업로드
      - name: Upload to S3
        run: |
          aws s3 cp \
            --region ap-northeast-2 \
            ./seniors-build.zip s3://backend-app-bucket    

      # CodeDeploy에 배포 요청
      - name: Code Deploy Deployment Request
        run: |
          aws deploy create-deployment --application-name seniors \
            --deployment-config-name CodeDeployDefault.OneAtATime \
            --deployment-group-name seniors \
            --s3-location bucket=backend-app-bucket,bundleType=zip,key=seniors-build.zip

      # 배포 결과 Slack 알람 전송
      - name: Slack 알람 발송
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_ICON: https://github.com/rtCamp.png?size=48
          SLACK_MESSAGE: 배포 결과 => ${{ job.status }}
          SLACK_TITLE: 배포 결과 알람
          SLACK_USERNAME: Notification-Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: always()

위 workflow를 작성하면서 사용할 secrets 들을 설정해준다. Github Actions의 Secret에는 외부에 공개되면 안 되는 값들을 저장해서 사용할 수 있다. 대표적으로 AWS의 access key, secret key 등의 정보들을 담는다.


6. Nginx

6-1. Nginx 연결하기

 Reverse proxy 서버를 위해 Nginx를 설치한다. Reverse proxy의 장점으로는 로드밸런싱, 캐싱, SSL 터미네이션 등이 있다. 나는 Nginx에 SSL 인증서를 설치해서 HTTPS를 적용했고 로드밸런싱 기능도 사용했다. 참고로 배포 시점에 30초간 blue, green 버전이 동시에 띄어져 있는데 이때 짧게나마 로드밸런싱이 적용된다.

ec2에 nginx를 설치하고 연결해보자.

  1. ec2 접속

    $ ssh -i [pem 키] username@[ip 주소]

  2. nginx 설치

    $ sudo apt install nginx

  3. nginx 시작

    $ sudo systemctl start nginx

  4. 현재 nginx 상태 확인(초록불 정상)

    $ sudo systemctl status nginx

  1. nginx 설정 파일 수정

    $ sudo vi /etc/nginx/nginx.conf

# nginx.conf

# Nginx 이벤트 모듈 설정.
events {}

# HTTP 요청과 관련된 설정을 하는 부분.
http {

    # upstream 서버 그룹을 정의. 로드 밸런싱을 위해 여러개의 서버를 가리킬 수 있음.
    upstream spring-server {
        least_conn;
        # 로드 밸런싱을 위해 locahost의 8081 포트와 8082 포트에 동작하는 서버를 지정.
        server localhost:8081 max_fails=3 fail_timeout=10s;
        server localhost:8082 max_fails=3 fail_timeout=10s;
    }

    # 실제 HTTP 서버를 설정하는 부분.
    server {
        # listen 지시문은 서버가 80포트에서 들어오는 요청을 수신하도록 설정.
        listen 80;
        server_name [my domain name]

        include /etc/nginx/default.d/*.conf;

        # 모든 경로에 대한 처리를 정의. 프록시 서버로의 요청을 설정하는 부분.
        location / {
            # proxy_set_header는 프록시 서버로 전달되는 요청 헤더를 설정하는 역할.
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header HOST $http_host;
            proxy_set_header X-Nginx-Proxy true;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            # proxy_pass는 실제 요청을 전달할 upstream 서버 그룹을 지정.
            proxy_pass http://spring-server;

            # proxy_redirect는 프록시 응답의 리다이렉션을 설정하는 부분.
            proxy_redirect off;
        }
    }
}

6-2. Nginx에 SSL 적용

 nginx에 SSL 인증서를 발급해 HTTPS를 적용해보자. CA로는 무료 SSL 인증서 발급 기관인 Let's Encrypt를 사용한다. 또한 간단한 SSL 인증서 발급 및 Nginx 환경 설정을 위해 Certbot을 사용한다.

참고 : Nginx와 Let's Encrypt로 HTTPS 웹 서비스 배포하기 (feat. Certbot)


7. Slack

 현재 프로젝트에서는 팀원들과 slack을 통해서 협업하고 있다. 따라서 배포 과정에서 특정한 이벤트가 발생할 경우 slack으로 알림을 받도록 하였다. slack으로 알림을 받는 이벤트들은 아래와 같다.

Case 1 : develop 브랜치에 pr->push 할 경우 -> build 성공 여부

Case 2 : main 브랜치에 push 할 경우 -> deploy 성공 여부

Case 3 : blue/green 버전 교체 시 런타임 에러로 서버가 내려가는 경우 -> 런타임 에러 발생

slack을 통해 알림을 받으려면 Action-Slack을 활용하면 된다.

  1. Slack API 사이트에 접속한다.

  2. "create new app"을 누르고 본인이 원하는 App Name, development slack workspace를 선택해서 새로운 앱을 만든다.

  3. 만든 앱을 선택한 다음 "Incoming webhooks"를 클릭한다.

  4. Incoming Webhooks를 클릭하여 활성화한다. 그 후 "Add New Webhook to workspace"를 클릭하여 slack에 내가 원하는 채널과 연동시킨다.

  5. allow를 클릭하면 Webhook URL이 발급된다.

  6. 이제 알림 설정하자.
    Case 1, 2 : 위 Github Actions의 workflow에서 slack 알림 관련한 코드를 작성했었다. Github Actions의 Secret에 방금 발급한 webhook URL을 추가하면 된다.

    Case 3 : 위 deploy.sh에서 slack 알림 관련한 코드를 작성했었다. 리눅스에서 문서 편집기로 아래 파일들을 작성하자.

    • slack_blue.sh

      # slack-web-hook URL 세팅
      slack_web_hook="........."
      
      # 배포 중 문제가 발생했다는 내용의 로그를 남겨준다.
      echo "blue 배포 중 문제 발생 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
      echo "관리자 알람 발송 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
      
      # 슬랙으로 보낼 메시지를 변수에 저장해준다.
      json="{ \"text\": \"blue  배포 중 문제가 발생하여 배포가 비정상 중단되었으니 확>인 부탁드립니다 -> 문제 발생 시각: $(date '+%Y-%m-%d %H:%M:%S')\" }"
      
      # 변수에 메시지가 잘 입력되었는지 콘솔 창에 출력해본다.
      echo "json: $json"
      
      # 슬랙으로 메시지를 발송한다.
      curl -X POST -H 'Content-type: application/json' --data "$json" "$slack_web_hook"
      
      # 슬랙 알람 발송 이후 배포 비정상종료 로그를 남겨준다.
      echo "관리자 알람 발송 완료, 배포 비정상종료 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
    • slack_green.sh

      # slack-web-hook URL 셋팅
      slack_web_hook="....."
      
      # 배포 중 문제가 발생했다는 내용의 로그를 남겨준다.
      echo "green 배포 중 문제 발생 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
      echo "관리자 알람 발송 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
      
      # 슬랙으로 보낼 메시지를 변수에 저장해준다.
      json="{ \"text\": \"green  배포 중 문제가 발생하여 배포가 비정상 중단되었으니 확
      인 부탁드립니다 -> 문제 발생 시각: $(date '+%Y-%m-%d %H:%M:%S')\" }"
      
      # 변수에 메시지가 잘 입력 되었는지 콘솔 창에 출력해본다.
      echo "json: $json"
      
      # 슬랙으로 메시지를 발송한다.
      curl -X POST -H 'Content-type: application/json' --data "$json" "$slack_web_hook"
      
      # 슬랙 알람 발송 이후 배포 비정상종료 로그를 남겨준다.
      echo "관리자 알람 발송 완료, 배포 비정상종료 : $(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" >> /home/ubuntu/deploy.log
  7. 결과는 아래와 같다.

    Case 1, 2

    Case 3

    Case 3에서 Seniors가 아닌 로그 봇인 이유는 이전 Seniors 앱 생성하기 전 로그이기 때문이다. 현재는 Case1, 2와 같은 Seniors가 나온다.


참고

무중단 배포 아키텍처의 다양한 배포전략 (Rolling, Blue&Green, Canary 배포에 대해)

Github Actions & Nginx를 이용한 CI/CD 무중단 배포 자동화 구축 - EC2 & S3 설정

profile
Problem Solving과 기술적 의사결정을 중요시합니다.

0개의 댓글