govon-runtime / scripts /offline-deploy.sh
umyunsang's picture
sync: scripts/ (verify_e2e_tool_calling.py)
769e684 verified
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
IMAGE_FILE="${PROJECT_DIR}/govon-image.tar.gz"
ENV_TEMPLATE="${PROJECT_DIR}/.env.airgap.example"
ENV_FILE="${PROJECT_DIR}/.env"
API_KEY_PLACEHOLDER="CHANGE_ME_TO_SECURE_RANDOM_KEY"
BM25_INDEX_HMAC_KEY_PLACEHOLDER="CHANGE_ME_TO_SECURE_HMAC_KEY"
extract_env_value() {
local key="$1"
local file="$2"
awk -F= -v key="$key" '
$0 ~ "^[[:space:]]*" key "=" {
sub(/^[^=]*=/, "", $0)
print $0
exit
}
' "$file"
}
require_secure_env_value() {
local key="$1"
local placeholder="$2"
local value
value="$(extract_env_value "$key" "$ENV_FILE")"
if [ -z "$value" ] || [ "$value" = "$placeholder" ]; then
echo "[ERROR] ${key} 값이 λΉ„μ–΄ μžˆκ±°λ‚˜ μ˜ˆμ‹œ placeholder κ·ΈλŒ€λ‘œμž…λ‹ˆλ‹€."
echo " ${ENV_FILE}μ—μ„œ ${key}λ₯Ό μ•ˆμ „ν•œ μž„μ˜ λ¬Έμžμ—΄λ‘œ μˆ˜μ •ν•œ λ’€ λ‹€μ‹œ μ‹€ν–‰ν•˜μ„Έμš”."
exit 1
fi
}
echo "=== GovOn μ˜€ν”„λΌμΈ 배포 슀크립트 ==="
# 1. Docker μ„€μΉ˜ 확인
if ! command -v docker &>/dev/null; then
echo "[ERROR] Dockerκ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
echo "μ„€μΉ˜ κ°€μ΄λ“œ: https://docs.docker.com/engine/install/"
exit 1
fi
echo "[OK] Docker: $(docker --version)"
# 2. Docker Compose 확인
if ! docker compose version &>/dev/null; then
echo "[ERROR] Docker Composeκ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
exit 1
fi
echo "[OK] Docker Compose: $(docker compose version --short)"
# 3. NVIDIA Container Toolkit 확인 (경고만)
if docker info 2>/dev/null | grep -q "Runtimes.*nvidia"; then
echo "[OK] NVIDIA Container Toolkit 감지됨"
else
echo "[WARNING] NVIDIA Container Toolkit이 κ°μ§€λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€."
echo "GPU 가속이 ν•„μš”ν•©λ‹ˆλ‹€: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html"
fi
# 4. 이미지 파일 확인 및 λ‘œλ“œ
if [ ! -f "$IMAGE_FILE" ]; then
echo "[ERROR] 이미지 νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: $IMAGE_FILE"
exit 1
fi
echo "Docker 이미지 λ‘œλ“œ 쀑... (μ‹œκ°„μ΄ μ†Œμš”λ  수 μžˆμŠ΅λ‹ˆλ‹€)"
gunzip -c "$IMAGE_FILE" | docker load
echo "[OK] 이미지 λ‘œλ“œ μ™„λ£Œ"
# 5. ν™˜κ²½λ³€μˆ˜ ν…œν”Œλ¦Ώ μ€€λΉ„
if [ ! -f "$ENV_FILE" ] && [ -f "$ENV_TEMPLATE" ]; then
cp "$ENV_TEMPLATE" "$ENV_FILE"
echo "[OK] .env νŒŒμΌμ„ .env.airgap.example κΈ°μ€€μœΌλ‘œ μƒμ„±ν–ˆμŠ΅λ‹ˆλ‹€."
echo " API_KEY, BM25_INDEX_HMAC_KEY, CORS_ORIGINS 등을 μˆ˜μ •ν•œ λ’€ μž¬μ‹€ν–‰ν•˜μ„Έμš”."
fi
if [ -z "${MODEL_PATH:-}" ] && [ ! -f "$ENV_FILE" ]; then
echo "[INFO] MODEL_PATHκ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€."
echo " μ˜€ν”„λΌμΈ ν™˜κ²½μ—μ„œλŠ” μ»¨ν…Œμ΄λ„ˆ λ‚΄λΆ€ 경둜λ₯Ό μ§€μ •ν•˜μ„Έμš”:"
echo " export MODEL_PATH=/app/models/EXAONE-4.0-32B-AWQ"
fi
if [ ! -f "$ENV_FILE" ]; then
echo "[ERROR] ν™˜κ²½λ³€μˆ˜ νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: $ENV_FILE"
exit 1
fi
require_secure_env_value "API_KEY" "$API_KEY_PLACEHOLDER"
require_secure_env_value "BM25_INDEX_HMAC_KEY" "$BM25_INDEX_HMAC_KEY_PLACEHOLDER"
# 6. λ³Όλ₯¨ 디렉토리 생성
echo "λ³Όλ₯¨ 디렉토리 생성 쀑..."
mkdir -p \
"${PROJECT_DIR}/models" \
"${PROJECT_DIR}/data" \
"${PROJECT_DIR}/agents" \
"${PROJECT_DIR}/configs" \
"${PROJECT_DIR}/logs" \
"${PROJECT_DIR}/.cache"
echo "[OK] λ³Όλ₯¨ 디렉토리 μ€€λΉ„ μ™„λ£Œ"
# 7. μ»¨ν…Œμ΄λ„ˆ μ‹€ν–‰
echo "μ»¨ν…Œμ΄λ„ˆ μ‹œμž‘ 쀑..."
docker compose --env-file "${ENV_FILE}" -f "${PROJECT_DIR}/docker-compose.offline.yml" up -d
echo "[OK] μ»¨ν…Œμ΄λ„ˆ μ‹œμž‘λ¨"
# 8. ν—¬μŠ€μ²΄ν¬ λŒ€κΈ°
echo "μ„œλ²„ μ‹œμž‘ λŒ€κΈ° 쀑... (μ΅œλŒ€ 120초)"
for i in $(seq 1 24); do
if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
echo ""
echo "=============================="
echo "[SUCCESS] GovOn μ„œλ²„κ°€ 정상 μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€!"
echo "API μ£Όμ†Œ: http://localhost:8000"
echo "ν—¬μŠ€μ²΄ν¬: http://localhost:8000/health"
echo "=============================="
exit 0
fi
printf "."
sleep 5
done
echo ""
echo "[ERROR] μ„œλ²„ μ‹œμž‘ μ‹€νŒ¨ (120초 νƒ€μž„μ•„μ›ƒ)"
echo "둜그 확인: docker compose --env-file ${ENV_FILE} -f ${PROJECT_DIR}/docker-compose.offline.yml logs"
exit 1