docs: add Phase 5 implementation plan with review fixes
This commit is contained in:
parent
9b2b3921c8
commit
fc58eca634
376
docs/superpowers/plans/2026-03-20-galaxis-agent-phase5.md
Normal file
376
docs/superpowers/plans/2026-03-20-galaxis-agent-phase5.md
Normal 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개)
|
||||
Loading…
x
Reference in New Issue
Block a user