From 582ddf1e706c93dc6093d34f6ae51f06d8fbd66b Mon Sep 17 00:00:00 2001 From: AutonetSellCar Deploy Date: Thu, 1 Jan 2026 21:22:25 +0900 Subject: [PATCH] Update DEPLOYMENT.md with comprehensive deployment guide --- DEPLOYMENT.md | 443 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 291 insertions(+), 152 deletions(-) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 4ae764d..1d82344 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,32 +1,140 @@ # AutonetSellCar.com 배포 가이드 -## 서버 구성 +## 1. 서버 아키텍처 + +### 1.1 서버 구성도 ``` -server5 (집 Win11) - ↓ Remote Desktop -server4 (회사 Win11, 개발서버) - ↓ SSH / Git Push -server1 (192.168.0.201) - NPM (Nginx Proxy Manager) -server2 (192.168.0.202) - 운영서버 (Docker) -server3 (192.168.0.203) - grantech.kr +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 개발 환경 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ server5 (집 Win11) │ +│ │ Remote Desktop │ +│ ▼ │ +│ server4 (회사 Win11) ─── Claude Code 실행, 소스 편집 │ +│ │ │ +│ │ git push staging main │ +│ ▼ │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 운영 환경 (192.168.0.x) │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ server1 (192.168.0.201) server2 (192.168.0.202) │ +│ ┌─────────────────────┐ ┌─────────────────────────────────────┐ │ +│ │ PostgreSQL (5432) │◄────────►│ Docker Containers │ │ +│ │ Redis (6379) │ │ ├─ autonet-frontend (:3000) │ │ +│ │ Nginx Proxy Manager │ │ ├─ autonet-backend (:8000) │ │ +│ └─────────────────────┘ │ └─ carmodoo-agent │ │ +│ │ │ │ +│ │ Git Bare Repository │ │ +│ │ └─ /opt/autonet/git/autonet.git │ │ +│ │ │ │ +│ │ Staging: /opt/autonet/staging/ │ │ +│ │ Production: /opt/autonet/production/│ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ server3 (192.168.0.203) - grantech.kr (별도 서비스) │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ ``` -## 배포 흐름 +### 1.2 서버별 역할 + +| 서버 | IP | 역할 | 주요 서비스 | +|------|-----|------|------------| +| server5 | 집 | 원격 접속용 | Remote Desktop | +| server4 | 회사 | **개발서버** | Claude Code, VS Code, Git | +| server1 | 192.168.0.201 | **DB/인프라** | PostgreSQL, Redis, Nginx Proxy Manager | +| server2 | 192.168.0.202 | **운영서버** | Docker (Frontend, Backend, Agent) | +| server3 | 192.168.0.203 | 기타 | grantech.kr | + +--- + +## 2. 소스 코드 버전 관리 + +### 2.1 Git 저장소 구조 ``` -[server4 개발] - │ - ▼ git push staging main -[server2 스테이징 자동 배포] - │ - ▼ ssh server2 "/opt/autonet/scripts/deploy.sh promote" -[server2 운영 배포] +server4 (개발서버) server2 (운영서버) +┌────────────────────┐ ┌────────────────────────────────┐ +│ D:\Workspace\ │ │ /opt/autonet/ │ +│ claudeCode\ │ git push │ ├── git/autonet.git (bare) │ +│ AutonetSellCar.com │ ───────────► │ ├── staging/ (checkout) │ +│ │ staging │ ├── production/ (rsync copy) │ +│ .git/ │ │ ├── releases/ (백업) │ +│ ├── remote: staging│ │ └── scripts/ (배포스크립트) │ +└────────────────────┘ └────────────────────────────────┘ +``` + +### 2.2 Git Remote 설정 + +```bash +# 개발서버(server4)에서 확인 +git remote -v +# staging ssh://damon@192.168.0.202/opt/autonet/git/autonet.git (fetch) +# staging ssh://damon@192.168.0.202/opt/autonet/git/autonet.git (push) ``` --- -## 일반 배포 (코드만 변경) +## 3. 배포 흐름 (Data Flow) + +### 3.1 전체 배포 프로세스 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Step 1: 개발 (server4) │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 코드 수정 → git add → git commit │ +│ │ +│ $ git add -A && git commit -m "변경 내용" │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Step 2: 스테이징 배포 (자동) │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ $ git push staging main │ +│ │ +│ [자동 실행: post-receive hook] │ +│ 1. /opt/autonet/staging/ 에 코드 checkout │ +│ 2. Docker 컨테이너 빌드 및 시작 │ +│ 3. 스테이징 서버 가동 (포트 3001, 8001) │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Step 3: 스테이징 검증 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ Frontend: http://192.168.0.202:3001 │ +│ Backend: http://192.168.0.202:8001/docs │ +│ │ +│ ※ 반드시 브라우저에서 변경사항 확인! │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Step 4: 운영 승격 (수동) │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ $ ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh promote" │ +│ │ +│ [실행 내용] │ +│ 1. 현재 운영 버전 → /opt/autonet/releases/에 백업 │ +│ 2. staging → production 으로 rsync 복사 │ +│ ※ .env, *.db, uploads/ 는 제외 (preserve) │ +│ 3. Docker 컨테이너 재빌드 및 시작 │ +│ 4. 운영 서버 가동 (포트 3000, 8000) │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Step 5: 운영 확인 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ https://autonetsellcar.com │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 배포 명령어 요약 ```bash # 1. 커밋 @@ -35,83 +143,92 @@ git add -A && git commit -m "변경 내용" # 2. 스테이징 배포 (자동) git push staging main -# 3. 운영 승격 +# 3. 스테이징 확인 +# 브라우저: http://192.168.0.202:3001 + +# 4. 운영 승격 (확인 후) ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh promote" ``` --- -## DB 스키마 변경 시 (중요!) +## 4. 중요: 배포 시 보존되는 파일들 -### SQLite 특성 -- SQLAlchemy 모델에 컬럼 추가해도 **DB에 자동 반영 안 됨** -- Docker 재시작해도 DB 볼륨은 유지됨 -- **반드시 수동으로 ALTER TABLE 실행 필요!** +### 4.1 rsync 제외 목록 (deploy.sh) -### 새 컬럼 추가 시 체크리스트 +`deploy.sh promote` 실행 시 다음 파일/폴더는 **복사되지 않음**: + +| 제외 항목 | 이유 | +|----------|------| +| `.env` | 환경변수 (DB접속정보, API키 등) - 서버별로 다름 | +| `*.db` | SQLite 데이터베이스 (현재 미사용이지만 안전상) | +| `uploads/` | 업로드된 파일 (PDF, 이미지 등) | + +### 4.2 .env 파일 관리 (매우 중요!) ``` -□ 1. backend/app/models/*.py - 모델에 컬럼 추가 -□ 2. backend/app/schemas/*.py - 스키마에 필드 추가 -□ 3. backend/app/api/*.py - API 기본값 설정 -□ 4. git commit & push -□ 5. 운영 배포 후 DB에 컬럼 추가 (아래 명령어) -□ 6. 테스트 +/opt/autonet/staging/backend/.env ← 스테이징용 .env +/opt/autonet/production/backend/.env ← 운영용 .env (절대 덮어쓰면 안됨!) ``` -### DB 컬럼 추가 명령어 - -```bash -# 운영서버 DB에 컬럼 추가 -ssh damon@192.168.0.202 "docker exec autonet-backend python -c \" -import sqlite3 -for db in ['/app/autonet.db', '/app/autonet_data.db']: - try: - conn = sqlite3.connect(db) - conn.execute('ALTER TABLE 테이블명 ADD COLUMN 컬럼명 타입 DEFAULT 기본값') - conn.commit() - print(f'{db}: OK') - except Exception as e: - print(f'{db}: {e}') -\"" -``` - -### 예시: cc_per_banner_view 컬럼 추가 - -```bash -ssh damon@192.168.0.202 "docker exec autonet-backend python -c \" -import sqlite3 -for db in ['/app/autonet.db', '/app/autonet_data.db']: - try: - conn = sqlite3.connect(db) - conn.execute('ALTER TABLE system_settings ADD COLUMN cc_per_banner_view REAL DEFAULT 0.1') - conn.commit() - print(f'{db}: OK') - except Exception as e: - print(f'{db}: {e}') -\"" -``` - -### SQLite 타입 매핑 - -| Python/SQLAlchemy | SQLite | -|-------------------|--------| -| Integer | INTEGER | -| Float | REAL | -| String | TEXT | -| Boolean | INTEGER (0/1) | -| DateTime | TEXT | +**핵심 원칙**: `.env` 파일은 서버에 직접 생성하고, 배포로 덮어쓰지 않음 --- -## 롤백 +## 5. 데이터베이스 연결 + +### 5.1 DB 아키텍처 + +``` +┌─────────────────────┐ ┌─────────────────────┐ +│ server2 (Docker) │ │ server1 │ +│ │ │ │ +│ autonet-backend ────┼────────►│ PostgreSQL :5432 │ +│ │ TCP │ Database: autonet │ +│ │ │ │ +└─────────────────────┘ └─────────────────────┘ +``` + +### 5.2 환경변수 (backend/.env) + +```env +# 필수 - DB가 server1에 있음! +USE_SQLITE=False +DB_HOST=192.168.0.201 +DB_PORT=5432 +DB_NAME=autonet +DB_USER=admin +DB_PASSWORD=roskfl@1122 +``` + +### 5.3 DB 스키마 변경 시 + +PostgreSQL 직접 접속하여 ALTER TABLE 실행: + +```bash +# server1에서 직접 실행 +psql -U admin -d autonet -c "ALTER TABLE users ADD COLUMN new_column VARCHAR(100);" + +# 또는 server2에서 원격 실행 +ssh damon@192.168.0.202 "docker exec autonet-backend python -c \" +from app.database import engine +from sqlalchemy import text +with engine.connect() as conn: + conn.execute(text('ALTER TABLE users ADD COLUMN new_column VARCHAR(100)')) + conn.commit() +\"" +``` + +--- + +## 6. 롤백 ```bash # 직전 버전으로 롤백 ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh rollback" # 특정 버전으로 롤백 -ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh rollback-to 20260101_094303" +ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh rollback-to 20260101_211517" # 릴리즈 목록 확인 ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh status" @@ -119,7 +236,7 @@ ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh status" --- -## 서버 상태 확인 +## 7. 서버 상태 확인 ```bash # 컨테이너 상태 @@ -131,114 +248,136 @@ ssh damon@192.168.0.202 "docker logs autonet-backend --tail 50" # 프론트엔드 로그 ssh damon@192.168.0.202 "docker logs autonet-frontend --tail 50" -# DB 테이블 확인 +# 환경변수 확인 (DB 연결 설정) ssh damon@192.168.0.202 "docker exec autonet-backend python -c \" -import sqlite3 -conn = sqlite3.connect('/app/autonet.db') -cursor = conn.cursor() -cursor.execute('PRAGMA table_info(system_settings)') -for row in cursor.fetchall(): - print(row) +import os +print('USE_SQLITE:', os.getenv('USE_SQLITE')) +print('DB_HOST:', os.getenv('DB_HOST')) \"" ``` --- -## SSH 키 설정 (server4 → server1,2,3) +## 8. 절대 하지 말아야 할 것들 -```powershell -# 공개키 확인 -cat ~/.ssh/id_ed25519.pub +### 8.1 .env 파일 관련 -# 각 서버에 등록 -# server1,2,3 각각에서: -nano ~/.ssh/authorized_keys -# 공개키 붙여넣기 -``` +| 금지 사항 | 이유 | 올바른 방법 | +|----------|------|------------| +| `.env`를 git에 커밋 | 보안 위험 | `.gitignore`에 포함됨 | +| 운영서버 `.env` 직접 삭제 | 서비스 중단 | 백업 후 수정 | +| docker-compose에서 `.env` 볼륨 마운트 | 파일/디렉토리 혼동 | `env_file:` 사용 | ---- +### 8.2 이전에 발생한 실수와 해결책 -## 자주 발생하는 문제 +#### 실수 1: .env가 디렉토리로 생성됨 -### 1. "no such column" 에러 -- **원인**: 코드에 새 컬럼 추가했지만 DB에는 없음 -- **해결**: ALTER TABLE로 컬럼 추가 (위 참고) +**증상**: +- 로그인 실패 +- `(sqlite3.OperationalError) no such column` 에러 +- 이메일 발송 안됨 -### 2. "Failed to save settings" 에러 -- **원인**: 보통 DB 스키마 불일치 -- **확인**: `docker logs autonet-backend --tail 30` -- **해결**: 누락된 컬럼 추가 - -### 3. 번역 안 됨 -- **원인**: i18n.ts에 해당 단어 번역 없음 -- **해결**: CAR_TRANSLATIONS에 번역 추가 - -### 4. 배포 후 변경사항 안 보임 -- **프론트엔드**: 브라우저 캐시 클리어 (Ctrl+Shift+R) -- **백엔드**: 컨테이너 재시작 확인 - -### 5. "Login failed" / SQLite 에러 -- **원인**: `.env` 파일이 디렉토리로 생성되어 환경변수 로드 실패 -- **증상**: `(sqlite3.OperationalError) no such column` 에러 -- **확인**: `ls -la /opt/autonet/production/backend/.env` -- **해결**: - ```bash - # .env가 디렉토리인 경우 - rm -rf /opt/autonet/production/backend/.env - # .env 파일 재생성 (개발서버에서 복사 또는 수동 생성) - # 컨테이너 재시작 - cd /opt/autonet/production && docker-compose -f docker-compose.production.yml up -d --force-recreate - ``` - ---- - -## .env 파일 관리 (중요!) - -### 운영서버 .env 파일 위치 - -``` -/opt/autonet/production/backend/.env -/opt/autonet/production/agent/.env (빈 파일) -``` - -### .env가 없거나 디렉토리로 생성된 경우 - -**증상**: 이메일이 안 보내짐, `[DEV]` 로그 출력 +**원인**: +- docker-compose에서 `.env`를 볼륨으로 마운트할 때, 파일이 없으면 디렉토리로 생성됨 +- 환경변수 로드 실패 → `USE_SQLITE=True` 기본값 사용 → SQLite 사용 시도 **해결**: ```bash -# .env가 디렉토리로 잘못 생성된 경우 +# 1. .env가 디렉토리인지 확인 +ssh damon@192.168.0.202 "ls -la /opt/autonet/production/backend/.env" + +# 2. 디렉토리면 삭제 ssh damon@192.168.0.202 "rm -rf /opt/autonet/production/backend/.env" -# 개발서버에서 .env 복사 또는 수동 생성 -scp backend/.env damon@192.168.0.202:/opt/autonet/production/backend/.env +# 3. 파일로 생성 +ssh damon@192.168.0.202 "cat > /opt/autonet/production/backend/.env << 'EOF' +USE_SQLITE=False +DB_HOST=192.168.0.201 +DB_PORT=5432 +DB_NAME=autonet +DB_USER=admin +DB_PASSWORD=roskfl@1122 +# ... 나머지 환경변수 +EOF" -# 컨테이너 재시작 -ssh damon@192.168.0.202 "cd /opt/autonet/production && docker compose -f docker-compose.production.yml down && docker compose -f docker-compose.production.yml up -d" +# 4. 컨테이너 재시작 +ssh damon@192.168.0.202 "cd /opt/autonet/production && docker-compose -f docker-compose.production.yml up -d --force-recreate" ``` -### 필수 환경변수 - -| 변수 | 설명 | 예시 | -|------|------|------| -| SMTP_USER | Gmail 계정 | autonetsellcar@gmail.com | -| SMTP_PASSWORD | 앱 비밀번호 | (16자리) | -| AZURE_TRANSLATOR_KEY | Azure 번역 API 키 | (API 키) | -| STRIPE_SECRET_KEY | Stripe 결제 키 | sk_live_... | +**예방책** (이미 적용됨): +- `docker-compose.production.yml`에서 `env_file:` 사용 (볼륨 마운트 대신) +- `deploy.sh`에서 `.env` rsync 제외 --- -## 변경 이력 +## 9. 필수 환경변수 목록 + +| 변수 | 설명 | 필수 | +|------|------|------| +| `USE_SQLITE` | `False` (PostgreSQL 사용) | ★ | +| `DB_HOST` | `192.168.0.201` | ★ | +| `DB_PORT` | `5432` | ★ | +| `DB_NAME` | `autonet` | ★ | +| `DB_USER` | `admin` | ★ | +| `DB_PASSWORD` | (비밀번호) | ★ | +| `SMTP_USER` | Gmail 계정 | ★ | +| `SMTP_PASSWORD` | 앱 비밀번호 (16자리) | ★ | +| `AZURE_TRANSLATOR_KEY` | Azure 번역 API 키 | ★ | +| `STRIPE_SECRET_KEY` | Stripe 결제 키 | 선택 | + +--- + +## 10. SSH 키 설정 + +```powershell +# server4에서 공개키 확인 +cat ~/.ssh/id_ed25519.pub + +# server2에 등록 +ssh damon@192.168.0.202 "echo '공개키내용' >> ~/.ssh/authorized_keys" +``` + +--- + +## 11. 변경 이력 | 날짜 | 변경 내용 | DB 변경 | |------|----------|---------| -| 2026-01-01 | .env 파일 문제 해결 (디렉토리→파일), deploy.sh rsync에서 .env 제외, docker-compose env_file 방식 | - | +| 2026-01-01 | Cost 페이지 배경색/폭 통일 | - | +| 2026-01-01 | .env 파일 문제 해결, deploy.sh rsync에서 .env 제외, docker-compose env_file 방식 | - | | 2026-01-01 | 강력한 비밀번호 정책 및 로그인 보안 강화 | users: failed_login_attempts, locked_until, password_reset_required | | 2026-01-01 | 삭제된 사용자 재가입 허용 수정 | - | | 2026-01-01 | inquiries 테이블 누락 컬럼 추가 | inquiries: category, subject 등 8개 컬럼 | | 2026-01-01 | 운영서버 .env 파일 생성 (SMTP 설정) | - | | 2026-01-01 | cc_per_banner_view 설정 추가 | system_settings.cc_per_banner_view (REAL) | -| 2026-01-01 | 마이스터 번역 추가 | - | + +--- + +## 12. 빠른 참조 (Quick Reference) + +### 일반 배포 +```bash +git add -A && git commit -m "메시지" +git push staging main +# 스테이징 확인: http://192.168.0.202:3001 +ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh promote" +``` + +### 롤백 +```bash +ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh rollback" +``` + +### 로그 확인 +```bash +ssh damon@192.168.0.202 "docker logs autonet-backend --tail 50" +``` + +### .env 문제 시 +```bash +ssh damon@192.168.0.202 "ls -la /opt/autonet/production/backend/.env" +# 디렉토리면 삭제 후 파일로 재생성 +``` ---