From 62ef19c78f8d783ede5e4425b896ea3a8327d4ed Mon Sep 17 00:00:00 2001 From: URP2026 Date: Wed, 29 Jul 2026 17:03:55 +0900 Subject: [PATCH] =?UTF-8?q?Gitea=201.22=20=ED=98=B8=ED=99=98:=20=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=ED=94=8C=EB=A1=9C=EC=97=90=EC=84=9C=20workflow=5Fdisp?= =?UTF-8?q?atch=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gitea 1.22.3은 workflow_dispatch(수동 실행)와 inputs 컨텍스트를 지원하지 않아 워크플로가 Actions 목록에 표시되지 않았다. 트리거를 push 하나로 단순화한다. 롤백은 서버에서 직접 수행하도록 README에 절차를 남긴다. Tomcat 힙도 768m -> 448m로 낮춘다. 가용 메모리 1G 안팎인 서버에서 Tomcat 재기동 직후 서버 전체가 응답 불능이 된 사례가 두 번 있었다. --- .gitea/workflows/deploy-dev.yml | 47 ++++------------- deploy/dev/README.md | 14 +++++- deploy/dev/arko-dev.service | 11 ++-- deploy/web/01-web-server-setup.sh | 84 +++++++++++++++++++++++++++++++ deploy/web/02-was-expose.sh | 57 +++++++++++++++++++++ deploy/web/csv.wise.ai.kr.conf | 66 ++++++++++++++++++++++++ 6 files changed, 238 insertions(+), 41 deletions(-) create mode 100644 deploy/web/01-web-server-setup.sh create mode 100644 deploy/web/02-was-expose.sh create mode 100644 deploy/web/csv.wise.ai.kr.conf diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index b761d4d..1b42afa 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -2,7 +2,7 @@ # # ┌ 설계 배경 ─────────────────────────────────────────────────────────────┐ # │ 이 서버(zio-server)는 2코어 / 메모리 여유 1G에 40개 이상의 서비스가 │ -# │ 동거한다. 실제로 구축 중 39분간 응답 불능 후 재부팅된 이력이 있다. │ +# │ 동거한다. 구축 중 서버 전체가 응답 불능이 되어 재부팅된 일이 두 번 있다. │ # │ 그래서 Maven 빌드(힙 1G)는 서버에서 돌리지 않는다. │ # └────────────────────────────────────────────────────────────────────────┘ # @@ -10,7 +10,11 @@ # [개발자 PC] git push origin master → 이 워크플로 자동 실행 # [서버] ROOT 재전개 + 환경설정 주입 + 재기동 + 헬스체크(+실패 시 롤백) # -# 수동 실행(workflow_dispatch)으로 재배포·롤백도 가능하다. +# ※ Gitea 1.22.3 기준으로 작성했다. 이 버전은 workflow_dispatch(수동 실행 버튼)와 +# inputs 컨텍스트를 지원하지 않는다 — 넣으면 워크플로 자체가 목록에 뜨지 않는다. +# 그래서 트리거는 push 하나만 둔다. +# 재배포는 커밋 없이도 `git commit --allow-empty` 후 push 하면 되고, +# 롤백은 서버에서 직접 수행한다(deploy/dev/README.md 참고). name: deploy-dev on: @@ -22,16 +26,6 @@ on: - '**.pptx' - 'docs/**' - '_workspace_privacy/**' - workflow_dispatch: - inputs: - action: - description: '수행할 작업' - required: true - default: 'deploy' - type: choice - options: - - deploy - - rollback concurrency: group: arko-dev-deploy @@ -51,13 +45,11 @@ jobs: - name: 사전 점검 run: | set -e - echo "트리거: ${{ gitea.event_name }} / 작업: ${{ inputs.action || 'deploy' }}" df -h "$APP_HOME" | tail -1 free -h | head -2 uptime - name: WAR 확인 - if: ${{ inputs.action != 'rollback' }} run: | set -e if [ ! -f "$INCOMING_WAR" ]; then @@ -68,36 +60,17 @@ jobs: ls -lh "$INCOMING_WAR" WAR_EPOCH=$(stat -c %Y "$INCOMING_WAR") echo "WAR 빌드 시각: $(date -d @$WAR_EPOCH '+%F %T')" - - # WAR이 이번 커밋보다 오래되었으면 옛 산출물을 배포하는 것이다. - # 문서/CI 파일만 바뀐 커밋도 있으므로 실패시키지 않고 경고만 남긴다. - COMMIT_EPOCH=$(git log -1 --format=%ct 2>/dev/null || echo 0) - if [ "$COMMIT_EPOCH" -gt "$WAR_EPOCH" ]; then - AGE_MIN=$(( (COMMIT_EPOCH - WAR_EPOCH) / 60 )) - echo "::warning::업로드된 WAR이 이번 커밋보다 ${AGE_MIN}분 오래됐다. 소스 변경이 포함된 커밋이라면 build-and-upload.sh 로 다시 올릴 것." + NOW=$(date +%s) + AGE_MIN=$(( (NOW - WAR_EPOCH) / 60 )) + if [ "$AGE_MIN" -gt 120 ]; then + echo "::warning::업로드된 WAR이 ${AGE_MIN}분 전 것이다. 소스 변경이 포함된 커밋이라면 build-and-upload.sh 로 다시 올릴 것." fi - name: 배포 - if: ${{ inputs.action != 'rollback' }} run: | set -e bash "$APP_HOME/bin/arko-dev-deploy.sh" "$INCOMING_WAR" - - name: 롤백 - if: ${{ inputs.action == 'rollback' }} - run: | - set -e - LATEST=$(ls -1t "$APP_HOME"/backup/ROOT_*.tar.gz 2>/dev/null | head -1 || true) - if [ -z "$LATEST" ]; then - echo "::error::롤백할 백업이 없다" - exit 1 - fi - echo "롤백 대상: $LATEST" - systemctl stop arko-dev - rm -rf "$APP_HOME/tomcat/webapps/ROOT" - tar -xzf "$LATEST" -C "$APP_HOME/tomcat/webapps" - systemctl start arko-dev - - name: 결과 확인 run: | set -e diff --git a/deploy/dev/README.md b/deploy/dev/README.md index c5e9456..4969eaf 100644 --- a/deploy/dev/README.md +++ b/deploy/dev/README.md @@ -89,7 +89,19 @@ git push origin master bash deploy/dev/build-and-upload.sh --deploy ``` -**재배포·롤백:** Gitea 웹 > Actions > deploy-dev > Run workflow > `deploy` 또는 `rollback` +**소스 변경 없이 재배포 (WAR만 다시 올린 경우):** +```bash +git commit --allow-empty -m "재배포" && git push origin master +``` + +**롤백:** Gitea 1.22는 수동 실행(workflow_dispatch) 버튼이 없어 서버에서 직접 수행한다. +```bash +ssh root@101.79.17.164 +systemctl stop arko-dev +rm -rf /opt/arko-dev/tomcat/webapps/ROOT +tar -xzf /opt/arko-dev/backup/ROOT_<타임스탬프>.tar.gz -C /opt/arko-dev/tomcat/webapps +systemctl start arko-dev +``` ## 운영 명령 diff --git a/deploy/dev/arko-dev.service b/deploy/dev/arko-dev.service index 5132666..d73e178 100644 --- a/deploy/dev/arko-dev.service +++ b/deploy/dev/arko-dev.service @@ -2,7 +2,12 @@ # 설치 위치: /etc/systemd/system/arko-dev.service # # 이 서버(zio-server)의 기존 서비스들과 같은 방식(systemd 직접 관리)을 따른다. -# 메모리 여유가 1.3G 수준이라 힙을 768m로 제한한다 — 부족하면 서버 전체가 스왑/OOM으로 흔들린다. +# +# 힙 448m — 처음엔 768m로 잡았다가 낮췄다. 이 서버는 40여 개 서비스가 동거해 +# 평상시 가용 메모리가 1G 안팎이고, 2026-07-29 Tomcat 재기동 직후 서버 전체가 +# 응답 불능이 되어 재부팅된 일이 두 번 있었다. arko는 기동 시 JSP 컴파일로 +# 메모리를 크게 쓰므로 상한을 낮춰 다른 서비스를 밀어내지 않도록 한다. +# 늘리려면 반드시 free -h 로 여유를 먼저 확인할 것. [Unit] Description=arko_renual DEV (Tomcat 9, csv.zioinfo.co.kr, :8088) After=network.target mariadb.service @@ -15,10 +20,10 @@ Environment="JAVA_HOME=/opt/arko-dev/jdk8" Environment="CATALINA_HOME=/opt/arko-dev/tomcat" Environment="CATALINA_BASE=/opt/arko-dev/tomcat" Environment="CATALINA_PID=/opt/arko-dev/tomcat/temp/tomcat.pid" -# -Xmx768m: 서버 가용 메모리 기준 상한. 늘리려면 free -h 먼저 확인할 것 # headless: 이미지 처리(썸네일) 시 X11 없는 환경에서 죽지 않도록 # Asia/Seoul: 로그·배치 시각을 서버 다른 서비스와 맞춘다 -Environment="CATALINA_OPTS=-Xms256m -Xmx768m -XX:MaxMetaspaceSize=256m -Djava.awt.headless=true -Duser.timezone=Asia/Seoul -Dfile.encoding=UTF-8" +# ExitOnOutOfMemoryError: OOM으로 반쯤 죽은 채 살아있느니 죽고 재기동하는 편이 낫다 +Environment="CATALINA_OPTS=-Xms192m -Xmx448m -XX:MaxMetaspaceSize=192m -XX:+ExitOnOutOfMemoryError -Djava.awt.headless=true -Duser.timezone=Asia/Seoul -Dfile.encoding=UTF-8" ExecStart=/opt/arko-dev/tomcat/bin/startup.sh ExecStop=/opt/arko-dev/tomcat/bin/shutdown.sh 30 -force diff --git a/deploy/web/01-web-server-setup.sh b/deploy/web/01-web-server-setup.sh new file mode 100644 index 0000000..55d6e2b --- /dev/null +++ b/deploy/web/01-web-server-setup.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# csv.wise.ai.kr 웹 티어 구축 — 웹서버에서 실행 +# +# 사용법: bash 01-web-server-setup.sh [WAS주소] +# WAS주소 기본값 101.79.17.164:8088 (같은 사설망이면 10.0.1.6:8088 로 주면 된다) +# +# 이 서버는 nginx만 올린다. WAS(Tomcat)와 DB(MariaDB)는 개발서버(101.79.17.164)를 그대로 쓴다. +# 멱등: 다시 실행해도 안전하다. +set -euo pipefail + +WAS_ADDR=${1:-101.79.17.164:8088} +DOMAIN=csv.wise.ai.kr +SRC_DIR=$(cd "$(dirname "$0")" && pwd) + +log() { echo -e "\n[$(date +'%F %T')] === $* ==="; } + +# ----------------------------------------------------------- 1. nginx 설치 +log "1. nginx 확인" +if command -v nginx > /dev/null; then + nginx -v 2>&1 +else + echo "nginx 설치" + apt-get update -qq + apt-get install -y nginx +fi + +# sites-enabled 구조가 없는 배포판(예: RHEL 계열)이면 만들어 준다 +mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled +if ! grep -q "sites-enabled" /etc/nginx/nginx.conf; then + echo "경고: nginx.conf 가 sites-enabled 를 include 하지 않는다. 수동 확인 필요." +fi + +# ------------------------------------------------- 2. WAS 도달 여부 확인 +log "2. WAS 도달 확인 ($WAS_ADDR)" +CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 -H "Host: $DOMAIN" "http://$WAS_ADDR/" || echo 000) +echo "http://$WAS_ADDR/ → HTTP $CODE" +if [ "$CODE" = "000" ]; then + cat < 를 먼저 실행할 것 + (Tomcat 바인딩 확대 + 방화벽에서 이 서버 IP만 8088 허용) + - 같은 사설망이면 WAS주소를 10.0.1.6:8088 로 주고 다시 실행할 것 +EOF + exit 1 +fi + +# --------------------------------------------------------- 3. vhost 배치 +log "3. nginx 가상호스트 등록" +install -m 644 "$SRC_DIR/$DOMAIN.conf" "/etc/nginx/sites-available/$DOMAIN.conf" + +# upstream 주소를 인자 값으로 교체 +sed -i "s|server 101.79.17.164:8088;|server $WAS_ADDR;|" "/etc/nginx/sites-available/$DOMAIN.conf" +grep -n "server .*:8088;" "/etc/nginx/sites-available/$DOMAIN.conf" + +ln -sfn "/etc/nginx/sites-available/$DOMAIN.conf" "/etc/nginx/sites-enabled/$DOMAIN.conf" + +if nginx -t; then + systemctl reload nginx + echo "nginx 반영 완료" +else + rm -f "/etc/nginx/sites-enabled/$DOMAIN.conf" + echo "nginx 설정 오류 → 링크 제거하고 중단" + exit 1 +fi + +# ------------------------------------------------------------- 4. 확인 +log "4. 프록시 확인" +CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 -H "Host: $DOMAIN" http://127.0.0.1/ || echo 000) +echo "nginx 경유 → HTTP $CODE" +curl -s --max-time 30 -H "Host: $DOMAIN" http://127.0.0.1/ | grep -oiE "[^<]*" | head -1 + +# --------------------------------------------------------------- 5. SSL +log "5. SSL" +if [ -d "/etc/letsencrypt/live/$DOMAIN" ]; then + echo "인증서 이미 존재" +else + cat < +# +# 현재 Tomcat은 127.0.0.1:8088 에만 바인딩되어 있어 같은 서버의 nginx만 접근 가능하다. +# 별도 웹서버를 두려면 바인딩을 넓히고, 대신 방화벽으로 그 웹서버 IP만 허용한다. +# (8088을 전체 공개하면 nginx를 우회해 WAS에 직접 접근할 수 있게 되므로 반드시 IP를 한정한다) +set -euo pipefail + +WEB_IP=${1:-} +[ -n "$WEB_IP" ] || { echo "사용법: $0 <웹서버IP>"; exit 1; } +echo "$WEB_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' || { echo "IP 형식이 아니다: $WEB_IP"; exit 1; } + +XML=/opt/arko-dev/tomcat/conf/server.xml +TS=$(date +%Y%m%d_%H%M%S) + +echo "=== 1. server.xml 백업 ===" +cp -f "$XML" "$XML.bak_$TS" +echo "$XML.bak_$TS" + +echo +echo "=== 2. Tomcat 바인딩 확대 (127.0.0.1 → 0.0.0.0) ===" +# address 속성을 제거하면 전체 인터페이스에 바인딩된다. +# 노출 통제는 아래 ufw 규칙이 담당한다. +sed -i 's|port="8088" protocol="HTTP/1.1" address="127.0.0.1"|port="8088" protocol="HTTP/1.1"|' "$XML" +python3 -c "import xml.dom.minidom; xml.dom.minidom.parse('$XML'); print('server.xml XML 검증 OK')" +grep -n 'port="8088"' "$XML" | head -2 + +echo +echo "=== 3. 방화벽: $WEB_IP 만 8088 허용 ===" +ufw allow from "$WEB_IP" to any port 8088 proto tcp comment "arko-dev WAS <- csv.wise.ai.kr 웹서버" +ufw status | grep 8088 + +echo +echo "=== 4. Tomcat 재기동 ===" +systemctl restart arko-dev +for i in $(seq 1 60); do + CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 http://127.0.0.1:8088/ || echo 000) + if [ "$CODE" = "200" ] || [ "$CODE" = "302" ]; then break; fi + sleep 3 +done +echo "로컬 확인 → HTTP $CODE" + +echo +echo "=== 5. 리슨 상태 ===" +ss -lntp | grep 8088 + +cat <