Merge pull request 'add/kubernetes' (#5) from add/kubernetes into main
All checks were successful
Deploy vexplor / build-and-deploy (push) Successful in 3m16s

Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
2025-12-28 09:20:53 +00:00
13 changed files with 946 additions and 79 deletions

4
.gitignore vendored
View File

@@ -291,4 +291,6 @@ uploads/
*.hwp
*.hwpx
claude.md
claude.md
.cursor/mcp.json

115
deploy/customers/README.md Normal file
View File

@@ -0,0 +1,115 @@
# 고객사별 환경 변수 관리
## 개요
이 폴더는 각 고객사(업체)별 환경 변수 설정을 **참고용**으로 관리합니다.
**중요:** 실제 비밀번호는 이 파일에 저장하지 마세요. 템플릿으로만 사용합니다.
---
## 고객사 목록
| 고객사 | 파일 | 배포 형태 | 상태 |
| :--- | :--- | :--- | :--- |
| 스피폭스 | `spifox.env` | 온프레미스 (공장 서버) | 진행 중 |
| 엔키드 | `enkid.env` | 온프레미스 (공장 서버) | 예정 |
---
## 신규 고객사 추가 절차
### 1단계: 환경 변수 파일 생성
```bash
# 기존 파일 복사
cp spifox.env newcustomer.env
# 수정
nano newcustomer.env
```
필수 수정 항목:
- `COMPANY_CODE`: 고유한 회사 코드 (예: NEWCO)
- `SERVER_IP`: 고객사 서버 IP
- `DB_PASSWORD`: 고유한 비밀번호
- `JWT_SECRET`: 고유한 시크릿 키
### 2단계: 데이터베이스에 회사 등록
```sql
-- company_info 테이블에 추가
INSERT INTO company_info (company_code, company_name, status)
VALUES ('NEWCO', '신규고객사', 'ACTIVE');
```
### 3단계: 관리자 계정 생성
```sql
-- user_info 테이블에 관리자 추가
INSERT INTO user_info (user_id, user_name, company_code, role)
VALUES ('newco_admin', '신규고객사 관리자', 'NEWCO', 'COMPANY_ADMIN');
```
### 4단계: 고객사 서버에 배포
```bash
# 고객사 서버에 SSH 접속
ssh user@customer-server
# 설치 폴더 생성
sudo mkdir -p /opt/vexplor
cd /opt/vexplor
# docker-compose.yml 복사 (deploy/onpremise/에서)
# .env 파일 복사 및 수정
# 서비스 시작
docker compose up -d
```
---
## 환경 변수 설명
| 변수 | 설명 | 예시 |
| :--- | :--- | :--- |
| `COMPANY_CODE` | 회사 고유 코드 (멀티테넌시) | `SPIFOX`, `ENKID` |
| `SERVER_IP` | 서버의 실제 IP | `192.168.0.100` |
| `DB_PASSWORD` | DB 비밀번호 | (고객사별 고유) |
| `JWT_SECRET` | JWT 토큰 시크릿 | (고객사별 고유) |
| `IMAGE_TAG` | Docker 이미지 버전 | `latest`, `v1.0.0` |
---
## 보안 주의사항
1. **비밀번호**: 이 폴더의 파일에는 실제 비밀번호를 저장하지 마세요
2. **Git**: `.env` 파일이 커밋되지 않도록 `.gitignore` 확인
3. **고객사별 격리**: 각 고객사는 별도 서버, 별도 DB로 완전 격리
4. **키 관리**: JWT_SECRET은 고객사별로 반드시 다르게 설정
---
## 구조 다이어그램
```
[Harbor (이미지 저장소)]
│ docker pull
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 스피폭스 공장 │ │ 엔키드 공장 │ │ 신규 고객사 │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ Vexplor │ │ │ │ Vexplor │ │ │ │ Vexplor │ │
│ │ SPIFOX │ │ │ │ ENKID │ │ │ │ NEWCO │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ │ │ │ │ │
│ [독립 DB] │ │ [독립 DB] │ │ [독립 DB] │
└─────────────────┘ └─────────────────┘ └─────────────────┘
* 각 공장은 완전히 독립적으로 운영
* 같은 Docker 이미지 사용, .env만 다름
* 데이터는 절대 섞이지 않음 (물리적 격리)
```

View File

@@ -0,0 +1,36 @@
# ============================================
# 엔키드(ENKID) 공장 서버 환경 변수
# ============================================
# 이 파일을 엔키드 공장 서버의 /opt/vexplor/.env로 복사
# 회사 정보
COMPANY_CODE=ENKID
# 서버 정보 (실제 서버 IP로 변경 필요)
SERVER_IP=10.0.0.50
# 데이터베이스
DB_USER=vexplor
DB_PASSWORD=enkid_secure_password_here
DB_NAME=vexplor
DB_PORT=5432
# 백엔드
BACKEND_PORT=3001
JWT_SECRET=enkid_jwt_secret_minimum_32_characters
JWT_EXPIRES_IN=24h
LOG_LEVEL=info
# 프론트엔드
FRONTEND_PORT=80
# Harbor 레지스트리
HARBOR_USER=enkid_harbor_user
HARBOR_PASSWORD=enkid_harbor_password
# 이미지 태그
IMAGE_TAG=latest
# Watchtower (1시간마다 업데이트 확인)
UPDATE_INTERVAL=3600

View File

@@ -0,0 +1,36 @@
# ============================================
# 스피폭스(SPIFOX) 공장 서버 환경 변수
# ============================================
# 이 파일을 스피폭스 공장 서버의 /opt/vexplor/.env로 복사
# 회사 정보
COMPANY_CODE=SPIFOX
# 서버 정보 (실제 서버 IP로 변경 필요)
SERVER_IP=192.168.0.100
# 데이터베이스
DB_USER=vexplor
DB_PASSWORD=spifox_secure_password_here
DB_NAME=vexplor
DB_PORT=5432
# 백엔드
BACKEND_PORT=3001
JWT_SECRET=spifox_jwt_secret_minimum_32_characters
JWT_EXPIRES_IN=24h
LOG_LEVEL=info
# 프론트엔드
FRONTEND_PORT=80
# Harbor 레지스트리
HARBOR_USER=spifox_harbor_user
HARBOR_PASSWORD=spifox_harbor_password
# 이미지 태그
IMAGE_TAG=latest
# Watchtower (1시간마다 업데이트 확인)
UPDATE_INTERVAL=3600

321
deploy/onpremise/README.md Normal file
View File

@@ -0,0 +1,321 @@
# Vexplor 온프레미스(공장) 배포 가이드
## 개요
이 가이드는 Vexplor를 **공장 내부 서버(온프레미스)**에 배포하는 방법을 설명합니다.
**Watchtower**를 사용하여 Harbor에 새 이미지가 푸시되면 **자동으로 업데이트**됩니다.
---
## 사전 요구사항
### 서버 요구사항
| 항목 | 최소 사양 | 권장 사양 |
| :--- | :--- | :--- |
| OS | Ubuntu 20.04+ | Ubuntu 22.04 LTS |
| CPU | 4 Core | 8 Core |
| RAM | 8 GB | 16 GB |
| Disk | 50 GB | 100 GB SSD |
| Network | Harbor 접근 가능 | - |
### 필수 소프트웨어
```bash
# Docker 설치 확인
docker --version # 20.10 이상
# Docker Compose 설치 확인
docker compose version # v2.0 이상
```
---
## 1단계: 초기 설정
### 1.1 배포 폴더 생성
```bash
# 배포 폴더 생성
sudo mkdir -p /opt/vexplor
cd /opt/vexplor
# 파일 복사 (또는 git clone)
# deploy/onpremise/ 폴더의 내용을 복사
```
### 1.2 환경 변수 설정
```bash
# 예제 파일 복사
cp env.example .env
# 편집
nano .env
```
**필수 수정 항목:**
```bash
# 서버 IP (이 서버의 실제 IP)
SERVER_IP=192.168.0.100
# 회사 코드
COMPANY_CODE=SPIFOX
# DB 비밀번호 (강력한 비밀번호 설정)
DB_PASSWORD=MySecurePassword123!
# JWT 시크릿 (32자 이상)
JWT_SECRET=your-super-secret-jwt-key-minimum-32-chars
# Harbor 인증 정보
HARBOR_USER=your_username
HARBOR_PASSWORD=your_password
```
### 1.3 Harbor 레지스트리 로그인
Watchtower가 이미지를 당겨올 수 있도록 Docker 로그인이 필요합니다.
```bash
# Harbor 로그인
docker login harbor.wace.me
# Username: (입력)
# Password: (입력)
# 로그인 성공 확인
cat ~/.docker/config.json
```
---
## 2단계: 서비스 실행
### 2.1 서비스 시작
```bash
cd /opt/vexplor
# 이미지 다운로드 & 실행
docker compose up -d
# 상태 확인
docker compose ps
```
### 2.2 정상 동작 확인
```bash
# 모든 컨테이너 Running 상태 확인
docker compose ps
# 로그 확인
docker compose logs -f
# 개별 서비스 로그
docker compose logs -f backend
docker compose logs -f frontend
docker compose logs -f watchtower
```
### 2.3 웹 접속 테스트
```
프론트엔드: http://SERVER_IP:80
백엔드 API: http://SERVER_IP:3001/health
```
---
## 3단계: 자동 업데이트 확인
### Watchtower 동작 확인
```bash
# Watchtower 로그 확인
docker compose logs -f watchtower
```
**정상 로그 예시:**
```
watchtower | time="2024-12-28T10:00:00+09:00" level=info msg="Checking for updates..."
watchtower | time="2024-12-28T10:00:05+09:00" level=info msg="Found new image harbor.wace.me/vexplor/vexplor-backend:latest"
watchtower | time="2024-12-28T10:00:10+09:00" level=info msg="Stopping container vexplor-backend"
watchtower | time="2024-12-28T10:00:15+09:00" level=info msg="Starting container vexplor-backend"
```
### 업데이트 주기 변경
```bash
# .env 파일에서 변경
UPDATE_INTERVAL=3600 # 1시간마다 확인
# 변경 후 watchtower 재시작
docker compose restart watchtower
```
---
## 운영 가이드
### 서비스 관리 명령어
```bash
# 모든 서비스 상태 확인
docker compose ps
# 모든 서비스 중지
docker compose stop
# 모든 서비스 시작
docker compose start
# 모든 서비스 재시작
docker compose restart
# 모든 서비스 삭제 (데이터 유지)
docker compose down
# 모든 서비스 삭제 + 볼륨 삭제 (주의: 데이터 삭제됨!)
docker compose down -v
```
### 로그 확인
```bash
# 전체 로그 (실시간)
docker compose logs -f
# 특정 서비스 로그
docker compose logs -f backend
docker compose logs -f frontend
docker compose logs -f database
# 최근 100줄만
docker compose logs --tail=100 backend
```
### 수동 업데이트 (긴급 시)
자동 업데이트를 기다리지 않고 즉시 업데이트하려면:
```bash
# 최신 이미지 다운로드
docker compose pull
# 재시작
docker compose up -d
```
### 특정 버전으로 롤백
```bash
# .env 파일에서 버전 지정
IMAGE_TAG=v1.0.0
# 재시작
docker compose up -d
```
---
## 백업 가이드
### DB 백업
```bash
# 백업 디렉토리 생성
mkdir -p /opt/vexplor/backups
# PostgreSQL 백업
docker compose exec database pg_dump -U vexplor vexplor > /opt/vexplor/backups/backup_$(date +%Y%m%d_%H%M%S).sql
```
### 업로드 파일 백업
```bash
# 볼륨 위치 확인
docker volume inspect vexplor_backend_uploads
# 또는 직접 복사
docker cp vexplor-backend:/app/uploads /opt/vexplor/backups/uploads_$(date +%Y%m%d)
```
### 자동 백업 스크립트 (Cron)
```bash
# crontab 편집
crontab -e
# 매일 새벽 3시 DB 백업
0 3 * * * docker compose -f /opt/vexplor/docker-compose.yml exec -T database pg_dump -U vexplor vexplor > /opt/vexplor/backups/backup_$(date +\%Y\%m\%d).sql
```
---
## 문제 해결
### 컨테이너가 시작되지 않음
```bash
# 로그 확인
docker compose logs backend
# 일반적인 원인:
# 1. 환경 변수 누락 → .env 파일 확인
# 2. 포트 충돌 → netstat -tlnp | grep 3001
# 3. 메모리 부족 → free -h
```
### DB 연결 실패
```bash
# DB 컨테이너 상태 확인
docker compose logs database
# DB 직접 접속 테스트
docker compose exec database psql -U vexplor -d vexplor -c "SELECT 1"
```
### Watchtower가 업데이트하지 않음
```bash
# Watchtower 로그 확인
docker compose logs watchtower
# Harbor 인증 확인
docker pull harbor.wace.me/vexplor/vexplor-backend:latest
# 라벨 확인 (라벨이 있는 컨테이너만 업데이트)
docker inspect vexplor-backend | grep watchtower
```
### 디스크 공간 부족
```bash
# 사용하지 않는 이미지/컨테이너 정리
docker system prune -a
# 오래된 로그 정리
docker compose logs --tail=0 backend # 로그 초기화
```
---
## 보안 권장사항
1. **방화벽 설정**: 필요한 포트(80, 3001)만 개방
2. **SSL/TLS**: Nginx 리버스 프록시 + Let's Encrypt 적용 권장
3. **정기 백업**: 최소 주 1회 DB 백업
4. **로그 모니터링**: 비정상 접근 감시
---
## 연락처
배포 관련 문의: [담당자 이메일]

View File

@@ -0,0 +1,155 @@
# Vexplor 온프레미스(공장) 배포용 Docker Compose
# 사용법: docker-compose up -d
version: '3.8'
services:
# ============================================
# 1. 데이터베이스 (PostgreSQL)
# ============================================
database:
image: postgres:15-alpine
container_name: vexplor-db
environment:
POSTGRES_USER: ${DB_USER:-vexplor}
POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: ${DB_NAME:-vexplor}
TZ: Asia/Seoul
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d # 초기화 스크립트 (선택)
ports:
- "${DB_PORT:-5432}:5432"
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-vexplor}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- vexplor-network
# ============================================
# 2. 백엔드 API (Node.js)
# ============================================
backend:
image: harbor.wace.me/vexplor/vexplor-backend:${IMAGE_TAG:-latest}
container_name: vexplor-backend
environment:
NODE_ENV: production
PORT: 3001
HOST: 0.0.0.0
TZ: Asia/Seoul
# DB 연결
DB_HOST: database
DB_PORT: 5432
DB_USER: ${DB_USER:-vexplor}
DB_PASSWORD: ${DB_PASSWORD}
DB_NAME: ${DB_NAME:-vexplor}
# JWT
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-24h}
# 회사 코드 (온프레미스는 단일 회사)
DEFAULT_COMPANY_CODE: ${COMPANY_CODE:-SPIFOX}
# 로깅
LOG_LEVEL: ${LOG_LEVEL:-info}
volumes:
- backend_uploads:/app/uploads
- backend_data:/app/data
- backend_logs:/app/logs
ports:
- "${BACKEND_PORT:-3001}:3001"
depends_on:
database:
condition: service_healthy
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- vexplor-network
labels:
- "com.centurylinklabs.watchtower.enable=true"
# ============================================
# 3. 프론트엔드 (Next.js)
# ============================================
frontend:
image: harbor.wace.me/vexplor/vexplor-frontend:${IMAGE_TAG:-latest}
container_name: vexplor-frontend
environment:
NODE_ENV: production
PORT: 3000
HOSTNAME: 0.0.0.0
TZ: Asia/Seoul
# 백엔드 API URL (내부 통신)
NEXT_PUBLIC_API_URL: http://${SERVER_IP:-localhost}:${BACKEND_PORT:-3001}/api
ports:
- "${FRONTEND_PORT:-80}:3000"
depends_on:
- backend
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- vexplor-network
labels:
- "com.centurylinklabs.watchtower.enable=true"
# ============================================
# 4. Watchtower (자동 업데이트)
# ============================================
watchtower:
image: containrrr/watchtower:latest
container_name: vexplor-watchtower
environment:
TZ: Asia/Seoul
# Harbor 레지스트리 인증
REPO_USER: ${HARBOR_USER}
REPO_PASS: ${HARBOR_PASSWORD}
# 업데이트 설정
WATCHTOWER_POLL_INTERVAL: ${UPDATE_INTERVAL:-300} # 5분마다 확인 (초 단위)
WATCHTOWER_CLEANUP: "true" # 이전 이미지 자동 삭제
WATCHTOWER_INCLUDE_STOPPED: "true" # 중지된 컨테이너도 업데이트
WATCHTOWER_ROLLING_RESTART: "true" # 순차 재시작 (다운타임 최소화)
WATCHTOWER_LABEL_ENABLE: "true" # 라벨이 있는 컨테이너만 업데이트
# 업데이트 시간 제한 (선택: 새벽 2-4시만 업데이트)
# WATCHTOWER_SCHEDULE: "0 0 2 * * *" # cron 형식 (매일 새벽 2시)
# 알림 설정 (선택)
# WATCHTOWER_NOTIFICATIONS: slack
# WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL: ${SLACK_WEBHOOK_URL}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Harbor 인증 정보 (docker login 후 생성됨)
- ~/.docker/config.json:/config.json:ro
restart: always
networks:
- vexplor-network
# ============================================
# 볼륨 정의
# ============================================
volumes:
postgres_data:
driver: local
backend_uploads:
driver: local
backend_data:
driver: local
backend_logs:
driver: local
# ============================================
# 네트워크 정의
# ============================================
networks:
vexplor-network:
driver: bridge

