diff --git a/backend/appspec.yml b/backend/appspec.yml index 0026b70..6dcc4ce 100644 --- a/backend/appspec.yml +++ b/backend/appspec.yml @@ -21,11 +21,6 @@ hooks: - location: scripts/download_env.sh timeout: 2000 runas: ubuntu - - AfterInstall: - - location: scripts/after-deploy.sh - timeout: 2000 - runas: root AfterInstall: - location: scripts/blue-green-deploy.sh diff --git a/backend/scripts/after-deploy.sh b/backend/scripts/after-deploy.sh deleted file mode 100644 index 0c75790..0000000 --- a/backend/scripts/after-deploy.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -set -e - -# 기본 설정 -REPOSITORY=/home/ubuntu/deploy -LOG_FILE="$REPOSITORY/deploy.log" - -# 로그 파일로 모든 출력 리디렉션 -exec > >(tee -a "$LOG_FILE") 2>&1 - -echo "> 🔵 Deployment script started at $(date)" - -# 디렉토리 이동 -cd $REPOSITORY/api_back - -echo "> 🔵 Stop & Remove docker services." -docker compose down || echo "Failed to stop docker services." - -echo "> 🟢 Run new docker services." -docker compose up --build -d || echo "Failed to start docker services." - -echo "> 🔵 Deployment script finished at $(date)" \ No newline at end of file diff --git a/backend/scripts/blue-green-deploy.sh b/backend/scripts/blue-green-deploy.sh index 5b6dc4d..046bf8b 100755 --- a/backend/scripts/blue-green-deploy.sh +++ b/backend/scripts/blue-green-deploy.sh @@ -1,214 +1,127 @@ #!/bin/bash - -# Blue/Green 무중단 배포 스크립트 set -e -echo "🚀 Blue/Green 무중단 배포를 시작합니다..." +# 기본 설정 +REPOSITORY=/home/ubuntu/deploy +LOG_FILE="$REPOSITORY/deploy.log" -# 환경변수 설정 -# CodeDeploy 배포 디렉토리 찾기 -DEPLOYMENT_ROOT="/opt/codedeploy-agent/deployment-root" +# 로그 파일로 모든 출력 리디렉션 +exec > >(tee -a "$LOG_FILE") 2>&1 -# 실제 배포된 파일들이 있는 디렉토리 찾기 -echo "DEBUG: deployment-root 내용 확인" -find $DEPLOYMENT_ROOT -type f -name "*.yml" -o -name "*.conf" 2>/dev/null | head -5 +echo "> 🔵 Blue/Green 무중단 배포 시작 at $(date)" -# 가장 최근 배포 디렉토리에서 실제 파일들 찾기 (수정 시간 기준으로 정렬) -PROJECT_DIR=$(find $DEPLOYMENT_ROOT -type f -name "docker-compose.yml" -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -1 | cut -d' ' -f2- | xargs dirname) - -if [ -z "$PROJECT_DIR" ]; then - # 대안: ls로 가장 최근 디렉토리 찾기 - LATEST_APP_DIR=$(ls -td $DEPLOYMENT_ROOT/*/d-*/deployment-archive 2>/dev/null | head -1) - if [ -n "$LATEST_APP_DIR" ] && [ -f "$LATEST_APP_DIR/docker-compose.yml" ]; then - PROJECT_DIR="$LATEST_APP_DIR" - else - echo "❌ docker-compose.yml을 찾을 수 없습니다. 배포 실패." - exit 1 - fi -fi - -NGINX_CONFIG="$PROJECT_DIR/nginx.conf" -BACKUP_CONFIG="$PROJECT_DIR/nginx.conf.backup" -DOCKER_COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml" +# 디렉토리 이동 +cd $REPOSITORY echo "DEBUG: 현재 작업 디렉토리: $(pwd)" -echo "DEBUG: 프로젝트 디렉토리: $PROJECT_DIR" -echo "DEBUG: nginx.conf 경로: $NGINX_CONFIG" - -# 프로젝트 디렉토리로 이동 -cd "$PROJECT_DIR" - -# 디렉토리 권한 확인 및 수정 echo "DEBUG: 현재 사용자: $(whoami)" -echo "DEBUG: 디렉토리 권한 확인" -ls -la "$PROJECT_DIR" || echo "디렉토리 목록 확인 실패" -# 프로젝트 디렉토리 전체 소유자 root로 변경 -sudo chown -R root:root "$PROJECT_DIR" -# 디렉토리는 755, 파일은 644로 권한 설정 -sudo find "$PROJECT_DIR" -type d -exec chmod 755 {} \; -sudo find "$PROJECT_DIR" -type f -exec chmod 644 {} \; +# 앱 이름 설정 +DOCKER_APP_NAME="fastapi" -# 현재 활성 서버 확인 -check_active_server() { - if grep -q "backup" $NGINX_CONFIG; then - if grep "fastapi-blue:8000" $NGINX_CONFIG | grep -q "backup"; then - echo "green" - else - echo "blue" - fi - else - echo "blue" # 기본값 - fi -} +# Blue를 기준으로 현재 떠있는 컨테이너를 체크한다. +EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.yml ps fastapi-blue 2>/dev/null | grep Up || echo "") + +echo "현재 Blue 컨테이너 상태 확인..." +if [ -n "$EXIST_BLUE" ]; then + echo "✅ Blue 컨테이너가 실행 중입니다." +else + echo "❌ Blue 컨테이너가 실행되지 않고 있습니다." +fi # 헬스체크 함수 health_check() { - local port=$1 - local attempts=5 + local color=$1 + local attempts=10 - echo "포트 $port 헬스체크 중..." + echo "📊 $color 환경 헬스체크 중..." for i in $(seq 1 $attempts); do - if curl -f http://localhost:$port/api/health > /dev/null 2>&1; then - echo "✅ 포트 $port 헬스체크 성공!" + # 컨테이너가 실행 중인지 확인 + if ! docker-compose -p ${DOCKER_APP_NAME}-${color} -f docker-compose.yml ps fastapi-${color} | grep -q "Up"; then + echo "⏳ $color 컨테이너 시작 대기 중... ($i/$attempts)" + sleep 3 + continue + fi + + # API 헬스체크 시도 + if docker-compose -p ${DOCKER_APP_NAME}-${color} -f docker-compose.yml exec -T fastapi-${color} curl -f http://localhost:8000/api/health > /dev/null 2>&1; then + echo "✅ $color 환경 헬스체크 성공!" return 0 fi - echo "⏳ 헬스체크 시도 $i/$attempts..." - sleep 2 + echo "⏳ $color 헬스체크 시도 $i/$attempts..." + sleep 3 done - echo "❌ 포트 $port 헬스체크 실패!" + echo "❌ $color 환경 헬스체크 실패!" return 1 } -# Nginx 설정 업데이트 -update_nginx_config() { - local active_server=$1 - - echo "Nginx 설정을 업데이트합니다. 활성 서버: $active_server" - - # 임시 파일 경로를 프로젝트 디렉토리로 설정 (권한 문제 해결) - TEMP_NGINX="$PROJECT_DIR/nginx.conf.temp" - BACKUP_CONFIG="$PROJECT_DIR/nginx.conf.backup" - - # 백업 생성 - cp "$NGINX_CONFIG" "$BACKUP_CONFIG" - - # 임시 파일로 복사 - cp "$NGINX_CONFIG" "$TEMP_NGINX" - - if [ "$active_server" = "blue" ]; then - # blue 활성, green backup - sed -i 's/server fastapi-blue:8000 weight=1 max_fails=3 fail_timeout=30s backup; # Blue 환경/server fastapi-blue:8000 weight=1 max_fails=3 fail_timeout=30s; # Blue 환경/' "$TEMP_NGINX" - sed -i 's/server fastapi-green:8000 weight=1 max_fails=3 fail_timeout=30s; # Green 환경/server fastapi-green:8000 weight=1 max_fails=3 fail_timeout=30s backup; # Green 환경/' "$TEMP_NGINX" - else - # green 활성, blue backup - sed -i 's/server fastapi-blue:8000 weight=1 max_fails=3 fail_timeout=30s; # Blue 환경/server fastapi-blue:8000 weight=1 max_fails=3 fail_timeout=30s backup; # Blue 환경/' "$TEMP_NGINX" - sed -i 's/server fastapi-green:8000 weight=1 max_fails=3 fail_timeout=30s backup; # Green 환경/server fastapi-green:8000 weight=1 max_fails=3 fail_timeout=30s; # Green 환경/' "$TEMP_NGINX" - fi - - # 편집된 파일을 원래 위치로 복사 - cp "$TEMP_NGINX" "$NGINX_CONFIG" - - # 임시 파일 정리 - rm -f "$TEMP_NGINX" -} +# 컨테이너 스위칭 +if [ -z "$EXIST_BLUE" ]; then + echo "� Blue 환경으로 배포합니다..." + + # Blue 환경 시작 + docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.yml up -d fastapi-blue nginx-lb + BEFORE_COMPOSE_COLOR="green" + AFTER_COMPOSE_COLOR="blue" +else + echo "🟢 Green 환경으로 배포합니다..." + + # Green 환경 시작 + docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.yml up -d fastapi-green nginx-lb + BEFORE_COMPOSE_COLOR="blue" + AFTER_COMPOSE_COLOR="green" +fi -# Nginx 리로드 -reload_nginx() { - echo "Nginx 설정을 리로드합니다..." +echo "⏳ 새로운 $AFTER_COMPOSE_COLOR 환경 안정화 대기 중..." +sleep 10 + +# 새로운 컨테이너가 제대로 떴는지 확인 +echo "새로운 $AFTER_COMPOSE_COLOR 환경 상태 확인..." +EXIST_AFTER=$(docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.yml ps fastapi-${AFTER_COMPOSE_COLOR} | grep Up || echo "") + +if [ -n "$EXIST_AFTER" ]; then + echo "✅ $AFTER_COMPOSE_COLOR 환경이 성공적으로 시작되었습니다." - # Nginx 설정 리로드 시도 - if docker-compose -f "$DOCKER_COMPOSE_FILE" exec -T nginx nginx -s reload 2>/dev/null; then - echo "✅ Nginx 리로드 성공!" - return 0 + # 헬스체크 수행 + if health_check $AFTER_COMPOSE_COLOR; then + echo "🔄 이전 $BEFORE_COMPOSE_COLOR 환경을 종료합니다..." + + # 이전 컨테이너 종료 + docker-compose -p ${DOCKER_APP_NAME}-${BEFORE_COMPOSE_COLOR} -f docker-compose.yml down 2>/dev/null || true + echo "✅ $BEFORE_COMPOSE_COLOR 환경이 종료되었습니다." + + echo "" + echo "🎉 Blue/Green 배포 완료!" + echo "📊 배포 결과:" + echo " - 새로운 활성 환경: $AFTER_COMPOSE_COLOR" + echo " - 종료된 환경: $BEFORE_COMPOSE_COLOR" + echo " - 배포 시간: $(date)" + + # 최종 상태 확인 + echo "" + echo "🔍 최종 컨테이너 상태:" + docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.yml ps + else - echo "⚠️ 리로드 실패, Nginx 컨테이너 재시작 시도..." - docker-compose -f "$DOCKER_COMPOSE_FILE" restart nginx - sleep 3 + echo "❌ $AFTER_COMPOSE_COLOR 환경 헬스체크 실패!" + echo "🔄 $AFTER_COMPOSE_COLOR 환경을 롤백합니다..." - if docker-compose -f "$DOCKER_COMPOSE_FILE" ps nginx | grep -q "Up"; then - echo "✅ Nginx 재시작 성공!" - return 0 - else - echo "❌ Nginx 재시작 실패!" - cp "$BACKUP_CONFIG" "$NGINX_CONFIG" - return 1 + # 실패한 환경 정리 + docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.yml down 2>/dev/null || true + + # 이전 환경이 있다면 다시 시작 + if [ "$BEFORE_COMPOSE_COLOR" != "none" ]; then + echo "🔄 이전 $BEFORE_COMPOSE_COLOR 환경을 복구합니다..." + docker-compose -p ${DOCKER_APP_NAME}-${BEFORE_COMPOSE_COLOR} -f docker-compose.yml up -d fi - fi -} - -# 메인 배포 로직 -main() { - # 현재 활성 서버 확인 - ACTIVE_SERVER=$(check_active_server) - echo "현재 활성 서버: $ACTIVE_SERVER" - - # 대기 서버 결정 - if [ "$ACTIVE_SERVER" = "blue" ]; then - STANDBY_SERVER="green" - STANDBY_PORT="8001" - STANDBY_SERVICE="fastapi-green" - else - STANDBY_SERVER="blue" - STANDBY_PORT="8000" - STANDBY_SERVICE="fastapi-blue" - fi - - echo "배포 대상: $STANDBY_SERVER (포트: $STANDBY_PORT)" - - # 1. 대기 서버 재시작 - echo "🔄 $STANDBY_SERVER 서버 재시작 중..." - - # 기존 컨테이너들 정리 (포트 충돌 방지) - echo "🧹 기존 컨테이너 정리 중..." - docker-compose -f "$DOCKER_COMPOSE_FILE" down 2>/dev/null || true - - # 80번 포트를 사용하는 프로세스 확인 및 정리 - echo "🔍 포트 80 사용 프로세스 확인..." - if lsof -ti:80 >/dev/null 2>&1; then - echo "⚠️ 포트 80이 사용 중입니다. 기존 프로세스 종료 시도..." - pkill -f nginx 2>/dev/null || true - sleep 2 - fi - - # 전체 서비스 시작 (네트워크 포함) - echo "🚀 전체 서비스 시작 중..." - docker-compose -f "$DOCKER_COMPOSE_FILE" up -d - - sleep 5 - - echo "⏳ 컨테이너 시작 대기 중..." - sleep 10 - - # 2. 헬스체크 - if ! health_check $STANDBY_PORT; then - echo "❌ 헬스체크 실패. 배포 중단." - exit 1 - fi - - # 3. 트래픽 전환 - echo "🔀 트래픽을 $STANDBY_SERVER로 전환..." - update_nginx_config $STANDBY_SERVER - - if ! reload_nginx; then - echo "❌ Nginx 리로드 실패. 배포 중단." - exit 1 - fi - - # 4. 최종 확인 - sleep 3 - if ! health_check 80; then - echo "❌ 최종 확인 실패. 롤백 중..." - update_nginx_config $ACTIVE_SERVER - reload_nginx + + echo "❌ 배포 실패! 롤백 완료." exit 1 fi - - echo "✅ Blue/Green 배포 완료!" - echo "새로운 활성 서버: $STANDBY_SERVER" -} - -# 스크립트 실행 -main "$@" \ No newline at end of file +else + echo "❌ $AFTER_COMPOSE_COLOR 환경 시작 실패!" + echo "❌ 배포 실패!" + exit 1 +fi diff --git a/backend/scripts/fix-permissions.sh b/backend/scripts/fix-permissions.sh index 89b16ad..87a1f67 100644 --- a/backend/scripts/fix-permissions.sh +++ b/backend/scripts/fix-permissions.sh @@ -14,12 +14,4 @@ if [ -d "$DEPLOY_DIR" ]; then find "$DEPLOY_DIR" -name "*.sh" -exec chmod 755 {} \; fi -# CodeDeploy 임시 디렉토리 권한도 수정 -CODEDEPLOY_ROOT="/opt/codedeploy-agent/deployment-root" -if [ -d "$CODEDEPLOY_ROOT" ]; then - echo "CodeDeploy 디렉토리 권한 수정: $CODEDEPLOY_ROOT" - find "$CODEDEPLOY_ROOT" -name "deployment-archive" -type d -exec chown -R ubuntu:ubuntu {} \; 2>/dev/null || true - find "$CODEDEPLOY_ROOT" -name "deployment-archive" -type d -exec chmod -R 755 {} \; 2>/dev/null || true -fi - echo "✅ 권한 수정 완료"