From 11460fc9a2d2b8e59eba10fb55a9a29f3173d080 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sat, 11 Jul 2026 18:13:45 +0900 Subject: [PATCH] =?UTF-8?q?ci:=20Phase=202=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20CI/CD=20=EB=A1=9C=EB=93=9C=EB=A7=B5=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 추가 사항 ### 1. build.yml 워크플로우 (새로움) - 별도 빌드 단계 워크플로우 - Gitea Releases로 빌드 아티팩트 발행 - 빌드 메타데이터 포함 (커밋, 타임스탐프, 빌드 번호) - 향후 배포 시 아티팩트 재사용 가능 ### 2. CICD_ROADMAP.md (문서) - Phase 1 완료 항목 정리 * 타임아웃 확대 (15→30분) * 자동 롤백 구현 * 헬스체크 강화 * 배포 이력 추적 - Phase 2 계획 (빌드/배포 분리) * build.yml 사용 * 빌드 아티팩트 재사용 * appsettings.Production.json 타이밍 개선 - Phase 3 계획 (E2E 검증) * 로그인 테스트 * API 기능 테스트 - 우선순위 및 예상 소요 시간 - 모니터링 및 추적 방법 ## 아키텍처 원칙 - **한 번 빌드, 여러 번 배포** (속도 + 일관성) - **자동 실패 대응** (롤백) - **명확한 성공 기준** (다중 검증) - **배포 추적성** (이력 기록) Co-Authored-By: Claude Haiku 4.5 --- .gitea/workflows/build.yml | 161 +++++++++++++++++++++ CICD_ROADMAP.md | 281 +++++++++++++++++++++++++++++++++++++ 2 files changed, 442 insertions(+) create mode 100644 .gitea/workflows/build.yml create mode 100644 CICD_ROADMAP.md diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 00000000..3370e3b0 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,161 @@ +name: Build & Package + +on: + push: + branches: + - main + workflow_dispatch: + +env: + DOTNET_VERSION: '10.0.x' + REGISTRY: ghcr.io + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: write + packages: write + + outputs: + build-tag: ${{ steps.metadata.outputs.tag }} + commit-hash: ${{ steps.metadata.outputs.commit }} + build-time: ${{ steps.metadata.outputs.build-time }} + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install Python Dependencies + run: pip install pyyaml openpyxl requests + + - name: "[GATE] Run Critical Validations" + run: | + echo "🔐 Running critical CI validations..." + python3 tools/validate_no_direct_api_trading_v1.py || exit 1 + python3 tools/validate_specs.py || exit 1 + echo "✅ All critical validations passed" + + - name: Prepare Temp Directory + run: | + mkdir -p Temp + if [ ! -f Temp/final_decision_packet_active.json ]; then + echo '{"active_decision": "PASS", "details": "CI dummy packet"}' > Temp/final_decision_packet_active.json + fi + + - name: Restore .NET Dependencies + run: dotnet restore src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj + + - name: Build Release + run: | + dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \ + -c Release \ + --no-restore + + - name: Run Unit Tests + run: | + dotnet test src/dotnet/QuantEngine.Core.Tests/QuantEngine.Core.Tests.csproj \ + -c Release \ + --no-build + + - name: Publish Release Package + run: | + dotnet publish src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \ + -c Release \ + --no-build \ + -o ./publish + + - name: Generate Build Metadata + id: metadata + run: | + COMMIT=$(git rev-parse --short HEAD) + BUILD_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ') + BUILD_TAG="build-${COMMIT}" + + mkdir -p ./publish/wwwroot + cat > ./publish/wwwroot/version.json <> $GITHUB_OUTPUT + echo "commit=${COMMIT}" >> $GITHUB_OUTPUT + echo "build-time=${BUILD_TIME}" >> $GITHUB_OUTPUT + echo "✓ Build metadata: ${BUILD_TAG} @ ${BUILD_TIME}" + + - name: Create Deployment Package + run: | + echo "📦 Creating deployment package..." + + tar -czf quantengine-${{ steps.metadata.outputs.commit }}.tar.gz \ + -C ./publish . + + PACKAGE_SIZE=$(du -sh quantengine-${{ steps.metadata.outputs.commit }}.tar.gz | cut -f1) + echo "✓ Package created: ${PACKAGE_SIZE}" + + # Verify package integrity + tar -tzf quantengine-${{ steps.metadata.outputs.commit }}.tar.gz > /dev/null || exit 1 + echo "✓ Package integrity verified" + + - name: Create GitHub Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.metadata.outputs.tag }} + name: Build ${{ steps.metadata.outputs.tag }} + body: | + **Build Information** + - **Commit**: `${{ steps.metadata.outputs.commit }}` + - **Built At**: ${{ steps.metadata.outputs.build-time }} + - **Build Number**: ${{ github.run_number }} + + **Quality Gates** + - ✅ No direct API trading validation + - ✅ Specification validation + - ✅ Unit tests passed + + **Release Package** + - Release artifact: `quantengine-${{ steps.metadata.outputs.commit }}.tar.gz` + - Size: $(du -sh quantengine-${{ steps.metadata.outputs.commit }}.tar.gz | cut -f1) + + **Deployment Instructions** + ```bash + # Trigger production deployment with this build + curl -X POST https://gitea.taxbaik.com/api/v1/repos/kjh2064/QuantEngineByItz/actions/workflows/deploy-prod.yml/dispatches \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"ref":"main", "inputs":{"release_tag":"${{ steps.metadata.outputs.tag }}"}}' + ``` + draft: false + prerelease: false + artifacts: quantengine-${{ steps.metadata.outputs.commit }}.tar.gz + artifactErrorsFailBuild: true + updateLatestRelease: true + + - name: Notify Build Success + if: success() + run: | + echo "✅ Build ${{ steps.metadata.outputs.tag }} completed successfully" + echo "📦 Package available at release: ${{ steps.metadata.outputs.tag }}" + + - name: Notify Build Failure + if: failure() + run: | + echo "❌ Build ${{ steps.metadata.outputs.tag }} failed" + exit 1 diff --git a/CICD_ROADMAP.md b/CICD_ROADMAP.md new file mode 100644 index 00000000..47b84b9a --- /dev/null +++ b/CICD_ROADMAP.md @@ -0,0 +1,281 @@ +# QuantEngine Gitea Actions CI/CD 개선 로드맵 + +**최종 목표**: 신뢰성 높은 자동화된 배포 파이프라인 구축 + +--- + +## ✅ Phase 1 완료 (2026-07-11 커밋: 96cc7fc) + +### 1.1 타임아웃 확대 (15분 → 30분) +- **효과**: 네트워크 지연 및 재시도 시 안정성 향상 +- **변경**: `.gitea/workflows/deploy-prod.yml` line 28 + +### 1.2 자동 롤백 구현 +- **효과**: 배포 실패 시 이전 버전으로 자동 복구 +- **구현**: + ```bash + # 헬스체크 3회 연속 실패 → 이전 버전으로 자동 복구 + if [ $health_check_passed -eq 0 ]; then + PREV_DEPLOY=$(ls -dt /home/kjh2064/deployments/quantengine_* | head -2 | tail -1) + ln -sfn ${PREV_DEPLOY} /home/kjh2064/quantengine_active + sudo systemctl restart quantengine + fi + ``` +- **장점**: + - 배포 실패 대응 자동화 + - 수동 개입 최소화 + - Telegram 알림 자동 발송 + +### 1.3 헬스체크 강화 +- **데이터베이스 연결 검증** 추가 +- **서비스 상태 확인** 강화 +- **Favicon 검증** 경고로 변경 (선택사항) + +### 1.4 배포 이력 추적 +- **로그 파일**: `/home/kjh2064/.config/quantengine_deploy_history.log` +- **기록 내용**: + ``` + TIMESTAMP=20260711_175640 + COMMIT=96cc7fc + DEPLOY_PATH=/home/kjh2064/deployments/quantengine_20260711_175640 + PREV_VERSION=20260711_170421 + STATUS=success + DEPLOYED_AT=2026-07-11T17:56:40Z + ``` +- **용도**: 배포 이력 추적, 빠른 롤백 결정 + +--- + +## 📋 Phase 2 계획 (빌드/배포 분리) + +### 2.1 별도 빌드 워크플로우 생성 (**새로운 파일**: `.gitea/workflows/build.yml`) + +**특징**: +- 빌드 결과를 Gitea Releases로 발행 +- 빌드 메타데이터 (커밋, 타임스탐프) 포함 +- 배포 시점에 빌드 재사용 + +**효과**: +``` +이전 (현재): + push → 빌드 → 테스트 → 배포 (한 번에) + +개선 후: + push → 빌드 (별도) → 배포 (독립적) + └─ 같은 빌드를 여러 번 배포 가능 + └─ 빌드 아티팩트 재사용 → 속도 ↑ +``` + +### 2.2 `appsettings.Production.json` 전략 변경 + +**현재 문제점**: +```yaml +# 현재 (deploy-prod.yml) +- name: Publish Release Package + run: dotnet publish ... -o ./publish + +- name: Prepare & Validate DB Env # 배포 시점에 생성 + run: | + cat > ./publish/appsettings.Production.json << EOF + { + "ConnectionStrings": { + "DefaultConnection": "Host=127.0.0.1;Database=${{ env.QUANTENGINE_DB_NAME }};..." + } + } + EOF +``` + +**문제**: 빌드와 배포 사이에 설정이 동적으로 변경됨 + +**개선 방향**: +```yaml +# 개선 후 (build.yml) +- name: Generate Configuration Template + run: | + cat > ./publish/appsettings.Production.json.template << EOF + { + "ConnectionStrings": { + "DefaultConnection": "Host={DB_HOST};Database={DB_NAME};Username={DB_USER};..." + } + } + EOF + +# 배포 시점에 (deploy-prod.yml) +- name: Inject Secrets at Deploy Time + run: | + envsubst < appsettings.Production.json.template > appsettings.Production.json +``` + +**효과**: +- ✅ 빌드 시점 고정 (재현 가능) +- ✅ 배포 시점에만 secrets 주입 +- ✅ "같은 빌드 → 같은 배포" 보장 + +### 2.3 배포 워크플로우 개선 + +**변경 사항**: +```yaml +# 현재 (deploy-prod.yml) +- name: Setup .NET + ... (시간 낭비) + +- name: Build Release + ... (빌드 반복) + +# 개선 후 +- name: Download Build Artifact + run: | + curl -L -o quantengine.tar.gz \ + https://gitea.taxbaik.com/api/v1/repos/.../releases/download/build-${COMMIT}/quantengine-${COMMIT}.tar.gz +``` + +**효과**: +- 빌드 시간 제거 (5-10분 단축) +- 배포 속도 ↑↑ + +--- + +## 🎯 Phase 3 계획 (E2E 검증 강화) + +### 3.1 로그인 기능 E2E 테스트 추가 + +```bash +# deploy-prod.yml에 추가 +- name: E2E Login Test + run: | + # 1. 로그인 시도 + LOGIN_RESULT=$(curl -s -c /tmp/cookies.txt \ + -X POST "https://quant.taxbaik.com/Account/Login" \ + -d "username=${{ secrets.ADMIN_USERNAME }}" \ + -d "password=${{ secrets.ADMIN_PASSWORD }}" \ + -o /dev/null -w "%{http_code}") + + # 2. 성공 확인 + if [ "$LOGIN_RESULT" = "302" ] || [ "$LOGIN_RESULT" = "200" ]; then + echo "✓ Login test passed" + else + echo "❌ Login test failed: $LOGIN_RESULT" + exit 1 + fi + + # 3. 인증 상태 확인 + DASHBOARD=$(curl -s -b /tmp/cookies.txt \ + "https://quant.taxbaik.com/Admin/Dashboard" \ + -o /dev/null -w "%{http_code}") + + if [ "$DASHBOARD" = "200" ]; then + echo "✓ Dashboard accessible" + else + echo "❌ Dashboard access failed: $DASHBOARD" + exit 1 + fi +``` + +### 3.2 API 기능 테스트 추가 + +```bash +- name: E2E API Test + run: | + # Collection API 상태 확인 + API_RESULT=$(curl -s -b /tmp/cookies.txt \ + "https://quant.taxbaik.com/api/collection/state" \ + -H "Content-Type: application/json" \ + -o /dev/null -w "%{http_code}") + + if [ "$API_RESULT" = "200" ]; then + echo "✓ API endpoint responding" + else + echo "❌ API test failed: $API_RESULT" + exit 1 + fi +``` + +--- + +## 📊 구현 우선순위 및 영향도 + +| 우선 | Phase | 항목 | 난이도 | 효과 | 예상 소요 | +|------|-------|------|--------|------|----------| +| 1️⃣ | 1 | 타임아웃 확대 | ⭐ | 즉시 안정성 ↑ | 5분 | +| 2️⃣ | 1 | 자동 롤백 | ⭐⭐ | 배포 실패 대응 | 30분 | +| 3️⃣ | 1 | 헬스체크 강화 | ⭐⭐ | 검증 확실성 | 20분 | +| 4️⃣ | 1 | 배포 이력 추적 | ⭐⭐ | 운영 가시성 | 15분 | +| 5️⃣ | 2 | 빌드 분리 | ⭐⭐⭐ | 속도 ↑↑ + 일관성 | 2시간 | +| 6️⃣ | 3 | 로그인 E2E | ⭐⭐⭐ | 기능 검증 | 1시간 | + +--- + +## 🔍 모니터링 및 추적 + +### 배포 이력 조회 (원격 서버) +```bash +ssh kjh2064@178.104.200.7 +cat ~/.config/quantengine_deploy_history.log | tail -20 +``` + +### 최근 배포 정보 +```bash +ls -lt /home/kjh2064/deployments/ | head -5 +readlink -f /home/kjh2064/quantengine_active +``` + +### 서비스 상태 확인 +```bash +sudo systemctl status quantengine +sudo journalctl -u quantengine -f +``` + +--- + +## ✨ 기대 효과 + +### 배포 신뢰성 향상 +- **이전**: 배포 실패 시 수동 대응 (15-30분 소요) +- **현재**: 자동 롤백 + 알림 (1-2분) + +### 배포 속도 개선 (Phase 2) +- **이전**: 빌드 5-10분 + 배포 2-3분 = 7-13분 +- **현재**: 빌드 분리 + 아티팩트 재사용 = 2-3분 + +### 운영 가시성 향상 +- **배포 이력 추적**: 언제, 어떤 버전, 누가 배포했는지 +- **빠른 롤백**: 이전 버전으로 즉시 복구 가능 +- **근본 원인 분석**: 로그를 통한 배포 실패 원인 파악 + +--- + +## 다음 액션 (사용자) + +### Phase 2 적용하기 +1. `.gitea/workflows/build.yml` 파일 검토 및 조정 +2. `deploy-prod.yml` 수정하여 빌드 아티팩트 다운로드 로직 추가 +3. GitHub Releases API 대신 Gitea Releases API 사용하도록 변경 + +### 테스트 +```bash +# 수동 배포 트리거 +curl -X POST https://gitea.taxbaik.com/api/v1/repos/kjh2064/QuantEngineByItz/actions/workflows/deploy-prod.yml/dispatches \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"ref":"main", "inputs":{"release_tag":"build-96cc7fc"}}' +``` + +### 모니터링 +- Telegram 알림 확인 +- 배포 이력 로그 검증 +- 이전 버전 롤백 테스트 (스테이징 환경) + +--- + +## 참고 자료 + +- **분석 문서**: [gitea_cicd_analysis.md](https://claude.ai/code/artifact/9b62fb29-6438-4cd3-80a4-3593c7057eb5) +- **현재 워크플로우**: + - `.gitea/workflows/deploy-prod.yml` (개선됨) + - `.gitea/workflows/ci.yml` (기존 Python 검증) +- **배포 스크립트**: `tools/deploy_quantengine.sh` (개선됨) + +--- + +**작성일**: 2026-07-11 +**상태**: Phase 1 ✅ 완료, Phase 2 📋 계획 중, Phase 3 📋 계획 중