View File

@@ -0,0 +1,65 @@
# ============================================
# Vexplor 온프레미스(공장) 환경 변수
# ============================================
# 사용법: 이 파일을 .env로 복사 후 값 수정
# cp env.example .env
# ============================================
# 서버 정보
# ============================================
# 이 서버의 IP 주소 (프론트엔드가 백엔드 API 호출할 때 사용)
SERVER_IP=192.168.0.100
# ============================================
# 회사 정보
# ============================================
# 이 공장의 회사 코드 (멀티테넌시용)
COMPANY_CODE=SPIFOX
# ============================================
# 데이터베이스 설정
# ============================================
DB_USER=vexplor
DB_PASSWORD=your_secure_password_here
DB_NAME=vexplor
DB_PORT=5432
# ============================================
# 백엔드 설정
# ============================================
BACKEND_PORT=3001
JWT_SECRET=your_jwt_secret_key_minimum_32_characters
JWT_EXPIRES_IN=24h
LOG_LEVEL=info
# ============================================
# 프론트엔드 설정
# ============================================
FRONTEND_PORT=80
# ============================================
# Harbor 레지스트리 인증
# ============================================
# Watchtower가 이미지를 당겨올 때 사용
HARBOR_USER=your_harbor_username
HARBOR_PASSWORD=your_harbor_password
# ============================================
# 이미지 태그
# ============================================
# latest 또는 특정 버전 (v1.0.0 등)
IMAGE_TAG=latest
# ============================================
# Watchtower 설정
# ============================================
# 업데이트 확인 주기 (초 단위)
# 300 = 5분, 3600 = 1시간, 86400 = 24시간
UPDATE_INTERVAL=3600
# ============================================
# 알림 설정 (선택)
# ============================================
# Slack 웹훅 URL (업데이트 알림 받기)
# SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxx

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# ============================================
# Vexplor 백업 스크립트
# Cron에 등록하여 정기 백업 가능
# ============================================
set -e
INSTALL_DIR="/opt/vexplor"
BACKUP_DIR="/opt/vexplor/backups"
DATE=$(date +%Y%m%d_%H%M%S)
# 백업 디렉토리 생성
mkdir -p $BACKUP_DIR
echo "=========================================="
echo " Vexplor 백업 시작 - $DATE"
echo "=========================================="
cd $INSTALL_DIR
# 1. PostgreSQL 데이터베이스 백업
echo "[1/3] 데이터베이스 백업..."
docker compose exec -T database pg_dump -U vexplor vexplor > "$BACKUP_DIR/db_$DATE.sql"
gzip "$BACKUP_DIR/db_$DATE.sql"
echo "$BACKUP_DIR/db_$DATE.sql.gz"
# 2. 업로드 파일 백업
echo "[2/3] 업로드 파일 백업..."
docker cp vexplor-backend:/app/uploads "$BACKUP_DIR/uploads_$DATE" 2>/dev/null || echo " → 업로드 폴더 없음 (스킵)"
if [ -d "$BACKUP_DIR/uploads_$DATE" ]; then
tar -czf "$BACKUP_DIR/uploads_$DATE.tar.gz" -C "$BACKUP_DIR" "uploads_$DATE"
rm -rf "$BACKUP_DIR/uploads_$DATE"
echo "$BACKUP_DIR/uploads_$DATE.tar.gz"
fi
# 3. 환경 설정 백업
echo "[3/3] 환경 설정 백업..."
cp "$INSTALL_DIR/.env" "$BACKUP_DIR/env_$DATE"
cp "$INSTALL_DIR/docker-compose.yml" "$BACKUP_DIR/docker-compose_$DATE.yml"
echo "$BACKUP_DIR/env_$DATE"
echo "$BACKUP_DIR/docker-compose_$DATE.yml"
# 4. 오래된 백업 정리 (30일 이상)
echo ""
echo "[정리] 30일 이상 된 백업 삭제..."
find $BACKUP_DIR -type f -mtime +30 -delete 2>/dev/null || true
# 완료
echo ""
echo "=========================================="
echo " 백업 완료!"
echo "=========================================="
echo ""
echo "백업 위치: $BACKUP_DIR"
ls -lh $BACKUP_DIR | tail -10

