From 67db5982d901fa414c9ff361730256defdd72234 Mon Sep 17 00:00:00 2001 From: aidev Date: Sat, 23 May 2026 15:28:04 +0900 Subject: [PATCH] =?UTF-8?q?fix=20:=20docker=20=EA=B8=B0=EB=B0=98=20deploy.?= =?UTF-8?q?sh=20=EB=B0=8F=20postcss=20=EA=B0=84=EC=84=AD=20=EB=B0=A9?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/postcss.config.cjs | 4 ++ scripts/deploy.sh | 135 ++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 frontend/postcss.config.cjs create mode 100755 scripts/deploy.sh diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs new file mode 100644 index 0000000..f3729b9 --- /dev/null +++ b/frontend/postcss.config.cjs @@ -0,0 +1,4 @@ +/** 프로젝트 전용 — 상위(~) postcss.config.js(tailwind) 로드 방지 */ +module.exports = { + plugins: {}, +}; diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..f34c9d1 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# ============================================================================== +# GoldenChart 공통 배포 스크립트 v2 — Docker Compose +# 호출: Git post-receive (Track A) | Jenkins (Track B) +# 설치: /Volumes/ADATA/git/deploy.sh +# ============================================================================== +set -euo pipefail + +GIT_DIR="${GIT_DIR:-/Volumes/ADATA/git/goldenChart.git}" +WORK_TREE="${WORK_TREE:-/Users/aidev/apps/goldenChart}" +BRANCH="${BRANCH:-main}" +DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE:-${WORK_TREE}/docker-compose.yml}" +DEPLOY_LOG="${DEPLOY_LOG:-/Volumes/ADATA/logs/deploy/deploy.log}" +LOG_TAG="[goldenChart-deploy]" +SERVICE_NAME="${SERVICE_NAME:-all}" +BACKEND_HEALTH_URL="${BACKEND_HEALTH_URL:-http://localhost:8080/api/indicators/list}" +FRONTEND_URL="${FRONTEND_URL:-http://localhost:80}" + +export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:${PATH:-/usr/bin:/bin}" + +mkdir -p "$(dirname "$DEPLOY_LOG")" +exec >> "$DEPLOY_LOG" 2>&1 + +log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $LOG_TAG $*"; } +info() { log "[INFO] $*"; } +warn() { log "[WARN] $*"; } +err() { log "[ERROR] $*"; exit 1; } + +log "======================================================" +log " GoldenChart 배포 시작 (v2 Docker)" +log " 서비스 : $SERVICE_NAME" +log " 브랜치 : $BRANCH" +log " 작업트리: $WORK_TREE" +log " compose : $DOCKER_COMPOSE_FILE" +log " 실행자 : $(whoami)" +log "======================================================" + +LOCK_FILE="/tmp/goldenchart_deploy.lock" +if [ -f "$LOCK_FILE" ]; then + LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null || echo "") + if [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then + err "다른 배포 진행 중 (PID: $LOCK_PID)" + fi + rm -f "$LOCK_FILE" +fi +echo $$ > "$LOCK_FILE" +trap 'rm -f "$LOCK_FILE"; log "락 파일 해제"' EXIT + +# Phase 1 +info "[Phase 1] Git checkout" +[ ! -d "$WORK_TREE" ] && mkdir -p "$WORK_TREE" +[ ! -d "$GIT_DIR" ] && err "GIT_DIR 없음: $GIT_DIR" +git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" checkout -f "$BRANCH" +info "체크아웃 완료: $(git --git-dir="$GIT_DIR" rev-parse --short HEAD)" + +[ ! -f "$DOCKER_COMPOSE_FILE" ] && err "docker-compose.yml 없음: $DOCKER_COMPOSE_FILE" +cd "$WORK_TREE" + +# Phase 2 — Docker 이미지 빌드 (호스트 npm 사용 안 함 → postcss 홈 디렉터리 간섭 방지) +info "[Phase 2] Docker 이미지 빌드 ($SERVICE_NAME)" + +build_frontend() { + info "docker compose build frontend" + docker compose -f "$DOCKER_COMPOSE_FILE" build frontend +} + +build_backend() { + info "docker compose build backend" + docker compose -f "$DOCKER_COMPOSE_FILE" build backend +} + +case "$SERVICE_NAME" in + frontend) build_frontend ;; + backend) build_backend ;; + all) + build_backend + build_frontend + ;; + docker-only) info "빌드 스킵 (docker-only)" ;; + python|ai-agent) + warn "goldenChart는 PM2 python 배포 미사용 — docker-only 권장" + ;; + *) warn "알 수 없는 SERVICE_NAME=$SERVICE_NAME" ;; +esac + +# Phase 3 +info "[Phase 3] Docker Compose up" + +case "$SERVICE_NAME" in + frontend) + docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps frontend + ;; + backend) + docker compose -f "$DOCKER_COMPOSE_FILE" up -d mysql + docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps backend + ;; + all|docker-only) + docker compose -f "$DOCKER_COMPOSE_FILE" up -d + ;; +esac + +# Phase 4 +info "[Phase 4] 헬스체크" + +check_url() { + local name="$1" url="$2" retries="${3:-12}" interval="${4:-5}" + local i code + for i in $(seq 1 "$retries"); do + code=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo "000") + if [[ "$code" =~ ^2 ]]; then + info "$name OK (HTTP $code)" + return 0 + fi + warn "$name 대기 ($i/$retries) HTTP $code" + sleep "$interval" + done + warn "$name 헬스체크 실패: $url" + return 1 +} + +case "$SERVICE_NAME" in + frontend) check_url "Frontend" "$FRONTEND_URL" || true ;; + backend) check_url "Backend" "$BACKEND_HEALTH_URL" || true ;; + all|docker-only) + check_url "Frontend" "$FRONTEND_URL" || true + check_url "Backend" "$BACKEND_HEALTH_URL" || true + ;; +esac + +log "======================================================" +log " 배포 완료: $(date '+%Y-%m-%d %H:%M:%S')" +log " 커밋: $(git --git-dir="$GIT_DIR" log --oneline -1 2>/dev/null || echo N/A)" +log "======================================================" + +docker compose -f "$DOCKER_COMPOSE_FILE" ps 2>/dev/null || docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"