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>
This commit is contained in:
parent
10cb87ff42
commit
e4973fb777
@ -17,7 +17,10 @@
|
||||
# ※ Gitea 1.22.3 기준으로 작성했다. 이 버전은 workflow_dispatch(수동 실행 버튼)와
|
||||
# inputs 컨텍스트를 지원하지 않는다 — 넣으면 워크플로 자체가 목록에 뜨지 않는다.
|
||||
# 그래서 트리거는 push 하나만 둔다.
|
||||
# 재배포는 커밋 없이도 `git commit --allow-empty` 후 push 하면 되고,
|
||||
# ※ 빈 커밋(`git commit --allow-empty`)으로는 재배포되지 않는다 — 변경 경로가 없어
|
||||
# 아래 paths-ignore 조건에서 걸러지고 워크플로가 아예 실행되지 않는다(2026-07-30 확인).
|
||||
# 재배포가 필요하면 아래 무시 대상이 아닌 파일을 실제로 변경해 push 하거나,
|
||||
# 서버에서 `bash /opt/arko-dev/bin/arko-dev-deploy.sh /opt/arko-dev/incoming/arko.war` 를 직접 실행한다.
|
||||
# 롤백은 서버에서 직접 수행한다(deploy/dev/README.md 참고).
|
||||
name: deploy-dev
|
||||
|
||||
|
||||
@ -38,8 +38,11 @@ mkdir -p "$BACKUP_DIR" "$LOG_DIR"
|
||||
# ---------------------------------------------------------------- 1. WAR 검증
|
||||
[ -n "$WAR_SRC" ] || die "사용법: $0 <arko.war 경로>"
|
||||
[ -f "$WAR_SRC" ] || die "WAR 파일 없음: $WAR_SRC"
|
||||
unzip -l "$WAR_SRC" > /dev/null 2>&1 || die "WAR 파일이 손상됨: $WAR_SRC"
|
||||
unzip -l "$WAR_SRC" | grep -q "WEB-INF/web.xml" || die "WEB-INF/web.xml 없음 — 정상 WAR 아님"
|
||||
# unzip을 두 번 돌리고 grep -q로 파이프하면 set -o pipefail과 맞물려 취약하다
|
||||
# (2026-07-30: 정상 WAR인데 Actions 실행 중 "web.xml 없음"으로 오판해 배포가 멈췄다).
|
||||
# 목록을 한 번만 읽어 변수에 담고 파이프 없이 검사한다.
|
||||
WAR_LIST=$(unzip -l "$WAR_SRC") || die "WAR 파일이 손상됨: $WAR_SRC"
|
||||
grep -q "WEB-INF/web.xml" <<< "$WAR_LIST" || die "WEB-INF/web.xml 없음 — 정상 WAR 아님"
|
||||
WAR_SIZE=$(du -h "$WAR_SRC" | cut -f1)
|
||||
log "배포 시작: $WAR_SRC ($WAR_SIZE)"
|
||||
|
||||
|
||||
@ -20,7 +20,9 @@ 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 불가)
|
||||
@ -53,7 +55,9 @@ if [ "$DO_BUILD" = "1" ]; then
|
||||
[ -x "$JDK8_HOME/bin/javac" ] || { echo "JDK 8을 찾을 수 없다: $JDK8_HOME (JDK8_HOME 환경변수로 지정)"; exit 1; }
|
||||
export JAVA_HOME="$JDK8_HOME"
|
||||
cd "$PROJECT_ROOT"
|
||||
mvn -B -ntp clean package -DskipTests
|
||||
# -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; }
|
||||
|
||||
@ -78,8 +82,40 @@ 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; }
|
||||
|
||||
# 전송 중 중단되어도 반쪽 WAR이 배포되지 않도록 임시 이름으로 올린 뒤 교체
|
||||
PSCP "$WAR" "$SERVER_USER@$SERVER_IP:$REMOTE_INCOMING/arko.war.uploading"
|
||||
# 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. 배포
|
||||
|
||||
Loading…
Reference in New Issue
Block a user