~/snippets/deploy
Published on

deploy.sh

1031 words6 min read
#!/bin/bash
set -e

# =============================================
# 통합 배포 스크립트
# 사용법: ./deploy.sh [up|down|restart|rebuild|logs|status|test]
# =============================================

SKIP_TEST=false

cd "$(dirname "$0")"

# 색상
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# .env 파일 확인
check_env() {
    if [ ! -f ".env.prod" ]; then
        log_error ".env.prod 파일이 없습니다."
        log_info ".env.prod.example을 참고하여 .env.prod 파일을 생성하세요."
        exit 1
    fi
}

# 서비스 시작 (빌드 없이)
cmd_up() {
    check_env
    log_info "서비스 시작..."
    docker compose --env-file .env.prod up -d
    cmd_status
}

# 테스트 실행
cmd_test() {
    log_info "테스트 실행..."
    if ./gradlew test --no-daemon; then
        log_info "모든 테스트 통과"
        return 0
    else
        log_error "테스트 실패"
        return 1
    fi
}

# 서비스 시작 (재빌드)
cmd_rebuild() {
    check_env
    log_info "Git pull (backend)..."
    git pull origin main || log_warn "backend git pull 실패 (계속 진행)"
    
    log_info "Git pull (frontend)..."
    (cd ../frontend && git pull origin main) || log_warn "frontend git pull 실패 (계속 진행)"
    
    # 테스트 실행 (--skip-test 옵션이 없으면)
    if [ "$SKIP_TEST" = false ]; then
        cmd_test || { log_error "테스트 실패로 배포 중단"; exit 1; }
    else
        log_warn "테스트 건너뛰기 (--skip-test)"
    fi
    
    log_info "이미지 빌드 및 서비스 시작..."
    docker compose --env-file .env.prod up -d --build
    cmd_status
}

# 서비스 중지
cmd_down() {
    log_info "서비스 중지..."
    docker compose --env-file .env.prod down
}

# 서비스 재시작
cmd_restart() {
    log_info "서비스 재시작..."
    docker compose --env-file .env.prod restart
    cmd_status
}

# 로그 확인
cmd_logs() {
    docker compose --env-file .env.prod logs -f
}

# 상태 확인
cmd_status() {
    echo ""
    docker compose --env-file .env.prod ps
    echo ""
    log_info "=== 헬스체크 ==="
    
    # Frontend 체크
    if curl -sf http://localhost:80/ > /dev/null 2>&1; then
        echo -e "Frontend: ${GREEN}Healthy${NC}"
    else
        echo -e "Frontend: ${RED}Unhealthy${NC} (시작 중일 수 있음)"
    fi
    
    # Backend 체크 (Frontend 프록시 경유)
    if curl -sf http://localhost:80/api/actuator/health > /dev/null 2>&1; then
        echo -e "Backend:  ${GREEN}Healthy${NC}"
    else
        echo -e "Backend:  ${RED}Unhealthy${NC} (시작 중일 수 있음)"
    fi
    
    # Redis 체크
    if docker exec myredis redis-cli ping > /dev/null 2>&1; then
        echo -e "Redis:    ${GREEN}Healthy${NC}"
    else
        echo -e "Redis:    ${RED}Unhealthy${NC}"
    fi
    echo ""
}

# 사용법
usage() {
    echo "Usage: $0 [command] [options]"
    echo ""
    echo "Commands:"
    echo "  up        서비스 시작 (기존 이미지 사용)"
    echo "  rebuild   git pull + 테스트 + 이미지 재빌드 + 시작"
    echo "  down      서비스 중지"
    echo "  restart   서비스 재시작"
    echo "  logs      로그 확인 (Ctrl+C로 종료)"
    echo "  status    서비스 상태 확인"
    echo "  test      테스트 실행"
    echo ""
    echo "Options:"
    echo "  --skip-test   rebuild 시 테스트 건너뛰기"
    exit 1
}

# 옵션 파싱
for arg in "$@"; do
    case $arg in
        --skip-test) SKIP_TEST=true ;;
    esac
done

# 메인
case ${1:-help} in
    up)       cmd_up ;;
    rebuild)  cmd_rebuild ;;
    down)     cmd_down ;;
    restart)  cmd_restart ;;
    logs)     cmd_logs ;;
    status)   cmd_status ;;
    test)     cmd_test ;;
    *)        usage ;;
esac