docs: add Phase 5 implementation plan with review fixes

This commit is contained in:
머니페니 2026-03-20 22:26:07 +09:00
parent 9b2b3921c8
commit fc58eca634

View File

@ -0,0 +1,376 @@
# galaxis-agent Phase 5: Oracle VM 배포 자동화 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** galaxis-agent를 Oracle VM에 Docker Compose 기반으로 배포하는 자동화 스크립트를 작성한다.
**Architecture:** `deploy.sh`가 pre-flight 체크(Docker, 네트워크, 환경변수) → 이미지 빌드 → 서비스 시작 → health check retry 검증을 수행한다. `build-sandbox.sh`가 샌드박스 이미지를 별도로 빌드한다. `.env.example`에 Phase 4 변수를 추가한다.
**Tech Stack:** Bash, Docker Compose, curl
**Spec:** `docs/superpowers/specs/2026-03-20-galaxis-agent-phase5-deploy-design.md`
**Working Directory:** `~/workspace/quant/galaxis-agent/`
---
## File Structure
### 신규 생성 파일
```
deploy.sh # 배포 스크립트 (pre-flight, build, up, health check)
build-sandbox.sh # 샌드박스 이미지 빌드 스크립트
```
### 수정할 파일
```
.env.example # Phase 4 환경변수 추가 (LOG_FORMAT, DAILY_COST_LIMIT_USD, PER_TASK_COST_LIMIT_USD)
```
---
**Task 의존성:** 3개 Task 모두 독립적 → 병렬 dispatch 가능 (sonnet 충분)
---
## Task 1: deploy.sh 작성
배포 스크립트. pre-flight 체크 → 이미지 빌드 → 서비스 시작 → health check 검증.
**Files:**
- Create: `deploy.sh`
### Step 1a: deploy.sh 작성
- [ ] **deploy.sh 작성**
```bash
#!/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
```
- [ ] **실행 권한 부여**
```bash
chmod +x deploy.sh
```
- [ ] **dry-run으로 검증**
```bash
# .env가 없는 상태에서 에러 메시지 확인
./deploy.sh --dry-run
```
Expected: `.env` 파일이 없으면 에러 메시지 출력, 있으면 pre-flight 체크 후 dry-run 명령 출력
- [ ] **커밋**
```bash
git add deploy.sh
git commit -m "feat: add deploy.sh for Oracle VM deployment automation"
```
---
## Task 2: build-sandbox.sh 작성
샌드박스 이미지를 빌드하는 독립 스크립트.
**Files:**
- Create: `build-sandbox.sh`
### Step 2a: build-sandbox.sh 작성
- [ ] **build-sandbox.sh 작성**
```bash
#!/usr/bin/env bash
set -euo pipefail
# galaxis-sandbox 이미지 빌드 스크립트
# Usage: ./build-sandbox.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
fi
IMAGE_NAME="galaxis-sandbox:latest"
DOCKERFILE="Dockerfile.sandbox"
# 색상
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; }
# Docker 설치 확인
if ! command -v docker &>/dev/null; then
error "Docker가 설치되어 있지 않습니다."
exit 1
fi
# Dockerfile.sandbox 존재 확인
if [[ ! -f "$DOCKERFILE" ]]; then
error "${DOCKERFILE}이 없습니다."
exit 1
fi
if [[ "$DRY_RUN" == true ]]; then
echo "[DRY-RUN] 실행될 명령:"
echo " docker build -f ${DOCKERFILE} -t ${IMAGE_NAME} ."
exit 0
fi
info "${IMAGE_NAME} 이미지 빌드 중..."
docker build -f "$DOCKERFILE" -t "$IMAGE_NAME" .
# 이미지 크기 출력
SIZE=$(docker image inspect "$IMAGE_NAME" --format='{{.Size}}' | awk '{printf "%.0f", $1/1024/1024}')
info "빌드 완료! 이미지 크기: ${SIZE}MB"
```
- [ ] **실행 권한 부여**
```bash
chmod +x build-sandbox.sh
```
- [ ] **dry-run으로 검증**
```bash
./build-sandbox.sh --dry-run
```
Expected: `[DRY-RUN] 실행될 명령: docker build -f Dockerfile.sandbox -t galaxis-sandbox:latest .`
- [ ] **커밋**
```bash
git add build-sandbox.sh
git commit -m "feat: add build-sandbox.sh for sandbox image building"
```
---
## Task 3: .env.example 업데이트
Phase 4에서 추가된 환경변수를 `.env.example`에 반영한다.
**Files:**
- Modify: `~/workspace/quant/galaxis-agent/.env.example`
### Step 3a: .env.example 수정
- [ ] **.env.example에 Phase 4 변수 추가**
파일 끝(`# Encryption` 섹션 다음)에 추가:
```bash
# Logging
LOG_FORMAT=json
# Cost Guard
DAILY_COST_LIMIT_USD=10.0
PER_TASK_COST_LIMIT_USD=3.0
```
- [ ] **커밋**
```bash
git add .env.example
git commit -m "docs: add Phase 4 environment variables to .env.example"
```
---
## Phase 5 완료 기준
- [ ] `deploy.sh`가 pre-flight 체크 → 이미지 빌드 → 서비스 시작 → health check retry 검증을 수행한다
- [ ] `deploy.sh --dry-run`이 Docker 명령 없이 pre-flight 체크와 명령 출력만 수행한다
- [ ] `build-sandbox.sh`가 샌드박스 이미지를 빌드하고 크기를 출력한다
- [ ] `build-sandbox.sh --dry-run`이 명령 출력만 수행한다
- [ ] `.env.example`에 Phase 4 환경변수(LOG_FORMAT, DAILY_COST_LIMIT_USD, PER_TASK_COST_LIMIT_USD)가 포함되어 있다
- [ ] 모든 기존 테스트 통과 (139개)