View File

@@ -0,0 +1,79 @@
#!/bin/bash
# ============================================
# Vexplor 온프레미스 초기 설치 스크립트
# ============================================
set -e
echo "=========================================="
echo " Vexplor 온프레미스 설치 스크립트"
echo "=========================================="
# 색상 정의
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 설치 경로
INSTALL_DIR="/opt/vexplor"
# 1. Docker 설치 확인
echo -e "\n${YELLOW}[1/5] Docker 설치 확인...${NC}"
if ! command -v docker &> /dev/null; then
echo -e "${RED}Docker가 설치되어 있지 않습니다.${NC}"
echo "다음 명령어로 설치하세요:"
echo " curl -fsSL https://get.docker.com | sh"
echo " sudo usermod -aG docker \$USER"
exit 1
fi
echo -e "${GREEN}Docker $(docker --version | cut -d' ' -f3)${NC}"
# 2. Docker Compose 확인
echo -e "\n${YELLOW}[2/5] Docker Compose 확인...${NC}"
if ! docker compose version &> /dev/null; then
echo -e "${RED}Docker Compose v2가 설치되어 있지 않습니다.${NC}"
exit 1
fi
echo -e "${GREEN}$(docker compose version)${NC}"
# 3. 설치 디렉토리 생성
echo -e "\n${YELLOW}[3/5] 설치 디렉토리 생성...${NC}"
sudo mkdir -p $INSTALL_DIR
sudo chown $USER:$USER $INSTALL_DIR
echo -e "${GREEN}$INSTALL_DIR 생성 완료${NC}"
# 4. 파일 복사
echo -e "\n${YELLOW}[4/5] 설정 파일 복사...${NC}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cp "$SCRIPT_DIR/docker-compose.yml" "$INSTALL_DIR/"
cp "$SCRIPT_DIR/env.example" "$INSTALL_DIR/"
if [ ! -f "$INSTALL_DIR/.env" ]; then
cp "$SCRIPT_DIR/env.example" "$INSTALL_DIR/.env"
echo -e "${YELLOW}[주의] .env 파일을 생성했습니다. 반드시 수정하세요!${NC}"
fi
echo -e "${GREEN}파일 복사 완료${NC}"
# 5. Harbor 로그인 안내
echo -e "\n${YELLOW}[5/5] Harbor 레지스트리 로그인...${NC}"
if [ ! -f ~/.docker/config.json ] || ! grep -q "harbor.wace.me" ~/.docker/config.json 2>/dev/null; then
echo -e "${YELLOW}Harbor 로그인이 필요합니다:${NC}"
echo " docker login harbor.wace.me"
else
echo -e "${GREEN}Harbor 로그인 확인됨${NC}"
fi
# 완료 메시지
echo -e "\n=========================================="
echo -e "${GREEN} 설치 준비 완료!${NC}"
echo "=========================================="
echo ""
echo "다음 단계:"
echo " 1. 환경 변수 설정: nano $INSTALL_DIR/.env"
echo " 2. Harbor 로그인: docker login harbor.wace.me"
echo " 3. 서비스 시작: cd $INSTALL_DIR && docker compose up -d"
echo ""

