From 97fa4d839001913b74220de48d878f53fdb2d215 Mon Sep 17 00:00:00 2001 From: jisangs Date: Fri, 10 Jul 2026 18:27:36 +0900 Subject: [PATCH] =?UTF-8?q?Stage=20=EC=84=9C=EB=B2=84=20=EB=B0=B0=ED=8F=AC?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20-=20Jenkins=EC=9D=98=20freestyle=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 46 +++++++++ deploy/{stage => stage-git}/Dockerfile | 0 deploy/{stage => stage-git}/deploy-stage.sh | 0 .../docker-compose.stage.yml | 0 deploy/stage-jenkins/config.sh | 16 ++++ deploy/stage-jenkins/package.sh | 24 +++++ deploy/stage-jenkins/remote_deploy.sh | 95 +++++++++++++++++++ 7 files changed, 181 insertions(+) create mode 100644 Jenkinsfile rename deploy/{stage => stage-git}/Dockerfile (100%) rename deploy/{stage => stage-git}/deploy-stage.sh (100%) rename deploy/{stage => stage-git}/docker-compose.stage.yml (100%) create mode 100644 deploy/stage-jenkins/config.sh create mode 100644 deploy/stage-jenkins/package.sh create mode 100644 deploy/stage-jenkins/remote_deploy.sh diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..8332b83 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,46 @@ +pipeline { + agent { label 'mac-mini' } + + environment { + NAS = "happyhome@jisangs.synology.me" + NAS_PORT = "21022" + NAS_TMP = "/volume1/docker/service/jisangs/chocomae-stage/tmp" + ARCHIVE = "chocomae-build-${BUILD_NUMBER}.tar.gz" + } + + stages { + stage('Package') { + steps { + sh 'chmod +x deploy/stage-jenkins/*.sh && ./deploy/stage-jenkins/package.sh' + } + } + stage('Upload') { + steps { + sh ''' + ssh -p ${NAS_PORT} ${NAS} "mkdir -p ${NAS_TMP}" + scp -O -P ${NAS_PORT} ${ARCHIVE} deploy/stage-jenkins/remote_deploy.sh ${NAS}:${NAS_TMP}/ + ''' + } + } + stage('Deploy') { + steps { + sh ''' + ssh -p ${NAS_PORT} ${NAS} \ + "bash ${NAS_TMP}/remote_deploy.sh ${ARCHIVE}" + ''' + } + } + } + + post { + always { + sh 'rm -fv ${ARCHIVE} || true' + } + success { + echo "✓ chocomae-stage 배포 성공 (build #${BUILD_NUMBER})" + } + failure { + echo "✗ 배포 실패 — Deploy stage였다면 NAS에서 자동 롤백됨. Console Output 확인" + } + } +} \ No newline at end of file diff --git a/deploy/stage/Dockerfile b/deploy/stage-git/Dockerfile similarity index 100% rename from deploy/stage/Dockerfile rename to deploy/stage-git/Dockerfile diff --git a/deploy/stage/deploy-stage.sh b/deploy/stage-git/deploy-stage.sh similarity index 100% rename from deploy/stage/deploy-stage.sh rename to deploy/stage-git/deploy-stage.sh diff --git a/deploy/stage/docker-compose.stage.yml b/deploy/stage-git/docker-compose.stage.yml similarity index 100% rename from deploy/stage/docker-compose.stage.yml rename to deploy/stage-git/docker-compose.stage.yml diff --git a/deploy/stage-jenkins/config.sh b/deploy/stage-jenkins/config.sh new file mode 100644 index 0000000..7141859 --- /dev/null +++ b/deploy/stage-jenkins/config.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# 배포 환경 설정 — 모든 스크립트가 공유 + +NAS_USER="happyhome" +NAS_HOST="jisangs.synology.me" +NAS_SSH_PORT="21022" + +NAS_BASE="/volume1/docker/service/jisangs/chocomae-stage" +NAS_TMP_DIR="${NAS_BASE}/tmp" +NAS_BACKUP_DIR="${NAS_BASE}/backup" +STAGE_HTML_DIR="${NAS_BASE}/html" +STAGE_DEPLOY_DIR="${STAGE_HTML_DIR}/mouse_typing" +STAGE_CONTAINER_NAME="chocomae-stage-http" # 실제 컨테이너명 확인 + +# BUILD_NUMBER는 Jenkins가 주입 — 로컬 수동 실행 시엔 manual-시각 사용 +ARCHIVE_NAME="chocomae-build-${BUILD_NUMBER:-manual-$(date +%Y%m%d%H%M%S)}.tar.gz" \ No newline at end of file diff --git a/deploy/stage-jenkins/package.sh b/deploy/stage-jenkins/package.sh new file mode 100644 index 0000000..a3d0d77 --- /dev/null +++ b/deploy/stage-jenkins/package.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +source "${SCRIPT_DIR}/config.sh" + +EXCLUDES=( + ".DS_Store" ".git" ".idea" ".claude" ".gitignore" + "__pycache__" "*.pyc" "node_modules" "venv" + "*.zip" "*.tar" "*.tar.gz" "*.pdf" "*.psd" "*.log" + "src/web/server/setup/service_db_setting.php" +) + +TAR_EXCLUDE_ARGS=() +for pattern in "${EXCLUDES[@]}"; do + TAR_EXCLUDE_ARGS+=(--exclude="${pattern}") +done + +echo "=== 압축: ${ARCHIVE_NAME} ===" +tar czf "${ARCHIVE_NAME}" "${TAR_EXCLUDE_ARGS[@]}" \ + index.html \ + src \ + resources + +ls -lh "${ARCHIVE_NAME}" \ No newline at end of file diff --git a/deploy/stage-jenkins/remote_deploy.sh b/deploy/stage-jenkins/remote_deploy.sh new file mode 100644 index 0000000..d64c934 --- /dev/null +++ b/deploy/stage-jenkins/remote_deploy.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# NAS에서 실행되는 배포 본체 +# 사용법: remote_deploy.sh +set -euo pipefail + +ARCHIVE_NAME="$1" + +NAS_BASE="/volume1/docker/service/jisangs/chocomae-stage" +NAS_TMP_DIR="${NAS_BASE}/tmp" +NAS_BACKUP_DIR="${NAS_BASE}/backup" +STAGE_HTML_DIR="${NAS_BASE}/html" +STAGE_DEPLOY_DIR="${STAGE_HTML_DIR}/mouse_typing" +STAGE_CONTAINER_NAME="chocomae-stage-http" + +TIMESTAMP=$(date +%Y%m%d%H%M%S) +NEW_DIR="${STAGE_DEPLOY_DIR}_new" +OLD_DIR="${STAGE_DEPLOY_DIR}_old" + +# ---------- 롤백 함수 ---------- +SWAPPED=0 +rollback() { + echo "!!! 배포 실패 — 롤백 시작 !!!" + if [ "${SWAPPED}" -eq 1 ] && [ -d "${OLD_DIR}" ]; then + # 교체 이후 실패 → 구버전 복원 + rm -rf "${STAGE_DEPLOY_DIR}" + mv "${OLD_DIR}" "${STAGE_DEPLOY_DIR}" + echo "구버전 디렉토리 복원 완료" + fi + rm -rf "${NEW_DIR}" + docker start "${STAGE_CONTAINER_NAME}" 2>/dev/null || true + echo "!!! 롤백 완료 — 빌드는 실패로 처리됨 !!!" + exit 1 +} +trap rollback ERR + +# ---------- 1. 새 버전을 옆에서 완성 (서비스 무영향 구간) ---------- +echo "=== [1/5] 새 버전 준비: ${NEW_DIR} ===" +rm -rf "${NEW_DIR}" +mkdir -p "${NEW_DIR}" +tar xzf "${NAS_TMP_DIR}/${ARCHIVE_NAME}" -C "${NEW_DIR}" + +echo "=== [2/5] stage 설정 적용 ===" +cp -v "${NEW_DIR}/src/game/lib/global/global_variables_debug.js" \ + "${NEW_DIR}/src/game/lib/global/global_variables.js" +cp -v "${NEW_DIR}/src/web/server/setup/NA_service_db_setting.php" \ + "${NEW_DIR}/src/web/server/setup/service_db_setting.php" + +DB_CONFIG="${NEW_DIR}/src/web/server/setup/service_db_setting.php" +sed -i 's/$db_host = "localhost";/$db_host = "mariadb.jisangs.com";/' "${DB_CONFIG}" +sed -i 's/$db_port = 3306;/$db_port = 30001;/' "${DB_CONFIG}" + +echo "--- 치환 결과 검증 ---" +grep -n "db_host\|db_port" "${DB_CONFIG}" +grep -q 'mariadb.jisangs.com' "${DB_CONFIG}" || { echo "db_host 치환 실패"; exit 1; } +grep -q '30001' "${DB_CONFIG}" || { echo "db_port 치환 실패"; exit 1; } + +# ---------- 2. 현재 버전 백업 ---------- +echo "=== [3/5] 현재 버전 백업 ===" +mkdir -p "${NAS_BACKUP_DIR}" +if [ -d "${STAGE_HTML_DIR}" ]; then + tar czf "${NAS_BACKUP_DIR}/chocomae-stage-backup-${TIMESTAMP}.tar.gz" \ + -C "$(dirname "${STAGE_HTML_DIR}")" "$(basename "${STAGE_HTML_DIR}")" +fi +# 7개 초과 백업은 오래된 순으로 정리 +ls -t "${NAS_BACKUP_DIR}"/chocomae-stage-backup-*.tar.gz 2>/dev/null | tail -n +8 | xargs -r rm -fv + +# ---------- 3. 순간 교체 (서비스 중단 최소 구간) ---------- +echo "=== [4/5] 컨테이너 중지 및 교체 ===" +docker stop "${STAGE_CONTAINER_NAME}" + +if [ -d "${STAGE_DEPLOY_DIR}" ]; then + mv "${STAGE_DEPLOY_DIR}" "${OLD_DIR}" +fi +mv "${NEW_DIR}" "${STAGE_DEPLOY_DIR}" +SWAPPED=1 + +# index.html은 html 루트에 위치 +mv -v "${STAGE_DEPLOY_DIR}/index.html" "${STAGE_HTML_DIR}/index.html" + +docker start "${STAGE_CONTAINER_NAME}" + +echo "--- 컨테이너 상태 확인 ---" +sleep 3 +docker ps --filter "name=${STAGE_CONTAINER_NAME}" --format "{{.Names}}: {{.Status}}" | grep -q "Up" \ + || { echo "컨테이너 기동 실패"; exit 1; } +docker ps --filter "name=${STAGE_CONTAINER_NAME}" --format "table {{.Names}}\t{{.Status}}" + +# ---------- 4. 정리 ---------- +echo "=== [5/5] 정리 ===" +trap - ERR # 여기부터는 실패해도 롤백 불필요 +rm -rf "${OLD_DIR}" +rm -fv "${NAS_TMP_DIR}/${ARCHIVE_NAME}" +rm -fv "${NAS_TMP_DIR}/remote_deploy.sh" + +echo "=== 배포 완료 (backup: ${TIMESTAMP}) ===" \ No newline at end of file