CI CD

무중단 배포 (Github Actions, Code Deploy) - 2

붓 필 2025. 1. 23. 00:36

 

이번엔 CodeDeploy에서 ec2 인스턴스에 자동 배포하는 것을 설정해보려 한다. 

 

1. docker-compose파일 생성

docekr-compose 작성법과 문법 설명은 생략하겠다. 

아래처럼 yaml파일을 작성한다. 경로는 프로젝트 최상위 경로에 있다.

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - '80:80'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - /dev/null:/etc/nginx/conf.d/default.conf # default.conf 무효화
    networks:
      - app-network
    restart: always

  nest-green:
    build: .
    container_name: nest-green
    restart: always
    ports:
      - '3001:3000'
    volumes:
      - ./src:/app/src
    networks:
      - app-network

  nest-blue:
    build: .
    container_name: nest-blue
    restart: always
    ports:
      - '3002:3000'
    volumes:
      - ./src:/app/src
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

 

2. 쉘 스크립트 파일 생성

최상위 프로젝트의 scripts폴더에 exec.sh, docker-script.sh파일을 생성해 준다.

권한 문제 삽질로 파일을 두 개로 나누었고, 로그를 보면서 해볼 길 바란다.

######   =>>>>>>     exec.sh 파일
#!/bin/bash

# Docker 권한 문제 해결을 위해 ssm-user를 docker 그룹에 추가
sudo usermod -aG docker ubuntu
sudo usermod -aG docker ssm-user

echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
ls -l /home/ubuntu/my-nest-app
echo "Switching to project directory..."

cd /home/ubuntu/my-nest-app || exit 1
echo "Running docker script..."

sh /home/ubuntu/my-nest-app/scripts/docker-script.sh
######   =>>>>>>     docker-script.sh 파일
#!/bin/bash

# Nginx와 현재 구동 중인 애플리케이션의 상태 확인
EXIST_GREEN=$(docker ps | grep nest-green)
EXIST_BLUE=$(docker ps | grep nest-blue)
DOCKER_APP_NAME=nest

# Nginx 설정 파일 경로
NGINX_CONF=<nginx 파일 경로>
NGINX_CONF_BACKUP="${NGINX_CONF}.backup"

# 현재 설정 백업
cp $NGINX_CONF $NGINX_CONF_BACKUP

# 이번 배포 타겟 결정
TARGET_PORT=0
CURRENT_CONTAINER=""
NEW_CONTAINER=""

# Green이 없으면 Green을 시작하고 Blue가 없으면 Blue를 시작, Green을 종료
if [ -z "$EXIST_GREEN" ]; then
    echo "> Green container is not running. Starting Green container..."
    TARGET_PORT=3001
    CURRENT_CONTAINER="nest-blue"
    NEW_CONTAINER="nest-green"
    
    # Green 컨테이너 시작
    docker-compose up -d nest-green
elif [ -z "$EXIST_BLUE" ]; then
    echo "> Blue container is not running. Starting Blue container..."
    TARGET_PORT=3002
    CURRENT_CONTAINER="nest-green"
    NEW_CONTAINER="nest-blue"

    # Blue 컨테이너 시작
    docker-compose up -d nest-blue
else
    echo "> Both Green and Blue containers are running. Updating configuration..."
    TARGET_PORT=3001
    CURRENT_CONTAINER="nest-blue"
    NEW_CONTAINER="nest-green"
    
    # Green 컨테이너 다시 시작
    docker-compose up -d nest-green
fi

echo "> Health check of New WAS at 'http://127.0.0.1:${TARGET_PORT}'..."

# 헬스 체크
for RETRY_COUNT in {1..10}
do
    echo "> Retrying health check... (${RETRY_COUNT})"
    RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${TARGET_PORT})
    
    if [ ${RESPONSE_CODE} -eq 200 ]; then
        echo "> New WAS successfully running"
        
        # Nginx upstream 설정 업데이트
        # 현재 실행 중인 컨테이너를 새로운 컨테이너로 변경
        sed -i.bak "s/server ${CURRENT_CONTAINER}:3000/server ${NEW_CONTAINER}:3000/g" $NGINX_CONF
        
        # Nginx 설정 리로드
        docker exec nginx nginx -s reload
        
        echo "> Nginx reloaded with new configuration"
        
        # 이전 컨테이너 종료 (Green 또는 Blue 컨테이너 종료)
        if [ ! -z "$CURRENT_CONTAINER" ]; then
            echo "> Stopping previous container: $CURRENT_CONTAINER"
            docker-compose stop $CURRENT_CONTAINER
            docker-compose rm -f $CURRENT_CONTAINER
        fi
        
        break
    elif [ ${RETRY_COUNT} -eq 10 ]; then
        echo "> Health check failed."
        # 새 컨테이너 종료
        docker-compose stop $NEW_CONTAINER
        docker-compose rm -f $NEW_CONTAINER
        
        # Nginx 설정 복구
        cp $NGINX_CONF_BACKUP $NGINX_CONF
        docker exec nginx nginx -s reload
        
        exit 1
    fi
    sleep 10
done

# Nginx 컨테이너가 여전히 실행 중이라면, 재시작
docker-compose up -d nginx

# 불필요한 도커 리소스 정리
echo "Prune Docker System"
docker system prune -af

# 백업 파일 제거
rm -f $NGINX_CONF_BACKUP

exit 0

CodeDeploy가 s3에서 압축파일을 가져와 서버에 아축파일을 풀고 exec.sh 스크립트를 실행하게 된다. 

자 여기서 push하고 테스트해보면 정상적으로 동작하는게 보인다.