View File

@@ -0,0 +1,41 @@
#!/bin/bash
# ============================================
# Vexplor 수동 업데이트 스크립트
# Watchtower를 기다리지 않고 즉시 업데이트할 때 사용
# ============================================
set -e
INSTALL_DIR="/opt/vexplor"
cd $INSTALL_DIR
echo "=========================================="
echo " Vexplor 수동 업데이트"
echo "=========================================="
# 1. 현재 상태 백업
echo "[1/4] 현재 설정 백업..."
docker compose config > "backup-config-$(date +%Y%m%d-%H%M%S).yml"
# 2. 최신 이미지 다운로드
echo "[2/4] 최신 이미지 다운로드..."
docker compose pull backend frontend
# 3. 서비스 재시작 (롤링 업데이트)
echo "[3/4] 서비스 재시작..."
docker compose up -d --no-deps backend
sleep 10 # 백엔드가 완전히 뜰 때까지 대기
docker compose up -d --no-deps frontend
# 4. 상태 확인
echo "[4/4] 상태 확인..."
sleep 5
docker compose ps
echo ""
echo "=========================================="
echo " 업데이트 완료!"
echo "=========================================="
echo ""
echo "로그 확인: docker compose logs -f"

View File

@@ -1,41 +0,0 @@
# Nginx Ingress Controller 설치
# 단일 노드 클러스터용 설정 (NodePort 사용)
#
# 설치 명령어:
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/baremetal/deploy.yaml
#
# 또는 이 파일로 커스텀 설치:
# kubectl apply -f k8s/ingress-nginx.yaml
# NodePort를 80, 443으로 고정하는 패치용 설정
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
spec:
type: NodePort
externalTrafficPolicy: Local
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv4
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
nodePort: 30080
- name: https
port: 443
protocol: TCP
targetPort: https
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller

