# CI/CD 자동 배포 설정 가이드 **K-ArtSell Aegis v16.0 - Gitea CI/CD 자동 배포** --- ## 📋 개요 Gitea Actions 워크플로우가 자동 배포를 처리합니다. ``` Git Push (main) → Build Stage (backend + frontend) → Deploy Stage (production server) → Verify Stage (health checks) → LIVE ✅ ``` **총 소요: ~8분 (완전 자동)** --- ## 🔐 Step 1: SSH 키 생성 프로덕션 서버에 SSH로 배포하기 위해 SSH 키 쌍을 생성합니다. ### 로컬에서 (개발 머신) ```bash ssh-keygen -t ed25519 -f kartsell-deploy -N "" ``` 결과: - `kartsell-deploy` (private key) - `kartsell-deploy.pub` (public key) ### 프로덕션 서버에 공개 키 등록 ```bash # 프로덕션 서버에 SSH로 접속 ssh user@production-server.com # ~/.ssh 디렉토리 확인 mkdir -p ~/.ssh chmod 700 ~/.ssh # 공개 키 추가 cat >> ~/.ssh/authorized_keys << 'EOF' ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... (kartsell-deploy.pub 내용) EOF chmod 600 ~/.ssh/authorized_keys ``` --- ## 🔑 Step 2: Gitea Secrets 설정 저장소 Settings → Actions Secrets에 다음을 추가합니다: ### 1. `DEPLOY_HOST` **프로덕션 서버 호스트명** ``` production-server.com 또는 192.168.1.100 ``` ### 2. `DEPLOY_USER` **배포 사용자명** ``` deploy 또는 다른 ssh 사용자 ``` ### 3. `DEPLOY_SSH_KEY` **SSH 개인 키 (전체 내용)** ``` -----BEGIN OPENSSH PRIVATE KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC... (kartsell-deploy 파일의 전체 내용) -----END OPENSSH PRIVATE KEY----- ``` ### Gitea에서 설정하기 1. 저장소 페이지 접속 2. Settings → Actions (또는 CI/CD) 3. Secrets 탭 4. Add Secret 클릭 5. 위 3개 값 추가 --- ## 🖥️ Step 3: 프로덕션 서버 준비 ### 디렉토리 생성 ```bash sudo mkdir -p /opt/kartsell sudo mkdir -p /var/www/kartsell/frontend sudo mkdir -p /var/log/nginx sudo chown kartsell:kartsell /opt/kartsell sudo chown www-data:www-data /var/www/kartsell/frontend ``` ### Systemd 서비스 파일 **파일: `/etc/systemd/system/kartsell-api.service`** ```ini [Unit] Description=K-ArtSell API Service After=network.target Wants=network-online.target [Service] Type=simple User=kartsell Group=kartsell WorkingDirectory=/opt/kartsell/ ExecStart=/opt/kartsell/KArtSell.Host Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal # Environment Environment="ASPNETCORE_ENVIRONMENT=Production" Environment="ASPNETCORE_URLS=http://localhost:5002" Environment="KARTSELL_POSTGRES=Host=db.internal;Port=5432;Database=kartsell;Username=kartsell;Password=kartsell" [Install] WantedBy=multi-user.target ``` ### Systemd 활성화 ```bash sudo systemctl daemon-reload sudo systemctl enable kartsell-api.service sudo systemctl status kartsell-api.service ``` ### SSL/TLS 인증서 준비 Let's Encrypt 또는 다른 CA에서 인증서를 발급받습니다: ```bash # Let's Encrypt (Certbot 사용) sudo apt install certbot python3-certbot-nginx sudo certbot certonly --nginx -d kartsell.taxbaik.com # 인증서 위치 확인 ls -la /etc/letsencrypt/live/kartsell.taxbaik.com/ ``` --- ## 🚀 Step 4: 워크플로우 확인 ### 1. 워크플로우 파일 확인 ```bash cat .gitea/workflows/deploy.yml ``` ### 2. main 브랜치에 push ```bash git add . git commit -m "Ready for auto-deployment" git push origin main ``` ### 3. Gitea Actions에서 모니터링 저장소 → Actions 탭에서 진행 상황 확인 ``` Workflow: Auto Deploy to Production ├─ Build (backend + frontend) ✅ ├─ Deploy (SSH to production) ✅ ├─ Verify (health checks) ✅ └─ Monitor (Phase 1 status) ✅ ``` --- ## 📊 워크플로우 상세 ### Build Stage ``` 1. .NET 10 SDK 설정 2. Backend 빌드 (Release mode) 3. Backend 테스트 (217/217) 4. Backend 퍼블리시 → /publish/ 5. Node.js + pnpm 설정 6. Frontend 빌드 (Production) 7. Frontend 테스트 (40/40) 8. Frontend 빌드 → /frontend/dist/ 9. 아티팩트 업로드 ``` **예상 시간: 3-5분** ### Deploy Stage ``` 1. 아티팩트 다운로드 2. SSH 키 설정 3. Backend 파일 복사 → /opt/kartsell/ 4. Frontend 파일 복사 → /var/www/kartsell/frontend/ 5. Nginx 설정 자동 생성 6. Nginx 재로드 7. 서비스 재시작 8. 헬스 체크 (frontend + API) ``` **예상 시간: 2-3분** --- ## ✅ 배포 후 확인 ### 프로덕션 서버에서 ```bash # 서비스 상태 sudo systemctl status kartsell-api.service # 로그 확인 sudo journalctl -u kartsell-api.service -f # Nginx 상태 sudo systemctl status nginx ``` ### 클라이언트에서 ```bash # Frontend curl https://kartsell.taxbaik.com/ # Expected: 200 OK (HTML) # API curl https://kartsell.taxbaik.com/api/health # Expected: 200 OK (JSON) # Full API curl https://kartsell.taxbaik.com/api/internal/v1/model-operations/plan # Expected: 200 OK (data) ``` --- ## 🔄 롤백 절차 만약 배포 후 문제가 발생하면: ### 1. 이전 버전 복원 ```bash # 프로덕션 서버에서 cd /opt/kartsell/ # 백업에서 복원 (또는 이전 릴리스 다운로드) git clone --branch ./previous-release cp -r ./previous-release/* ./ sudo systemctl restart kartsell-api.service ``` ### 2. 데이터베이스 마이그레이션 롤백 ```bash # 필요한 경우만 dotnet run --project src/KArtSell.DbMigrator -- --rollback ``` ### 3. 다시 배포 ```bash git push origin main # 수정된 코드 push # 워크플로우가 자동으로 다시 배포 ``` --- ## 🛡️ 보안 최고 사례 ### ✅ 안전한 관행 - SSH 키는 절대 코드에 저장하지 않음 - Secrets는 마스킹됨 (로그에 표시 안 됨) - 최소 권한 원칙 (deploy 사용자는 필요한 디렉토리만 접근) - 헬스 체크로 나쁜 배포 방지 ### ✅ 구성 관리 - 환경 변수는 systemd 서비스 파일에서 관리 - 민감 정보는 secrets 저장소 사용 - SSL 인증서는 자동 갱신 설정 (Certbot) ### ✅ 모니터링 - 배포 후 헬스 체크 - Nginx 및 API 로그 모니터링 - 서비스 자동 재시작 (systemd Restart=on-failure) --- ## 🔧 문제 해결 ### SSH 접속 실패 ```bash # 1. 공개 키 확인 cat kartsell-deploy.pub # 2. 프로덕션 서버에서 authorized_keys 확인 grep -i "ssh-ed25519" ~/.ssh/authorized_keys # 3. 권한 확인 ls -la ~/.ssh/ # authorized_keys: 600 # .ssh: 700 ``` ### 배포 실패 (NGINX 설정) ```bash # 프로덕션 서버에서 sudo nginx -t sudo systemctl reload nginx # 로그 확인 sudo tail -f /var/log/nginx/error.log ``` ### 서비스 시작 실패 ```bash # 프로덕션 서버에서 sudo systemctl status kartsell-api.service sudo journalctl -u kartsell-api.service -n 50 ``` ### 포트 충돌 ```bash # 포트 5002 확인 sudo netstat -tulpn | grep 5002 # 기존 프로세스 종료 sudo lsof -i :5002 sudo kill -9 ``` --- ## 📅 배포 일정 ### 자동 배포 트리거 - **push to main**: 자동 배포 - **PR merge to main**: 자동 배포 - **Manual trigger**: Actions에서 "Run workflow" 클릭 ### 배포 스케줄 (선택사항) ```yaml # .gitea/workflows/deploy.yml에 추가 schedule: - cron: '0 2 * * *' # 매일 02:00 UTC에 배포 ``` --- ## 🎯 다음 단계 ### 즉시 (지금) 1. ✅ SSH 키 생성 2. ✅ Gitea Secrets 설정 3. ✅ 프로덕션 서버 준비 4. ✅ main에 push (배포 시작) ### 배포 후 1. ✅ Actions 탭에서 진행 상황 모니터링 2. ✅ ~8분 후 서비스 LIVE 3. ✅ 헬스 체크 확인 4. ✅ Phase 1 자동 모니터링 계속 ### 진행 중 - Phase 1: 자동 실행 (50-90일) - Phase 2: 배포 완료 ✅ - Phase 3-4: Phase 1 완료 후 자동 트리거 --- ## 📞 지원 ### Gitea Actions 문서 - https://docs.gitea.com/usage/actions/ ### SSH 키 생성 문서 - https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent ### Systemd 서비스 문서 - https://www.freedesktop.org/software/systemd/man/systemd.service.html --- **CI/CD 자동 배포 설정 완료!** **다음 push에서 자동 배포가 시작됩니다.** 🚀