arko_renual/deploy/web/04-prod-web-deploy.sh
URP2026 7376c99f17
All checks were successful
deploy-dev / deploy (push) Successful in 36s
운영 웹서버(csv.wise.ai.kr) 구축 및 개발→운영 자동 배포 연결
웹 티어(211.37.173.197 / Rocky 8):
- csv.wise.ai.kr nginx vhost + Let's Encrypt SSL
- WAS는 SSH 터널(arko-was-tunnel.service)로 연결 — 개발서버가 NAT 뒤라
  8088이 포워딩되지 않고 Tomcat도 127.0.0.1 바인딩이기 때문이다.
  키는 WAS에서 restrict,permitopen="127.0.0.1:8088" 로 묶어 셸 접근 불가.
- 정적 리소스는 운영 웹이 직접 서빙하고 없으면 @was 폴백 — 전환 중에도 깨지지 않는다.

파이프라인:
  git push -> 개발 WAS 배포 -> 개발 헬스체크 -> 운영 웹 정적 배포 -> 운영 검증
개발 헬스체크를 통과한 뒤에만 운영으로 넘어간다.
접속 방향은 개발->운영(개발서버는 NAT 뒤라 역방향 접속이 불가능하다).
2026-07-29 17:50:32 +09:00

77 lines
3.5 KiB
Bash

#!/usr/bin/env bash
# 개발서버(zio-server)에서 실행 — 운영 웹서버로 정적 리소스를 배포한다.
#
# 설치 위치: /opt/arko-dev/bin/arko-prodweb-deploy.sh
# 호출 주체: Gitea Actions(.gitea/workflows/deploy-dev.yml) 마지막 단계, 또는 수동
#
# 흐름: git push → CI → 개발 WAS 배포 → (헬스체크 통과) → 이 스크립트 → 운영 웹 반영
#
# 방향이 개발 → 운영이다. 운영 웹서버(211.37.173.197)는 NAT 밖 공인망에 있고
# SSH 9271이 열려 있어 개발서버에서 바로 접속할 수 있다.
# 반대로 개발서버는 NAT 뒤라 운영에서 먼저 접속할 수 없다.
#
# 배포 대상은 방금 개발 WAS에 전개된 ROOT의 정적 리소스다.
# WAR를 다시 풀지 않고 실제 서비스 중인 파일을 그대로 복사하므로
# 개발과 운영 웹이 항상 같은 산출물을 바라본다.
set -euo pipefail
PROD_HOST=211.37.173.197
PROD_PORT=9271
PROD_USER=root
KEY=/root/.ssh/id_arko_prodweb
SRC_ROOT=/opt/arko-dev/tomcat/webapps/ROOT
DEST=/var/www/csv.wise.ai.kr/static
SITE=https://csv.wise.ai.kr/
DIRS="images css js fonts new"
log() { echo "[$(date +'%F %T')] $*"; }
die() { echo "[$(date +'%F %T')] ERROR: $*"; exit 1; }
SSH_OPTS="-p $PROD_PORT -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=20 -o BatchMode=yes"
# ------------------------------------------------------------ 1. 사전 확인
[ -f "$KEY" ] || die "배포 키가 없다: $KEY"
[ -d "$SRC_ROOT" ] || die "전개된 ROOT가 없다: $SRC_ROOT (개발 배포가 선행되어야 한다)"
log "운영 웹서버 접속 확인 ($PROD_HOST:$PROD_PORT)"
ssh $SSH_OPTS "$PROD_USER@$PROD_HOST" "test -d $DEST" \
|| die "접속 또는 대상 디렉토리 확인 실패 — 운영 웹에서 05-prodweb-prepare.sh 를 먼저 실행할 것"
# ------------------------------------------------------------ 2. 동기화
# --delete 는 쓰지 않는다. 운영 웹에만 있는 파일(수동 배치분)을 지워버릴 수 있고,
# 정적 리소스는 누적되어도 문제가 없다. 대신 크기·시각이 다른 것만 전송한다.
TOTAL=0
for d in $DIRS; do
if [ ! -d "$SRC_ROOT/$d" ]; then
log "건너뜀(원본 없음): $d"
continue
fi
SIZE=$(du -sh "$SRC_ROOT/$d" | cut -f1)
log "동기화: $d ($SIZE)"
OUT=$(rsync -az --stats --human-readable \
-e "ssh $SSH_OPTS" \
"$SRC_ROOT/$d/" "$PROD_USER@$PROD_HOST:$DEST/$d/" 2>&1) || die "rsync 실패: $d"
N=$(echo "$OUT" | grep -oE "Number of regular files transferred: [0-9,]+" | grep -oE "[0-9,]+$" | tr -d ',')
N=${N:-0}
TOTAL=$((TOTAL + N))
log " 전송 $N"
done
log "총 전송 파일 수: $TOTAL"
# ------------------------------------------------------------ 3. 검증
log "운영 웹 확인"
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$SITE" || echo 000)
log "$SITE → HTTP $CODE"
[ "$CODE" = "200" ] || [ "$CODE" = "302" ] || die "운영 웹이 정상 응답하지 않는다 (HTTP $CODE)"
# 정적 파일이 실제로 운영 웹에서 나오는지 표본 확인.
# X-Cache 헤더가 없으므로 nginx access_log 대신 응답 코드로만 판단한다.
SAMPLE=$(find "$SRC_ROOT/images" -maxdepth 2 -type f \( -name "*.png" -o -name "*.jpg" -o -name "*.gif" \) 2>/dev/null | head -1)
if [ -n "$SAMPLE" ]; then
REL=${SAMPLE#$SRC_ROOT}
SCODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 20 "https://csv.wise.ai.kr$REL" || echo 000)
log "표본 정적 파일 $REL → HTTP $SCODE"
fi
log "운영 웹 배포 완료"