All checks were successful
deploy-dev / deploy (push) Successful in 39s
2026-07-30 나눔고딕 글꼴 배포 중 드러난 문제들이다. 1) build-and-upload.sh: 업로드 검증이 없어 잘린 WAR이 통과했다 pscp가 대용량 전송 중 약 30초 지점에서 조용히 끊기며 exit 0을 반환해, 194MB WAR이 66MB/84MB로 잘린 채 "업로드 완료"로 처리됐다. 그 WAR로 배포가 돌아 실패했다. 30MB 조각 전송 + 조각별 크기 확인(3회 재시도) + 서버 결합 후 size/md5 대조를 통과할 때만 arko.war 로 교체하도록 바꿨다. 2) build-and-upload.sh: mvn -ntp 는 Maven 3.6.1+ 전용 PATH에 3.5.4가 잡히면 "Unrecognized option: -ntp"로 빌드가 즉시 죽는다. 진행률 억제 옵션일 뿐이라 제거했다. 3) arko-dev-deploy.sh: WAR 검증이 파이프+pipefail 조합으로 취약 정상 WAR인데 Actions 실행 중 "WEB-INF/web.xml 없음"으로 오판해 배포가 멈췄다(서버에서 동일 명령 재실행 시 20/20 통과). unzip 목록을 한 번만 읽어 변수에 담고 파이프 없이 검사한다. ※ 서버의 /opt/arko-dev/bin/ 사본은 워크플로가 갱신하지 않으므로 별도 반영 필요. 덧붙여 워크플로 주석의 "빈 커밋으로 재배포" 안내를 정정했다 — paths-ignore 때문에 변경 경로가 없는 커밋은 워크플로가 실행되지 않는다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
153 lines
7.0 KiB
Bash
153 lines
7.0 KiB
Bash
#!/usr/bin/env bash
|
|
# arko_renual — 로컬 빌드 → 개발서버 WAR 업로드 (개발자 PC에서 실행)
|
|
#
|
|
# 표준 흐름:
|
|
# 1) bash deploy/dev/build-and-upload.sh 빌드 + WAR 업로드
|
|
# 2) git push origin master → Gitea Actions가 자동 배포
|
|
#
|
|
# 옵션:
|
|
# --build-only 빌드만 (업로드 안 함)
|
|
# --no-build 업로드만 (기존 target/arko.war 사용)
|
|
# --deploy 업로드 후 서버 배포까지 직접 실행 (push 없이 즉시 반영할 때)
|
|
#
|
|
# 서버(2코어/메모리 여유 1G)에서 Maven을 돌리지 않기 위한 구조다.
|
|
# 빌드는 개발자 PC에서, 서버는 전개만 한다.
|
|
set -euo pipefail
|
|
|
|
# ------------------------------------------------------------------ 설정
|
|
SERVER_IP=101.79.17.164
|
|
SERVER_USER=root
|
|
SERVER_PW='1q2w3e!Q'
|
|
HOSTKEY="SHA256:Zm5aAv5DJ/EnKiObKSadOxA5nKuXgToCGhNiyhVhAjY"
|
|
REMOTE_INCOMING=/opt/arko-dev/incoming
|
|
REMOTE_PARTS=/opt/arko-dev/incoming/parts
|
|
REMOTE_DEPLOY=/opt/arko-dev/bin/arko-dev-deploy.sh
|
|
CHUNK_SIZE=30m # pscp 연결이 30초 부근에서 끊기는 사례가 있어 조각 단위로 올린다
|
|
SITE_URL=https://csv.zioinfo.co.kr/
|
|
|
|
# arko는 maven-compiler-plugin이 source/target 1.7 → JDK 8로만 빌드된다 (17/21 불가)
|
|
JDK8_HOME=${JDK8_HOME:-"C:/Program Files/Java/jdk1.8.0_202"}
|
|
|
|
PROJECT_ROOT=$(cd "$(dirname "$0")/../.." && pwd)
|
|
WAR="$PROJECT_ROOT/target/arko.war"
|
|
|
|
DO_BUILD=1
|
|
DO_UPLOAD=1
|
|
DO_DEPLOY=0 # 기본은 업로드까지만 — 배포는 git push가 Gitea Actions로 트리거한다
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--build-only) DO_UPLOAD=0 ;;
|
|
--no-build) DO_BUILD=0 ;;
|
|
--deploy) DO_DEPLOY=1 ;;
|
|
*) echo "사용법: $0 [--build-only] [--no-build] [--deploy]"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
log() { echo -e "\n[$(date +'%F %T')] === $* ==="; }
|
|
|
|
# PuTTY plink/pscp 사용 (Windows 기본 ssh는 비밀번호 자동입력이 안 된다)
|
|
PLINK() { plink -batch -hostkey "$HOSTKEY" -pw "$SERVER_PW" "$SERVER_USER@$SERVER_IP" "$@"; }
|
|
PSCP() { pscp -batch -hostkey "$HOSTKEY" -pw "$SERVER_PW" "$@"; }
|
|
|
|
# ------------------------------------------------------------------ 1. 빌드
|
|
if [ "$DO_BUILD" = "1" ]; then
|
|
log "1. 로컬 빌드 (JDK 8)"
|
|
[ -x "$JDK8_HOME/bin/javac" ] || { echo "JDK 8을 찾을 수 없다: $JDK8_HOME (JDK8_HOME 환경변수로 지정)"; exit 1; }
|
|
export JAVA_HOME="$JDK8_HOME"
|
|
cd "$PROJECT_ROOT"
|
|
# -ntp(--no-transfer-progress)는 Maven 3.6.1+ 전용이다. PATH에 3.5.4가 잡히면
|
|
# "Unrecognized option: -ntp"로 즉시 죽으므로 쓰지 않는다.
|
|
mvn -B clean package -DskipTests
|
|
|
|
[ -f "$WAR" ] || { echo "WAR 생성 실패: $WAR"; exit 1; }
|
|
|
|
# 바이트코드 버전 확인 — 51(0x33)=Java7. JDK 17/21로 잘못 빌드되면 서버에서 못 뜬다
|
|
CLS=$(find target/classes -name "*.class" | head -1)
|
|
VER=$(od -An -t d1 -j 7 -N 1 "$CLS" | tr -d ' ')
|
|
echo "바이트코드 major=$VER (51이어야 정상)"
|
|
[ "$VER" = "51" ] || { echo "경고: JDK 8이 아닌 컴파일러로 빌드된 것으로 보인다"; exit 1; }
|
|
ls -lh "$WAR"
|
|
fi
|
|
|
|
[ "$DO_UPLOAD" = "1" ] || { log "빌드만 수행하고 종료"; exit 0; }
|
|
[ -f "$WAR" ] || { echo "WAR이 없다: $WAR (--no-build 이면 먼저 빌드할 것)"; exit 1; }
|
|
|
|
# ------------------------------------------------------------- 2. 업로드
|
|
log "2. 서버 업로드 ($(du -h "$WAR" | cut -f1))"
|
|
PLINK "mkdir -p $REMOTE_INCOMING"
|
|
|
|
# 서버 디스크 여유 확인 — WAR 3배(업로드+전개+백업)가 필요하다
|
|
FREE_MB=$(PLINK "df -m $REMOTE_INCOMING | awk 'NR==2 {print \$4}'" | tr -d '\r')
|
|
WAR_MB=$(( $(du -k "$WAR" | cut -f1) / 1024 ))
|
|
echo "서버 여유 ${FREE_MB}MB / WAR ${WAR_MB}MB"
|
|
[ "$FREE_MB" -gt $(( WAR_MB * 3 )) ] || { echo "서버 디스크 부족"; exit 1; }
|
|
|
|
# pscp가 대용량 전송 중 약 30초 지점에서 조용히 끊기면서 exit 0을 반환한 사례가 있다
|
|
# (2026-07-30: 194MB WAR이 66MB/84MB로 잘린 채 "업로드 완료"로 처리되어 배포가 깨졌다).
|
|
# 그래서 ① 조각으로 나눠 올리고 ② 조각마다 크기를 확인하고 ③ 서버에서 합친 뒤
|
|
# ④ size+md5가 로컬과 일치할 때만 arko.war 로 교체한다. 검증 실패 시 기존 WAR은 그대로 둔다.
|
|
LOCAL_SIZE=$(stat -c %s "$WAR")
|
|
LOCAL_MD5=$(md5sum "$WAR" | cut -d' ' -f1)
|
|
echo "로컬 size=$LOCAL_SIZE md5=$LOCAL_MD5"
|
|
|
|
PARTS_DIR="$PROJECT_ROOT/target/warparts"
|
|
rm -rf "$PARTS_DIR"; mkdir -p "$PARTS_DIR"
|
|
split -b "$CHUNK_SIZE" -d -a 2 "$WAR" "$PARTS_DIR/part_"
|
|
PART_CNT=$(ls "$PARTS_DIR" | wc -l)
|
|
echo "분할 ${PART_CNT}개 ($CHUNK_SIZE)"
|
|
|
|
PLINK "rm -rf $REMOTE_PARTS && mkdir -p $REMOTE_PARTS"
|
|
IDX=0
|
|
for P in "$PARTS_DIR"/part_*; do
|
|
IDX=$((IDX+1)); NAME=$(basename "$P"); LSZ=$(stat -c %s "$P"); OK=0
|
|
for TRY in 1 2 3; do
|
|
PSCP "$P" "$SERVER_USER@$SERVER_IP:$REMOTE_PARTS/$NAME" || true
|
|
RSZ=$(PLINK "stat -c %s $REMOTE_PARTS/$NAME 2>/dev/null || echo 0" | tr -d '\r')
|
|
if [ "$RSZ" = "$LSZ" ]; then echo " [$IDX/$PART_CNT] $NAME OK ($LSZ bytes)"; OK=1; break; fi
|
|
echo " [$IDX/$PART_CNT] $NAME 크기 불일치 (remote=$RSZ local=$LSZ) — 재시도 $TRY/3"
|
|
done
|
|
[ "$OK" = "1" ] || { echo "조각 전송 3회 실패: $NAME — 중단"; exit 1; }
|
|
done
|
|
|
|
PLINK "cat $REMOTE_PARTS/part_* > $REMOTE_INCOMING/arko.war.uploading && rm -rf $REMOTE_PARTS"
|
|
R_SIZE=$(PLINK "stat -c %s $REMOTE_INCOMING/arko.war.uploading" | tr -d '\r')
|
|
R_MD5=$(PLINK "md5sum $REMOTE_INCOMING/arko.war.uploading | cut -d' ' -f1" | tr -d '\r')
|
|
echo "서버 size=$R_SIZE md5=$R_MD5"
|
|
[ "$R_SIZE" = "$LOCAL_SIZE" ] || { echo "업로드 크기 불일치 — arko.war 를 교체하지 않고 중단"; exit 1; }
|
|
[ "$R_MD5" = "$LOCAL_MD5" ] || { echo "업로드 md5 불일치 — arko.war 를 교체하지 않고 중단"; exit 1; }
|
|
rm -rf "$PARTS_DIR"
|
|
PLINK "mv -f $REMOTE_INCOMING/arko.war.uploading $REMOTE_INCOMING/arko.war && ls -lh $REMOTE_INCOMING/arko.war"
|
|
|
|
# ------------------------------------------------------------- 3. 배포
|
|
if [ "$DO_DEPLOY" != "1" ]; then
|
|
log "업로드 완료 — 배포는 git push 가 트리거한다"
|
|
cat <<EOF
|
|
|
|
다음 단계:
|
|
git push origin master → Gitea Actions(deploy-dev)가 자동 배포
|
|
진행 상황: https://git.zioinfo.co.kr/somang4819/arko_renual/actions
|
|
|
|
push 없이 즉시 반영하려면: $0 --no-build --deploy
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
log "3. 서버 배포 (--deploy)"
|
|
PLINK "bash $REMOTE_DEPLOY $REMOTE_INCOMING/arko.war"
|
|
|
|
# ------------------------------------------------------------- 4. 확인
|
|
log "4. 접속 확인"
|
|
LOCAL_CODE=$(PLINK "curl -s -o /dev/null -w '%{http_code}' --max-time 15 http://127.0.0.1:8088/" | tr -d '\r')
|
|
echo "Tomcat 직접 → HTTP $LOCAL_CODE"
|
|
EXT_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 20 "$SITE_URL" || echo 000)
|
|
echo "$SITE_URL → HTTP $EXT_CODE"
|
|
|
|
case "$LOCAL_CODE" in
|
|
200|302) echo -e "\n배포 완료" ;;
|
|
*) echo -e "\n배포 실패 — 서버 로그 확인: plink ... 'tail -50 /opt/arko-dev/tomcat/logs/catalina.out'"; exit 1 ;;
|
|
esac
|
|
|
|
if [ "$EXT_CODE" = "000" ]; then
|
|
echo "참고: 외부 도메인 미응답 — csv.zioinfo.co.kr A 레코드 등록/SSL 발급 여부를 확인할 것"
|
|
fi
|