- deploy/systemd: kintex.service(백엔드 8021) + kintex-nanobanana.service(워커, GEMINI env 워커 한정) - deploy/nginx: kintex.zioinfo.kr vhost(/ static, /api·/ws → 8021) - deploy/deploy_kintex.sh: 검증→원자교체→헬스체크→롤백(WISE 패턴) - deploy/setup_kintex_service.py: 멱등 프로비저닝(유닛·venv·nginx) - deploy/deploy_server_kintex_block.py: 서버 webhook 블록 정본 사본 - Jenkinsfile: push→build(vite+bootJar)→deploy→health - .gitattributes: 배포 산출물 LF 강제 포트 8021 배정(8003~8020 기존 GUARDiA 예약). 시크릿은 서버 env only(미커밋). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
3.6 KiB
Bash
78 lines
3.6 KiB
Bash
#!/usr/bin/env bash
|
|
# KINTEX 배포 스크립트 — deploy_server.py(webhook) 또는 Jenkins가 실행.
|
|
# 인자: $1 = 소스 체크아웃 루트(빌드 산출물 위치, 기본 /opt/kintex/src)
|
|
# 동작(fail-safe): 프론트 dist 검증→원자적 교체(/var/www/kintex)→백엔드 jar 교체→서비스 재기동→헬스체크.
|
|
# 깨진 빌드가 라이브를 무너뜨리지 않도록 "검증 후 교체" + 실패 시 롤백(WISE deploy_uiws.sh 패턴).
|
|
set -euo pipefail
|
|
|
|
SRC="${1:-/opt/kintex/src}"
|
|
WEB_ROOT=/var/www/kintex
|
|
APP_JAR=/opt/kintex/app/app.jar
|
|
BACKEND_PORT=8021
|
|
|
|
log(){ echo "[deploy-kintex] $*"; }
|
|
die(){ echo "[deploy-kintex] ERROR: $*" >&2; exit 1; }
|
|
|
|
# ── 1. 프론트: 빌드 완전성 검증(라이브 건드리기 전) → 스테이징 → 원자적 rename ──
|
|
DIST="$SRC/src/frontend/dist"
|
|
if [ -d "$DIST" ]; then
|
|
[ -f "$DIST/index.html" ] || die "dist/index.html 없음 — 불완전 빌드, 배포 중단(라이브 무변경)"
|
|
[ -d "$DIST/assets" ] || die "dist/assets 없음 — 불완전 빌드, 배포 중단"
|
|
mapfile -t REFS < <(grep -oE '/assets/[A-Za-z0-9._-]+\.(js|css)' "$DIST/index.html" | sort -u)
|
|
[ "${#REFS[@]}" -gt 0 ] || die "index.html 참조 assets 없음 — 비정상 빌드, 중단"
|
|
for ref in "${REFS[@]}"; do
|
|
[ -f "${DIST}${ref}" ] || die "참조 자산 누락: ${ref} — 불완전 빌드, 중단"
|
|
done
|
|
log "프론트 빌드 검증 통과(${#REFS[@]} assets)"
|
|
|
|
STAGE="${WEB_ROOT}.new.$$"
|
|
rm -rf "$STAGE"; mkdir -p "$STAGE"
|
|
cp -r "$DIST/." "$STAGE/"
|
|
if [ -d "$WEB_ROOT" ] && [ -n "$(ls -A "$WEB_ROOT" 2>/dev/null)" ]; then
|
|
tar czf "/var/www/kintex.bak_$(date +%Y%m%d_%H%M%S).tgz" -C "$WEB_ROOT" . || log "WARN: 프론트 백업 실패(계속)"
|
|
fi
|
|
OLD="${WEB_ROOT}.old.$$"
|
|
[ -d "$WEB_ROOT" ] && mv "$WEB_ROOT" "$OLD" || true
|
|
mv "$STAGE" "$WEB_ROOT"
|
|
rm -rf "$OLD"
|
|
log "프론트 배포 완료 → $WEB_ROOT"
|
|
else
|
|
log "WARN: $DIST 없음 — 프론트 배포 건너뜀(백엔드만)"
|
|
fi
|
|
|
|
# ── 2. 백엔드 jar: 검증(BOOT-INF 메인 클래스) 후 교체 ──
|
|
JAR=$(ls -1 "$SRC"/src/backend/build/libs/kintex-backend-*.jar 2>/dev/null | grep -v plain | head -1 || true)
|
|
if [ -n "$JAR" ]; then
|
|
unzip -l "$JAR" | grep -q 'BOOT-INF/classes/com/zioinfo/kintex/KintexApplication.class' \
|
|
|| die "유효하지 않은 jar(메인 클래스 없음) — 배포 중단"
|
|
[ -f "$APP_JAR" ] && cp "$APP_JAR" "${APP_JAR}.bak" || true
|
|
cp "$JAR" "$APP_JAR"
|
|
log "백엔드 jar 교체 → $APP_JAR ($(basename "$JAR"))"
|
|
else
|
|
log "WARN: bootJar 없음 — 백엔드 교체 건너뜀"
|
|
fi
|
|
|
|
# ── 3. 워커 의존성 갱신(venv) — requirements 변경 대비(멱등) ──
|
|
if [ -x /opt/kintex/worker/venv/bin/pip ]; then
|
|
/opt/kintex/worker/venv/bin/pip install -q redis Pillow google-genai 2>/dev/null || log "WARN: 워커 의존성 갱신 스킵"
|
|
fi
|
|
|
|
# ── 4. 서비스 재기동 ──
|
|
systemctl restart kintex.service
|
|
systemctl restart kintex-nanobanana.service 2>/dev/null || log "WARN: 워커 재기동 스킵"
|
|
|
|
# ── 5. 헬스체크(백엔드 /health 200 = success:true) — 실패 시 jar 롤백 ──
|
|
ok=0
|
|
for i in $(seq 1 20); do
|
|
sleep 3
|
|
code=$(curl -s -m 5 -o /dev/null -w '%{http_code}' "http://127.0.0.1:${BACKEND_PORT}/health" || true)
|
|
if [ "$code" = "200" ]; then log "헬스체크 OK ($code)"; ok=1; break; fi
|
|
done
|
|
if [ "$ok" != "1" ]; then
|
|
log "헬스체크 실패 — jar 롤백 시도"
|
|
if [ -f "${APP_JAR}.bak" ]; then cp "${APP_JAR}.bak" "$APP_JAR"; systemctl restart kintex.service; fi
|
|
systemctl is-active kintex.service || true
|
|
die "배포 헬스체크 실패(롤백 수행)"
|
|
fi
|
|
log "배포 완료 — 백엔드 8021 UP, 워커 재기동"
|