Add deployment guide with ASCII art diagrams
Comprehensive documentation covering: - Full deployment pipeline overview - Server environment configuration - Step-by-step deployment process - Manual SCP deployment method - Docker container architecture - Rollback procedures - Quick reference commands - Troubleshooting guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,330 +1,525 @@
|
|||||||
# 사이트 배포 가이드
|
# AutonetSellCar.com 배포 가이드
|
||||||
|
|
||||||
## 개요
|
이 문서는 코드 수정부터 운영 배포까지의 전체 과정을 설명합니다.
|
||||||
|
|
||||||
이 문서는 Next.js Frontend + FastAPI Backend 사이트를 Ubuntu 서버에 배포하는 전체 과정을 설명합니다.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 배포 순서도
|
## 1. 전체 배포 흐름 개요
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 사이트 배포 전체 흐름 │
|
│ 배포 파이프라인 전체 흐름 │
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
1. 사전 준비
|
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||||
│
|
│ 1. 개발 │ ───▶ │ 2. 커밋 │ ───▶ │ 3. 스테이징 │ ───▶ │ 4. 운영 │
|
||||||
├─→ DNS 설정 (도메인 → 공인 IP)
|
│ (서버4) │ │ & Push │ │ 테스트 │ │ 배포 │
|
||||||
│ ├─ example.com → 59.14.158.123
|
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
|
||||||
│ ├─ www.example.com → 59.14.158.123
|
│ │ │ │
|
||||||
│ └─ api.example.com → 59.14.158.123 ★ 중요: API 서브도메인 필수
|
▼ ▼ ▼ ▼
|
||||||
│
|
코드 수정 git commit Docker 빌드 promote
|
||||||
├─→ 공유기 포트포워딩
|
로컬 테스트 git push staging 포트 3001/8001 포트 3000/8000
|
||||||
│ ├─ 80 → 192.168.0.201:80 (NPM)
|
|
||||||
│ └─ 443 → 192.168.0.201:443 (NPM)
|
|
||||||
│
|
|
||||||
└─→ 서버 준비
|
|
||||||
├─ Docker 설치
|
|
||||||
├─ Node.js 설치
|
|
||||||
└─ Python 설치
|
|
||||||
|
|
||||||
2. 소스코드 전송
|
|
||||||
│
|
|
||||||
├─→ 압축 (node_modules 제외)
|
|
||||||
│ └─ 7z a -tzip project.zip frontend backend -xr!node_modules
|
|
||||||
│
|
|
||||||
├─→ 전송 (내부망 경유 권장)
|
|
||||||
│ └─ scp project.zip damon@192.168.0.203:~/sites/project/
|
|
||||||
│
|
|
||||||
└─→ 압축 해제
|
|
||||||
└─ unzip project.zip
|
|
||||||
|
|
||||||
3. Backend 배포
|
|
||||||
│
|
|
||||||
├─→ 가상환경 생성
|
|
||||||
│ └─ python3 -m venv venv && source venv/bin/activate
|
|
||||||
│
|
|
||||||
├─→ 의존성 설치
|
|
||||||
│ └─ pip install -r requirements.txt
|
|
||||||
│
|
|
||||||
├─→ ★★★ CORS 설정 수정 ★★★
|
|
||||||
│ └─ config.py의 CORS_ORIGINS에 도메인 추가
|
|
||||||
│ - http://example.com
|
|
||||||
│ - https://example.com
|
|
||||||
│ - http://www.example.com
|
|
||||||
│ - https://www.example.com
|
|
||||||
│
|
|
||||||
├─→ Admin 계정 생성/리셋
|
|
||||||
│ └─ python init_admin.py 또는 reset_pw.py 실행
|
|
||||||
│
|
|
||||||
└─→ 서버 실행
|
|
||||||
└─ nohup uvicorn app.main:app --host 0.0.0.0 --port 8001 > ~/logs/backend.log 2>&1 &
|
|
||||||
|
|
||||||
4. Frontend 배포
|
|
||||||
│
|
|
||||||
├─→ 의존성 설치
|
|
||||||
│ └─ npm install
|
|
||||||
│
|
|
||||||
├─→ ★★★ 환경변수 설정 ★★★
|
|
||||||
│ └─ echo "NEXT_PUBLIC_API_URL=http://api.example.com/api" > .env.local
|
|
||||||
│
|
|
||||||
├─→ 빌드
|
|
||||||
│ └─ npm run build
|
|
||||||
│
|
|
||||||
└─→ 서버 실행
|
|
||||||
└─ nohup sh -c 'PORT=3001 npm start' > ~/logs/frontend.log 2>&1 &
|
|
||||||
|
|
||||||
5. NPM (Nginx Proxy Manager) 설정
|
|
||||||
│
|
|
||||||
├─→ Frontend Proxy Host
|
|
||||||
│ ├─ Domain: example.com, www.example.com
|
|
||||||
│ ├─ Forward: 192.168.0.203:3001
|
|
||||||
│ └─ SSL: Let's Encrypt
|
|
||||||
│
|
|
||||||
└─→ ★★★ API Proxy Host ★★★
|
|
||||||
├─ Domain: api.example.com
|
|
||||||
├─ Forward: 192.168.0.203:8001
|
|
||||||
└─ SSL: Let's Encrypt
|
|
||||||
|
|
||||||
6. 테스트
|
|
||||||
│
|
|
||||||
├─→ 사이트 접속: http://example.com
|
|
||||||
├─→ API 접속: http://api.example.com/api/health
|
|
||||||
└─→ Admin 로그인: http://example.com/admin/login
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 핵심 체크리스트
|
## 2. 서버 환경 구성
|
||||||
|
|
||||||
### 배포 전 필수 확인 사항
|
|
||||||
|
|
||||||
- [ ] DNS에 api 서브도메인 A 레코드 추가했는가?
|
|
||||||
- [ ] NPM에 api.도메인 프록시 설정했는가?
|
|
||||||
- [ ] Backend CORS_ORIGINS에 도메인 추가했는가?
|
|
||||||
- [ ] Frontend .env.local에 API URL 설정했는가?
|
|
||||||
- [ ] Admin 계정이 DB에 존재하는가?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 자주 발생하는 문제와 해결법
|
|
||||||
|
|
||||||
### 1. 사이트 로딩만 계속됨 (뱅글뱅글)
|
|
||||||
|
|
||||||
**원인**: Frontend가 API에 연결하지 못함
|
|
||||||
|
|
||||||
**확인 순서**:
|
|
||||||
```bash
|
|
||||||
# 1. Backend 실행 확인
|
|
||||||
ps aux | grep uvicorn
|
|
||||||
|
|
||||||
# 2. API 직접 테스트
|
|
||||||
curl http://api.example.com/api/health
|
|
||||||
|
|
||||||
# 3. .env.local 확인
|
|
||||||
cat ~/sites/project/frontend/.env.local
|
|
||||||
|
|
||||||
# 4. 빌드에 환경변수 적용 확인
|
|
||||||
grep -r "api.example" ~/sites/project/frontend/.next/ | head -3
|
|
||||||
```
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 네트워크 구성도 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
**해결**:
|
┌────────────────────┐ ┌────────────────────────────────┐
|
||||||
```bash
|
│ 서버4 │ │ 서버2 │
|
||||||
# .env.local 설정 후 재빌드
|
│ (개발 서버) │ │ (운영 서버) │
|
||||||
echo "NEXT_PUBLIC_API_URL=http://api.example.com/api" > .env.local
|
│ │ SSH/SCP │ 192.168.0.202 │
|
||||||
rm -rf .next
|
│ ┌──────────────┐ │ ─────────────────▶ │ │
|
||||||
npm run build
|
│ │ 소스 코드 │ │ │ ┌────────────┐ ┌────────────┐ │
|
||||||
|
│ │ (로컬 개발) │ │ │ │ Staging │ │ Production │ │
|
||||||
|
│ └──────────────┘ │ │ │ :3001/:8001│ │ :3000/:8000│ │
|
||||||
|
│ │ │ └────────────┘ └────────────┘ │
|
||||||
|
│ D:\Workspace\ │ │ │
|
||||||
|
│ claudeCode\ │ │ /opt/autonet/ │
|
||||||
|
│ AutonetSellCar.com│ │ ├── staging/ │
|
||||||
|
│ │ │ ├── production/ │
|
||||||
|
│ │ │ └── git/autonet.git │
|
||||||
|
└────────────────────┘ └────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. CORS 에러
|
## 3. 디렉토리 구조
|
||||||
|
|
||||||
**원인**: Backend에서 Frontend 도메인을 허용하지 않음
|
|
||||||
|
|
||||||
**증상**: 브라우저 Network 탭에서 "CORS error" 표시
|
|
||||||
|
|
||||||
**확인**:
|
|
||||||
```bash
|
|
||||||
cat ~/sites/project/backend/app/core/config.py | grep CORS
|
|
||||||
```
|
```
|
||||||
|
서버2 (/opt/autonet/)
|
||||||
**해결**: config.py의 CORS_ORIGINS에 도메인 추가
|
│
|
||||||
```python
|
├── git/
|
||||||
CORS_ORIGINS: list = [
|
│ └── autonet.git/ # Bare Git Repository
|
||||||
"http://localhost:3000",
|
│ └── hooks/
|
||||||
"http://example.com",
|
│ └── post-receive # 자동 배포 훅
|
||||||
"https://example.com",
|
│
|
||||||
"http://www.example.com",
|
├── staging/ # 스테이징 환경
|
||||||
"https://www.example.com"
|
│ ├── frontend/
|
||||||
]
|
│ ├── backend/
|
||||||
```
|
│ └── docker-compose.staging.yml
|
||||||
|
│
|
||||||
Backend 재시작:
|
├── production/ # 운영 환경
|
||||||
```bash
|
│ ├── frontend/
|
||||||
pkill -f uvicorn
|
│ ├── backend/
|
||||||
nohup uvicorn app.main:app --host 0.0.0.0 --port 8001 > ~/logs/backend.log 2>&1 &
|
│ └── docker-compose.production.yml
|
||||||
|
│
|
||||||
|
├── releases/ # 롤백용 백업
|
||||||
|
│ ├── 20241230_140000/
|
||||||
|
│ └── 20241230_150000/
|
||||||
|
│
|
||||||
|
└── scripts/
|
||||||
|
├── deploy-staging.sh
|
||||||
|
└── deploy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 3. 로그인 안 됨
|
## 4. 단계별 상세 설명
|
||||||
|
|
||||||
**원인**: DB에 admin 계정이 없거나 비밀번호가 다름
|
### Step 1: 코드 수정 (서버4)
|
||||||
|
|
||||||
**확인**:
|
```
|
||||||
```bash
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# API 직접 테스트
|
│ Step 1: 코드 수정 │
|
||||||
curl -X POST "http://api.example.com/api/auth/login" \
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"username":"admin","password":"비밀번호"}'
|
개발자 PC (서버4)
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ D:\Workspace\claudeCode\ │
|
||||||
|
│ └── AutonetSellCar.com\ │
|
||||||
|
│ ├── backend\ │
|
||||||
|
│ │ └── app\ │
|
||||||
|
│ │ ├── api\ ◀── 수정 │
|
||||||
|
│ │ ├── models\ │
|
||||||
|
│ │ └── schemas\ ◀── 수정 │
|
||||||
|
│ │ │
|
||||||
|
│ └── frontend\ │
|
||||||
|
│ └── src\ │
|
||||||
|
│ ├── app\ ◀── 수정 │
|
||||||
|
│ ├── components\ ◀── 수정 │
|
||||||
|
│ └── lib\ ◀── 수정 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────┐ │
|
||||||
|
│ │ 로컬 테스트 서버 │ │
|
||||||
|
│ │ Frontend: http://localhost:3000│ │
|
||||||
|
│ │ Backend: http://localhost:8000│ │
|
||||||
|
│ └─────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
|
||||||
|
명령어:
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ # Backend 실행 │
|
||||||
|
│ cd backend │
|
||||||
|
│ venv\Scripts\activate │
|
||||||
|
│ uvicorn app.main:app --reload --port 8000│
|
||||||
|
│ │
|
||||||
|
│ # Frontend 실행 │
|
||||||
|
│ cd frontend │
|
||||||
|
│ npm run dev │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**해결**: 비밀번호 리셋 스크립트 실행
|
### Step 2: Git Commit & Push
|
||||||
```bash
|
|
||||||
cd ~/sites/project/backend
|
```
|
||||||
source venv/bin/activate
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
cat > reset_pw.py << 'EOF'
|
│ Step 2: Git Commit & Push │
|
||||||
from app.core.database import SessionLocal
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
from app.models.admin import Admin
|
|
||||||
from app.core.security import get_password_hash
|
┌───────────────┐ ┌───────────────┐
|
||||||
db = SessionLocal()
|
│ 서버4 │ │ 서버2 │
|
||||||
admin = db.query(Admin).filter(Admin.username == 'admin').first()
|
│ (개발) │ │ (운영) │
|
||||||
if admin:
|
└───────┬───────┘ └───────┬───────┘
|
||||||
admin.password_hash = get_password_hash('새비밀번호')
|
│ │
|
||||||
db.commit()
|
│ 1. git add . │
|
||||||
print('Password reset')
|
│ 2. git commit -m "message" │
|
||||||
else:
|
│ │
|
||||||
print('Admin not found')
|
▼ │
|
||||||
db.close()
|
┌───────────────┐ │
|
||||||
EOF
|
│ Local Repo │ │
|
||||||
python reset_pw.py
|
│ (main) │ │
|
||||||
|
└───────┬───────┘ │
|
||||||
|
│ │
|
||||||
|
│ 3. git push staging main │
|
||||||
|
│ │
|
||||||
|
│ SSH (포트 22) │
|
||||||
|
│ ════════════════════════════════════▶ │
|
||||||
|
│ ▼
|
||||||
|
│ ┌───────────────┐
|
||||||
|
│ │ Bare Repo │
|
||||||
|
│ │ autonet.git │
|
||||||
|
│ └───────┬───────┘
|
||||||
|
│ │
|
||||||
|
│ │ post-receive 훅 실행
|
||||||
|
│ ▼
|
||||||
|
│ ┌───────────────┐
|
||||||
|
│ │ 스테이징 │
|
||||||
|
│ │ 자동 배포 │
|
||||||
|
│ └───────────────┘
|
||||||
|
|
||||||
|
명령어:
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ git status │
|
||||||
|
│ git add . │
|
||||||
|
│ git commit -m "feat: 기능 설명" │
|
||||||
|
│ git push staging main │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: 스테이징 테스트
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Step 3: 스테이징 테스트 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
서버2 스테이징 환경
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ /opt/autonet/staging/ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||||
|
│ │ Frontend Container │ │ Backend Container │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ autonet-frontend │ │ autonet-backend │ │
|
||||||
|
│ │ -staging │ │ -staging │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ Port: 3001 ─────┼─────▶ Port: 8001 │ │
|
||||||
|
│ │ │ API │ │ │
|
||||||
|
│ └─────────────────────┘ └──────────┬──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────────┐ │
|
||||||
|
│ │ staging-db │ │
|
||||||
|
│ │ (SQLite/Volume) │ │
|
||||||
|
│ └─────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
테스트 URL:
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Frontend: http://192.168.0.202:3001 │
|
||||||
|
│ Backend: http://192.168.0.202:8001 │
|
||||||
|
│ API Docs: http://192.168.0.202:8001/docs│
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
|
||||||
|
수동 빌드 명령어 (SSH 접속 후):
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ cd /opt/autonet/staging │
|
||||||
|
│ docker compose -f docker-compose.staging.yml down│
|
||||||
|
│ docker compose -f docker-compose.staging.yml build --no-cache│
|
||||||
|
│ docker compose -f docker-compose.staging.yml up -d│
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: 운영 배포 (Promote)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Step 4: 운영 배포 (Promote) │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────────┐ ┌─────────────────────┐
|
||||||
|
│ 스테이징 │ promote │ 운영 │
|
||||||
|
│ (테스트 완료) │ ══════════▶ │ (서비스 중) │
|
||||||
|
│ :3001 / :8001 │ │ :3000 / :8000 │
|
||||||
|
└─────────────────────┘ └─────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
│ ┌─────────────────────┐
|
||||||
|
│ │ 백업 생성 │
|
||||||
|
│ │ /releases/ │
|
||||||
|
│ │ 20241230_160000/ │
|
||||||
|
│ └─────────────────────┘
|
||||||
|
|
||||||
|
배포 흐름:
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 1. 현재 운영 백업 │
|
||||||
|
│ └── /opt/autonet/releases/20241230_160000/ │
|
||||||
|
│ │
|
||||||
|
│ 2. 운영 컨테이너 중지 │
|
||||||
|
│ └── docker compose down │
|
||||||
|
│ │
|
||||||
|
│ 3. 스테이징 → 운영 복사 (DB/uploads 제외) │
|
||||||
|
│ └── rsync -av --exclude='*.db' staging/ production/ │
|
||||||
|
│ │
|
||||||
|
│ 4. 운영 컨테이너 빌드 & 시작 │
|
||||||
|
│ └── docker compose up -d --build │
|
||||||
|
│ │
|
||||||
|
│ 5. 헬스체크 │
|
||||||
|
│ └── curl http://localhost:3000 && curl http://localhost:8000 │
|
||||||
|
│ │
|
||||||
|
│ 6. 실패 시 자동 롤백 │
|
||||||
|
│ └── deploy.sh rollback │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
명령어:
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ # 스테이징 → 운영 승격 │
|
||||||
|
│ /opt/autonet/scripts/deploy.sh promote │
|
||||||
|
│ │
|
||||||
|
│ # 롤백 (문제 발생 시) │
|
||||||
|
│ /opt/autonet/scripts/deploy.sh rollback │
|
||||||
|
│ │
|
||||||
|
│ # 상태 확인 │
|
||||||
|
│ /opt/autonet/scripts/deploy.sh status │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. 포트 충돌 (EADDRINUSE)
|
## 5. 수동 배포 방법 (SCP 직접 전송)
|
||||||
|
|
||||||
**원인**: 기존 프로세스가 포트를 점유 중
|
긴급 배포 또는 post-receive 훅 미설정 시 사용합니다.
|
||||||
|
|
||||||
**확인**:
|
|
||||||
```bash
|
|
||||||
sudo netstat -tlnp | grep 3001
|
|
||||||
sudo netstat -tlnp | grep 8001
|
|
||||||
```
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 수동 배포 (SCP 방식) │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
**해결**:
|
서버4 (개발) 서버2 (운영)
|
||||||
```bash
|
┌───────────────┐ ┌───────────────┐
|
||||||
# PID 확인 후 종료
|
│ │ │ │
|
||||||
sudo kill -9 <PID>
|
│ 수정된 파일 │ SCP 전송 │ production/ │
|
||||||
|
│ frontend/ │ ═══════════════════════▶│ frontend/ │
|
||||||
|
│ backend/ │ │ backend/ │
|
||||||
|
│ │ │ │
|
||||||
|
└───────────────┘ └───────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────┐
|
||||||
|
│ Docker 재빌드 │
|
||||||
|
│ │
|
||||||
|
│ docker build │
|
||||||
|
│ docker run │
|
||||||
|
└───────────────┘
|
||||||
|
|
||||||
# 또는 프로세스 이름으로 종료
|
Step 1: 파일 전송 (PowerShell에서)
|
||||||
pkill -f "npm start"
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
pkill -f uvicorn
|
│ # Frontend 파일 전송 │
|
||||||
|
│ scp -r frontend/src/app/admin/*.tsx \ │
|
||||||
|
│ damon@192.168.0.202:/opt/autonet/production/frontend/src/app/admin/│
|
||||||
|
│ │
|
||||||
|
│ # Backend 파일 전송 │
|
||||||
|
│ scp -r backend/app/* \ │
|
||||||
|
│ damon@192.168.0.202:/opt/autonet/production/backend/app/ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
Step 2: Docker 재빌드 (서버2 SSH 접속 후)
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ cd /opt/autonet/production │
|
||||||
|
│ │
|
||||||
|
│ # Frontend 재빌드 │
|
||||||
|
│ docker stop autonet-frontend │
|
||||||
|
│ docker rm autonet-frontend │
|
||||||
|
│ docker build -t autonet-frontend-prod \ │
|
||||||
|
│ --build-arg NEXT_PUBLIC_API_URL=http://192.168.0.202:8000 \ │
|
||||||
|
│ ./frontend │
|
||||||
|
│ docker run -d --name autonet-frontend \ │
|
||||||
|
│ -p 3000:3000 \ │
|
||||||
|
│ -e NEXT_PUBLIC_API_URL=http://192.168.0.202:8000 \ │
|
||||||
|
│ autonet-frontend-prod │
|
||||||
|
│ │
|
||||||
|
│ # Backend 재빌드 │
|
||||||
|
│ docker stop autonet-backend │
|
||||||
|
│ docker rm autonet-backend │
|
||||||
|
│ docker build -t autonet-backend-prod ./backend │
|
||||||
|
│ docker run -d --name autonet-backend \ │
|
||||||
|
│ -p 8000:8000 \ │
|
||||||
|
│ -v $(pwd)/backend/uploads:/app/uploads \ │
|
||||||
|
│ -v $(pwd)/backend/autonet.db:/app/autonet.db \ │
|
||||||
|
│ autonet-backend-prod │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. 500 Internal Server Error (정적 파일)
|
## 6. Docker 컨테이너 구성
|
||||||
|
|
||||||
**원인**: 빌드 파일 손상 또는 캐시 문제
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Docker 컨테이너 구성도 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
**해결**:
|
운영 환경 (Production)
|
||||||
```bash
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
cd ~/sites/project/frontend
|
│ │
|
||||||
pkill -f "npm start"
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||||
rm -rf .next
|
│ │ Docker Network │ │
|
||||||
rm -rf node_modules/.cache
|
│ │ │ │
|
||||||
npm run build
|
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
|
||||||
nohup sh -c 'PORT=3001 npm start' > ~/logs/frontend.log 2>&1 &
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ │ autonet-frontend│ API │ autonet-backend │ │ │
|
||||||
|
│ │ │ │───────▶│ │ │ │
|
||||||
|
│ │ │ Next.js 14 │ │ FastAPI │ │ │
|
||||||
|
│ │ │ Port: 3000 │ │ Port: 8000 │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ └──────────────────┘ └────────┬─────────┘ │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ┌────────▼─────────┐ │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ │ Volumes │ │ │
|
||||||
|
│ │ │ - autonet.db │ │ │
|
||||||
|
│ │ │ - uploads/ │ │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ └──────────────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────┐ │
|
||||||
|
│ │ carmodoo-agent │ (Playwright 브라우저 자동화) │
|
||||||
|
│ │ - PDF 생성 │ │
|
||||||
|
│ │ - 차량 스펙 조회 │ │
|
||||||
|
│ └──────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
포트 매핑:
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ 호스트:3000 ──▶ 컨테이너:3000 (Frontend)│
|
||||||
|
│ 호스트:8000 ──▶ 컨테이너:8000 (Backend) │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 유용한 명령어 모음
|
## 7. 롤백 절차
|
||||||
|
|
||||||
### 프로세스 관리
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 프로세스 확인
|
|
||||||
ps aux | grep -E "npm|uvicorn|node"
|
|
||||||
|
|
||||||
# 포트 사용 확인
|
|
||||||
sudo netstat -tlnp | grep -E "3001|8001"
|
|
||||||
|
|
||||||
# 로그 확인
|
|
||||||
tail -f ~/logs/frontend.log
|
|
||||||
tail -f ~/logs/backend.log
|
|
||||||
```
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 롤백 절차 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
### 서비스 재시작
|
문제 발생!
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────┐ 아니오 ┌───────────────┐
|
||||||
|
│ 자동 롤백 │ ◀────────────── │ 헬스체크 통과?│
|
||||||
|
│ 실행됨 │ └───────────────┘
|
||||||
|
└───────┬───────┘ │ 예
|
||||||
|
│ ▼
|
||||||
|
│ ┌───────────────┐
|
||||||
|
│ │ 배포 완료 │
|
||||||
|
│ └───────────────┘
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ /opt/autonet/releases/ │
|
||||||
|
│ │ │
|
||||||
|
│ ├── 20241230_140000/ ◀── 이전 버전으로 복원 │
|
||||||
|
│ ├── 20241230_150000/ │
|
||||||
|
│ └── 20241230_160000/ ◀── 현재 (문제 발생) │
|
||||||
|
│ │
|
||||||
|
└───────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
```bash
|
롤백 명령어:
|
||||||
# Frontend 재시작
|
┌─────────────────────────────────────────┐
|
||||||
pkill -f "npm start"
|
│ # 직전 버전으로 롤백 │
|
||||||
cd ~/sites/project/frontend
|
│ /opt/autonet/scripts/deploy.sh rollback │
|
||||||
nohup sh -c 'PORT=3001 npm start' > ~/logs/frontend.log 2>&1 &
|
│ │
|
||||||
|
│ # 특정 버전으로 롤백 │
|
||||||
# Backend 재시작
|
│ /opt/autonet/scripts/deploy.sh \ │
|
||||||
pkill -f uvicorn
|
│ rollback-to 20241230_140000 │
|
||||||
cd ~/sites/project/backend
|
│ │
|
||||||
source venv/bin/activate
|
│ # 사용 가능한 버전 확인 │
|
||||||
nohup uvicorn app.main:app --host 0.0.0.0 --port 8001 > ~/logs/backend.log 2>&1 &
|
│ ls /opt/autonet/releases/ │
|
||||||
```
|
└─────────────────────────────────────────┘
|
||||||
|
|
||||||
### API 테스트
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Health check
|
|
||||||
curl http://api.example.com/api/health
|
|
||||||
|
|
||||||
# 로그인 테스트
|
|
||||||
curl -X POST "http://api.example.com/api/auth/login" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"username":"admin","password":"password"}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 서버 정보
|
## 8. 빠른 참조 명령어
|
||||||
|
|
||||||
### 네트워크 구성
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 빠른 참조 명령어 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
| 서버 | 내부 IP | 역할 |
|
╔═══════════════════════════════════════════════════════════════════════════╗
|
||||||
|------|---------|------|
|
║ 개발 (서버4) ║
|
||||||
| Server1 | 192.168.0.201 | NPM, PostgreSQL, Redis, 모니터링 |
|
╠═══════════════════════════════════════════════════════════════════════════╣
|
||||||
| Server2 | 192.168.0.202 | MongolCar (autonetsellcar.com) |
|
║ git status # 변경 파일 확인 ║
|
||||||
| Server3 | 192.168.0.203 | Grantech, Cylinx |
|
║ git add . # 스테이징 ║
|
||||||
| Server4 | 192.168.0.204 | Windows PC (파일 전송 중계) |
|
║ git commit -m "message" # 커밋 ║
|
||||||
|
║ git push staging main # 서버2로 푸시 ║
|
||||||
|
╚═══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
### 외부 접속
|
╔═══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ 운영 (서버2) ║
|
||||||
|
╠═══════════════════════════════════════════════════════════════════════════╣
|
||||||
|
║ docker ps # 실행 중인 컨테이너 확인 ║
|
||||||
|
║ docker logs autonet-frontend # 프론트엔드 로그 ║
|
||||||
|
║ docker logs autonet-backend # 백엔드 로그 ║
|
||||||
|
║ docker restart autonet-frontend # 프론트엔드 재시작 ║
|
||||||
|
║ docker restart autonet-backend # 백엔드 재시작 ║
|
||||||
|
╚═══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
| 포트 | 용도 |
|
╔═══════════════════════════════════════════════════════════════════════════╗
|
||||||
|------|------|
|
║ 배포 스크립트 ║
|
||||||
| 80, 443 | NPM (웹 서비스) |
|
╠═══════════════════════════════════════════════════════════════════════════╣
|
||||||
| 81 | NPM 관리 페이지 |
|
║ ./deploy.sh promote # 스테이징 → 운영 승격 ║
|
||||||
| 201, 202, 203 | SSH (각 서버) |
|
║ ./deploy.sh rollback # 직전 버전 롤백 ║
|
||||||
|
║ ./deploy.sh rollback-to <ts> # 특정 버전 롤백 ║
|
||||||
### 도메인
|
║ ./deploy.sh status # 현재 상태 확인 ║
|
||||||
|
╚═══════════════════════════════════════════════════════════════════════════╝
|
||||||
| 도메인 | 서비스 |
|
```
|
||||||
|--------|--------|
|
|
||||||
| autonetsellcar.com | MongolCar |
|
|
||||||
| grantech.kr | Grantech |
|
|
||||||
| api.grantech.kr | Grantech API |
|
|
||||||
| cylinx.kr | Cylinx (예정) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 버전 정보
|
## 9. 체크리스트
|
||||||
|
|
||||||
- Node.js: 20.x
|
```
|
||||||
- Python: 3.10
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
- Next.js: 16.x
|
│ 배포 전 체크리스트 │
|
||||||
- FastAPI: Latest
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
- Ubuntu: 22.04
|
|
||||||
|
배포 전:
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [ ] 로컬에서 테스트 완료 │
|
||||||
|
│ [ ] git status로 변경 파일 확인 │
|
||||||
|
│ [ ] 불필요한 파일 제외 (.env, node_modules 등) │
|
||||||
|
│ [ ] 커밋 메시지 작성 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
스테이징 테스트:
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [ ] Frontend 정상 작동 (http://192.168.0.202:3001) │
|
||||||
|
│ [ ] Backend API 정상 작동 (http://192.168.0.202:8001/docs) │
|
||||||
|
│ [ ] 주요 기능 테스트 완료 │
|
||||||
|
│ [ ] 에러 로그 확인 (docker logs) │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
운영 배포 후:
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [ ] 헬스체크 통과 │
|
||||||
|
│ [ ] 주요 페이지 접속 확인 │
|
||||||
|
│ [ ] API 응답 확인 │
|
||||||
|
│ [ ] 이전 버전 백업 확인 (/opt/autonet/releases/) │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*최종 업데이트: 2025-12-05*
|
## 10. 문제 해결
|
||||||
|
|
||||||
|
| 문제 | 해결 방법 |
|
||||||
|
|------|----------|
|
||||||
|
| 컨테이너 시작 안됨 | `docker logs <container>` 로그 확인 |
|
||||||
|
| 포트 충돌 | `netstat -tlnp \| grep <port>` 확인 후 프로세스 종료 |
|
||||||
|
| 이미지 빌드 실패 | `docker build --no-cache` 캐시 없이 재빌드 |
|
||||||
|
| DB 연결 오류 | Volume 마운트 확인, 파일 권한 확인 |
|
||||||
|
| API 404 오류 | Backend 컨테이너 재시작, 라우터 등록 확인 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**최종 업데이트**: 2024-12-30
|
||||||
|
|||||||
Reference in New Issue
Block a user