View File

@@ -12,29 +12,29 @@
### 기존 서버 (참조용)
| 항목 | 값 |
|------|-----|
| IP | 211.115.91.170 |
| SSH 포트 | 12991 |
| 사용자 | geonhee |
| OS | Ubuntu 24.04.3 LTS |
| K8s 버전 | v1.28.0 |
| 컨테이너 런타임 | containerd 1.7.28 |
| 항목 | 값 |
| --------------- | ------------------ |
| IP | 211.115.91.170 |
| SSH 포트 | 12991 |
| 사용자 | geonhee |
| OS | Ubuntu 24.04.3 LTS |
| K8s 버전 | v1.28.0 |
| 컨테이너 런타임 | containerd 1.7.28 |
### 새 서버 (구축 완료)
| 항목 | 값 |
|------|-----|
| IP | 112.168.212.142 |
| SSH 포트 | 22 |
| 사용자 | wace |
| 호스트명 | waceserver |
| OS | Ubuntu 24.04.3 LTS |
| K8s 버전 | v1.28.15 |
| 컨테이너 런타임 | containerd 1.7.28 |
| 내부 IP | 10.10.0.74 |
| CPU | 20코어 |
| 메모리 | 31GB |
| 항목 | 값 |
| --------------- | ------------------ |
| IP | 112.168.212.142 |
| SSH 포트 | 22 |
| 사용자 | wace |
| 호스트명 | waceserver |
| OS | Ubuntu 24.04.3 LTS |
| K8s 버전 | v1.28.15 |
| 컨테이너 런타임 | containerd 1.7.28 |
| 내부 IP | 10.10.0.74 |
| CPU | 20코어 |
| 메모리 | 31GB |
---
@@ -112,6 +112,7 @@ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
```
**출력 결과 (중요 정보)**:
- 클러스터 초기화 성공
- API 서버: https://10.10.0.74:6443
- 워커 노드 조인 토큰 생성됨
@@ -155,9 +156,9 @@ kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl get nodes -o wide
```
| NAME | STATUS | ROLES | VERSION | INTERNAL-IP | OS-IMAGE | CONTAINER-RUNTIME |
|------|--------|-------|---------|-------------|----------|-------------------|
| waceserver | Ready | control-plane | v1.28.15 | 10.10.0.74 | Ubuntu 24.04.3 LTS | containerd://1.7.28 |
| NAME | STATUS | ROLES | VERSION | INTERNAL-IP | OS-IMAGE | CONTAINER-RUNTIME |
| ---------- | ------ | ------------- | -------- | ----------- | ------------------ | ------------------- |
| waceserver | Ready | control-plane | v1.28.15 | 10.10.0.74 | Ubuntu 24.04.3 LTS | containerd://1.7.28 |
### 시스템 Pod 상태
@@ -166,15 +167,15 @@ kubectl get pods -n kube-system
kubectl get pods -n kube-flannel
```
| 컴포넌트 | 상태 |
|---------|------|
| etcd | ✅ Running |
| kube-apiserver | ✅ Running |
| 컴포넌트 | 상태 |
| ----------------------- | ---------- |
| etcd | ✅ Running |
| kube-apiserver | ✅ Running |
| kube-controller-manager | ✅ Running |
| kube-scheduler | ✅ Running |
| kube-proxy | ✅ Running |
| coredns (x2) | ✅ Running |
| kube-flannel | ✅ Running |
| kube-scheduler | ✅ Running |
| kube-proxy | ✅ Running |
| coredns (x2) | ✅ Running |
| kube-flannel | ✅ Running |
---
@@ -188,6 +189,7 @@ kubeadm join 10.10.0.74:6443 --token 4lfga6.luad9f367uxh0rlq \
```
**토큰 만료 시 새 토큰 생성**:
```bash
kubeadm token create --print-join-command
```
@@ -271,11 +273,11 @@ k8s/
#### Gitea Repository Secrets 설정 필요
| Secret 이름 | 설명 |
|------------|------|
| `HARBOR_USERNAME` | Harbor 사용자명 |
| `HARBOR_PASSWORD` | Harbor 비밀번호 |
| `KUBECONFIG` | base64 인코딩된 Kubernetes config |
| Secret 이름 | 설명 |
| ------------------- | --------------------------------- |
| `HARBOR_USERNAME` | Harbor 사용자명 |
| `HARBOR_PASSWORD` | Harbor 비밀번호 |
| `KUBECONFIG` | base64 인코딩된 Kubernetes config |
```bash
# KUBECONFIG 생성 방법 (K8s 서버에서 실행)
@@ -301,4 +303,3 @@ ssh -p 12991 geonhee@211.115.91.170
- [Kubernetes 공식 문서](https://kubernetes.io/docs/)
- [kubeadm 설치 가이드](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/)
- [Flannel 네트워크 플러그인](https://github.com/flannel-io/flannel)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 KiB