diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..2e43ad7 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +set -euo pipefail + +# galaxis-agent 배포 스크립트 +# Usage: ./deploy.sh [--dry-run] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +DRY_RUN=false +if [[ "${1:-}" == "--dry-run" ]]; then + DRY_RUN=true + echo "[DRY-RUN] Docker 명령은 실행하지 않고 출력만 합니다." + echo "" +fi + +HEALTH_URL="${HEALTH_URL:-http://localhost:8100}" +HEALTH_RETRY_INTERVAL=5 +HEALTH_MAX_WAIT=60 + +# 색상 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +info() { echo -e "${GREEN}[INFO]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +error() { echo -e "${RED}[ERROR]${NC} $*"; } + +# ── Pre-flight 체크 ──────────────────────────────────── + +info "Pre-flight 체크 시작..." + +# 1. Docker +if ! command -v docker &>/dev/null; then + error "Docker가 설치되어 있지 않습니다." + echo " 설치: https://docs.docker.com/engine/install/" + exit 1 +fi +info "Docker: $(docker --version)" + +# 2. Docker Compose +if ! docker compose version &>/dev/null; then + error "Docker Compose가 설치되어 있지 않습니다." + echo " 설치: https://docs.docker.com/compose/install/" + exit 1 +fi +info "Docker Compose: $(docker compose version --short)" + +# 3. .env 파일 (docker compose config보다 먼저 확인 — env_file 의존) +if [[ ! -f .env ]]; then + error ".env 파일이 없습니다." + echo " cp .env.example .env 후 값을 설정하세요." + exit 1 +fi +info ".env 파일 OK" + +# 4. 필수 환경변수 검증 (grep 기반 — 셸 환경 오염 방지) +REQUIRED_VARS=( + ANTHROPIC_API_KEY + GITEA_TOKEN + GITEA_WEBHOOK_SECRET + DISCORD_TOKEN + DISCORD_CHANNEL_ID + FERNET_KEY + AGENT_API_KEY +) + +MISSING=() +for var in "${REQUIRED_VARS[@]}"; do + if ! grep -qE "^${var}=.+" .env; then + MISSING+=("$var") + fi +done + +if [[ ${#MISSING[@]} -gt 0 ]]; then + error "필수 환경변수가 설정되지 않았습니다:" + for var in "${MISSING[@]}"; do + echo " - $var" + done + echo " .env 파일을 확인하세요." + exit 1 +fi +info "필수 환경변수 OK (${#REQUIRED_VARS[@]}개 확인)" + +# 5. docker-compose.yml 유효성 +if ! docker compose config --quiet 2>/dev/null; then + error "docker-compose.yml 유효성 검증 실패." + echo " docker compose config 으로 상세 에러를 확인하세요." + exit 1 +fi +info "docker-compose.yml 유효성 OK" + +# 6. galaxis-net 네트워크 +if ! docker network inspect galaxis-net &>/dev/null; then + warn "galaxis-net 네트워크가 없습니다. 생성합니다." + if [[ "$DRY_RUN" == true ]]; then + echo " [DRY-RUN] docker network create galaxis-net" + else + docker network create galaxis-net + fi +fi +info "galaxis-net 네트워크 OK" + +echo "" +info "Pre-flight 체크 완료!" +echo "" + +# ── 배포 ──────────────────────────────────────────────── + +if [[ "$DRY_RUN" == true ]]; then + echo "[DRY-RUN] 실행될 명령:" + echo " docker compose build" + echo " docker compose up -d" + echo " Health check: ${HEALTH_URL}/health (${HEALTH_RETRY_INTERVAL}초 간격, 최대 ${HEALTH_MAX_WAIT}초)" + echo "" + info "Dry-run 완료. 실제 배포는 --dry-run 없이 실행하세요." + exit 0 +fi + +info "galaxis-agent 이미지 빌드 중..." +docker compose build + +info "서비스 시작 중..." +docker compose up -d + +# ── Health check ──────────────────────────────────────── + +info "Health check 시작 (${HEALTH_RETRY_INTERVAL}초 간격, 최대 ${HEALTH_MAX_WAIT}초)..." + +ELAPSED=0 +HEALTHY=false + +while [[ $ELAPSED -lt $HEALTH_MAX_WAIT ]]; do + if curl -sf "${HEALTH_URL}/health" | grep -q '"status".*"ok"' 2>/dev/null; then + HEALTHY=true + break + fi + sleep "$HEALTH_RETRY_INTERVAL" + ELAPSED=$((ELAPSED + HEALTH_RETRY_INTERVAL)) + echo " 대기 중... (${ELAPSED}초)" +done + +if [[ "$HEALTHY" != true ]]; then + error "Health check 실패: ${HEALTH_URL}/health 가 ${HEALTH_MAX_WAIT}초 내에 응답하지 않았습니다." + echo "" + echo " 로그 확인: docker compose logs" + echo " 수동 롤백:" + echo " docker compose down" + echo " git checkout <이전_커밋>" + echo " ./deploy.sh" + exit 1 +fi + +# 개별 health check +ENDPOINTS=("/health" "/health/gitea" "/health/discord" "/health/queue" "/health/costs") +ALL_OK=true + +echo "" +for ep in "${ENDPOINTS[@]}"; do + if curl -sf "${HEALTH_URL}${ep}" >/dev/null 2>&1; then + info " ${ep} ... OK" + else + warn " ${ep} ... FAIL" + ALL_OK=false + fi +done + +echo "" +if [[ "$ALL_OK" == true ]]; then + info "배포 성공! 모든 health check 통과." +else + warn "배포 완료. 일부 health check가 실패했습니다." + echo " 로그 확인: docker compose logs" +fi