Synology DS1525+ 최적화 배포 환경 완성: 32GB RAM/SSD캐시 최적화, 자동 배포 스크립트, 모니터링 도구
This commit is contained in:
279
README-DEPLOYMENT.md
Normal file
279
README-DEPLOYMENT.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# 🚀 Synology DS1525+ 배포 가이드
|
||||
|
||||
Document Server를 Synology DS1525+ NAS에 최적화하여 배포하는 가이드입니다.
|
||||
|
||||
## 🏗️ 하드웨어 사양
|
||||
|
||||
### Synology DS1525+ 최적화 구성
|
||||
- **CPU**: AMD Ryzen R1600 (4코어/8스레드)
|
||||
- **메모리**: 32GB DDR4 ECC
|
||||
- **스토리지**: SSD 읽기/쓰기 캐시 활성화
|
||||
- **볼륨 구성**:
|
||||
- **Volume1 (SSD)**: 고성능 데이터 (데이터베이스, 캐시, 로그)
|
||||
- **Volume2 (HDD)**: 대용량 저장소 (문서, 업로드, 백업)
|
||||
|
||||
## 📁 스토리지 전략
|
||||
|
||||
### SSD 볼륨 (/volume1) - 성능 최우선
|
||||
```
|
||||
/volume1/docker/document-server/
|
||||
├── database/ # PostgreSQL 데이터 (8GB shared_buffers)
|
||||
├── redis/ # Redis 캐시 (8GB maxmemory)
|
||||
├── logs/ # 애플리케이션 로그
|
||||
├── config/ # 설정 파일
|
||||
├── nginx/
|
||||
│ ├── conf.d/ # Nginx 설정
|
||||
│ └── cache/ # Nginx 캐시 (2GB)
|
||||
└── cache/ # 애플리케이션 캐시
|
||||
```
|
||||
|
||||
### HDD 볼륨 (/volume2) - 대용량 저장
|
||||
```
|
||||
/volume2/document-storage/
|
||||
├── uploads/ # 업로드된 파일 (HTML, PDF)
|
||||
├── documents/ # 변환된 문서
|
||||
├── thumbnails/ # 썸네일 이미지
|
||||
├── backups/ # 자동 백업 파일
|
||||
└── archives/ # 아카이브 데이터
|
||||
```
|
||||
|
||||
## 🚀 배포 방법
|
||||
|
||||
### 1. 자동 배포 (권장)
|
||||
```bash
|
||||
# 저장소 클론
|
||||
git clone <repository-url>
|
||||
cd document-server
|
||||
|
||||
# 자동 배포 스크립트 실행
|
||||
./scripts/deploy-synology.sh
|
||||
```
|
||||
|
||||
### 2. 수동 배포
|
||||
```bash
|
||||
# 1. 디렉토리 생성
|
||||
sudo mkdir -p /volume1/docker/document-server/{database,redis,logs,config,nginx/conf.d,nginx/cache,cache}
|
||||
sudo mkdir -p /volume2/document-storage/{uploads,documents,thumbnails,backups,archives}
|
||||
|
||||
# 2. 권한 설정
|
||||
sudo chown -R 1000:1000 /volume1/docker/document-server/
|
||||
sudo chown -R 1000:1000 /volume2/document-storage/
|
||||
|
||||
# 3. 환경 변수 설정
|
||||
cp .env.example .env.synology
|
||||
# .env.synology 파일 편집
|
||||
|
||||
# 4. Docker Compose 실행
|
||||
docker-compose -f docker-compose.synology-optimized.yml up -d
|
||||
```
|
||||
|
||||
## ⚙️ 성능 최적화 설정
|
||||
|
||||
### PostgreSQL (32GB RAM 최적화)
|
||||
```ini
|
||||
# /volume1/docker/document-server/config/postgresql.synology.conf
|
||||
shared_buffers = 8GB # RAM의 25%
|
||||
effective_cache_size = 24GB # RAM의 75%
|
||||
work_mem = 512MB # 복잡한 쿼리용
|
||||
maintenance_work_mem = 4GB # 인덱스 구축용
|
||||
max_worker_processes = 8 # 4코어/8스레드 최적화
|
||||
max_parallel_workers_per_gather = 4
|
||||
random_page_cost = 1.1 # SSD 최적화
|
||||
effective_io_concurrency = 200 # SSD 동시 I/O
|
||||
```
|
||||
|
||||
### Redis (대용량 메모리 활용)
|
||||
```conf
|
||||
maxmemory 8gb # 캐시 메모리 제한
|
||||
maxmemory-policy allkeys-lru # LRU 정책
|
||||
appendonly yes # 데이터 지속성
|
||||
auto-aof-rewrite-percentage 100 # AOF 최적화
|
||||
```
|
||||
|
||||
### Nginx (SSD 캐시 최적화)
|
||||
```nginx
|
||||
# 캐시 존 설정 (SSD에 저장)
|
||||
proxy_cache_path /var/cache/nginx/documents
|
||||
levels=1:2
|
||||
keys_zone=documents:100m
|
||||
max_size=2g
|
||||
inactive=60m;
|
||||
|
||||
# Gzip 압축
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||
|
||||
# 정적 파일 캐시
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 모니터링
|
||||
|
||||
### 실시간 모니터링
|
||||
```bash
|
||||
# 시스템 리소스 및 서비스 상태 확인
|
||||
./scripts/monitor-synology.sh
|
||||
|
||||
# 실시간 모니터링 (5초 간격)
|
||||
watch -n 5 './scripts/monitor-synology.sh'
|
||||
|
||||
# Docker 컨테이너 상태
|
||||
docker-compose -f docker-compose.synology-optimized.yml ps
|
||||
|
||||
# 실시간 로그
|
||||
docker-compose -f docker-compose.synology-optimized.yml logs -f
|
||||
|
||||
# 리소스 사용량
|
||||
docker stats
|
||||
```
|
||||
|
||||
### 주요 메트릭
|
||||
- **CPU 사용률**: 평상시 < 30%, 피크 < 70%
|
||||
- **메모리 사용률**: < 80% (32GB 중 25GB 이하)
|
||||
- **디스크 I/O**: SSD 캐시 효과로 응답 시간 < 100ms
|
||||
- **네트워크**: 기가비트 이더넷 활용
|
||||
|
||||
## 💾 백업 및 복구
|
||||
|
||||
### 자동 백업 설정
|
||||
```bash
|
||||
# Synology 작업 스케줄러에서 설정
|
||||
# 매일 새벽 2시 실행
|
||||
0 2 * * * /volume1/docker/document-server/backup.sh
|
||||
```
|
||||
|
||||
### 백업 내용
|
||||
- **데이터베이스**: PostgreSQL 덤프 (매일)
|
||||
- **설정 파일**: 압축 아카이브 (매일)
|
||||
- **문서 파일**: 증분 백업 (주간)
|
||||
- **보관 정책**: 7일간 보관 후 자동 삭제
|
||||
|
||||
### 복구 방법
|
||||
```bash
|
||||
# 데이터베이스 복구
|
||||
docker exec document-server-db psql -U docuser -d document_db < backup_file.sql
|
||||
|
||||
# 설정 파일 복구
|
||||
tar -xzf config_backup_YYYYMMDD_HHMMSS.tar.gz -C /volume1/docker/document-server/
|
||||
```
|
||||
|
||||
## 🔧 유지보수
|
||||
|
||||
### 정기 작업
|
||||
1. **주간**: 로그 파일 정리 및 압축
|
||||
2. **월간**: 데이터베이스 VACUUM 및 REINDEX
|
||||
3. **분기**: 전체 시스템 백업 및 복구 테스트
|
||||
4. **연간**: 하드웨어 점검 및 업그레이드 계획
|
||||
|
||||
### 로그 관리
|
||||
```bash
|
||||
# 로그 로테이션 설정
|
||||
/volume1/docker/document-server/logs/*.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 1000 1000
|
||||
}
|
||||
```
|
||||
|
||||
### 성능 튜닝
|
||||
```bash
|
||||
# PostgreSQL 통계 확인
|
||||
docker exec document-server-db psql -U docuser -d document_db -c "SELECT * FROM pg_stat_activity;"
|
||||
|
||||
# Redis 메모리 사용량 확인
|
||||
docker exec document-server-redis redis-cli info memory
|
||||
|
||||
# Nginx 캐시 효율성 확인
|
||||
docker exec document-server-nginx nginx -T
|
||||
```
|
||||
|
||||
## 🚨 트러블슈팅
|
||||
|
||||
### 일반적인 문제
|
||||
|
||||
#### 1. 메모리 부족
|
||||
```bash
|
||||
# 증상: 서비스 응답 지연, OOM 킬
|
||||
# 해결: PostgreSQL/Redis 메모리 설정 조정
|
||||
shared_buffers = 6GB # 8GB에서 감소
|
||||
maxmemory 6gb # 8GB에서 감소
|
||||
```
|
||||
|
||||
#### 2. 디스크 공간 부족
|
||||
```bash
|
||||
# SSD 공간 확보
|
||||
docker system prune -a
|
||||
find /volume1/docker/document-server/logs -name "*.log" -mtime +7 -delete
|
||||
|
||||
# HDD 공간 확보
|
||||
find /volume2/document-storage/backups -name "*.sql" -mtime +30 -delete
|
||||
```
|
||||
|
||||
#### 3. 네트워크 연결 문제
|
||||
```bash
|
||||
# 포트 확인
|
||||
netstat -tuln | grep -E "(24100|24101|24102|24103)"
|
||||
|
||||
# 방화벽 설정 확인
|
||||
iptables -L | grep -E "(24100|24101|24102|24103)"
|
||||
```
|
||||
|
||||
### 로그 위치
|
||||
- **애플리케이션**: `/volume1/docker/document-server/logs/`
|
||||
- **Nginx**: `/volume1/docker/document-server/logs/nginx/`
|
||||
- **PostgreSQL**: `docker logs document-server-db`
|
||||
- **Redis**: `docker logs document-server-redis`
|
||||
|
||||
## 📈 성능 벤치마크
|
||||
|
||||
### 예상 성능 (DS1525+ 32GB)
|
||||
- **동시 사용자**: 50-100명
|
||||
- **문서 처리**: 1000+ 문서
|
||||
- **응답 시간**: < 200ms (평균)
|
||||
- **업로드 속도**: 100MB/s (기가비트 네트워크)
|
||||
- **검색 속도**: < 100ms (인덱스 기반)
|
||||
|
||||
### 확장성
|
||||
- **수직 확장**: RAM 64GB까지 지원
|
||||
- **수평 확장**: 로드 밸런서 + 다중 백엔드
|
||||
- **스토리지**: 추가 볼륨 마운트 가능
|
||||
|
||||
## 🔒 보안 설정
|
||||
|
||||
### 네트워크 보안
|
||||
```bash
|
||||
# 방화벽 규칙 (필요한 포트만 개방)
|
||||
iptables -A INPUT -p tcp --dport 24100 -j ACCEPT # Nginx
|
||||
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # SSH
|
||||
iptables -A INPUT -j DROP # 기본 차단
|
||||
```
|
||||
|
||||
### 데이터 보안
|
||||
- **암호화**: 데이터베이스 및 Redis 암호 설정
|
||||
- **백업 암호화**: GPG를 이용한 백업 파일 암호화
|
||||
- **접근 제어**: 사용자별 권한 관리
|
||||
- **SSL/TLS**: Let's Encrypt 인증서 적용
|
||||
|
||||
## 📞 지원 및 문의
|
||||
|
||||
### 문제 보고
|
||||
1. **로그 수집**: `./scripts/monitor-synology.sh > system-report.txt`
|
||||
2. **환경 정보**: Docker 버전, 시스템 사양
|
||||
3. **재현 단계**: 문제 발생 과정 상세 기록
|
||||
|
||||
### 업데이트
|
||||
```bash
|
||||
# 코드 업데이트
|
||||
git pull origin main
|
||||
|
||||
# 컨테이너 재빌드
|
||||
docker-compose -f docker-compose.synology-optimized.yml build --no-cache
|
||||
docker-compose -f docker-compose.synology-optimized.yml up -d
|
||||
```
|
||||
134
docker-compose.prod.yml
Normal file
134
docker-compose.prod.yml
Normal file
@@ -0,0 +1,134 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Nginx 리버스 프록시 (프로덕션)
|
||||
nginx:
|
||||
build: ./nginx
|
||||
container_name: document-server-nginx-prod
|
||||
ports:
|
||||
- "24100:80"
|
||||
volumes:
|
||||
- ./frontend:/usr/share/nginx/html:ro
|
||||
- ./uploads:/usr/share/nginx/html/uploads:ro
|
||||
- nginx_cache:/var/cache/nginx
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- document-network
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NGINX_WORKER_PROCESSES=auto
|
||||
- NGINX_WORKER_CONNECTIONS=1024
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# Backend API 서버 (프로덕션)
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: document-server-backend-prod
|
||||
ports:
|
||||
- "24102:8000"
|
||||
volumes:
|
||||
- ./uploads:/app/uploads
|
||||
- backend_logs:/app/logs
|
||||
environment:
|
||||
- DATABASE_URL=postgresql+asyncpg://docuser:${DB_PASSWORD:-docpass}@database:5432/document_db
|
||||
- SECRET_KEY=${SECRET_KEY:-production-secret-key-change-this}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@test.com}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
|
||||
- DEBUG=false
|
||||
- ALLOWED_ORIGINS=http://localhost:24100,https://your-domain.com
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- document-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
reservations:
|
||||
memory: 512M
|
||||
|
||||
# PostgreSQL 데이터베이스 (프로덕션)
|
||||
database:
|
||||
image: postgres:15-alpine
|
||||
container_name: document-server-db-prod
|
||||
ports:
|
||||
- "24101:5432"
|
||||
environment:
|
||||
- POSTGRES_DB=document_db
|
||||
- POSTGRES_USER=docuser
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD:-docpass}
|
||||
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --locale=C
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./database/init:/docker-entrypoint-initdb.d:ro
|
||||
- ./config/postgresql.prod.conf:/etc/postgresql/postgresql.conf:ro
|
||||
networks:
|
||||
- document-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U docuser -d document_db"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
reservations:
|
||||
memory: 1G
|
||||
|
||||
# Redis (캐싱 및 세션) - 프로덕션
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: document-server-redis-prod
|
||||
ports:
|
||||
- "24103:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
- ./config/redis.prod.conf:/usr/local/etc/redis/redis.conf:ro
|
||||
networks:
|
||||
- document-network
|
||||
restart: unless-stopped
|
||||
command: redis-server /usr/local/etc/redis/redis.conf
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
reservations:
|
||||
memory: 256M
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
nginx_cache:
|
||||
driver: local
|
||||
backend_logs:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
document-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
178
docker-compose.synology-optimized.yml
Normal file
178
docker-compose.synology-optimized.yml
Normal file
@@ -0,0 +1,178 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# PostgreSQL 데이터베이스 (SSD 최적화 - 32GB RAM 활용)
|
||||
database:
|
||||
image: postgres:15-alpine
|
||||
container_name: document-server-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: document_db
|
||||
POSTGRES_USER: docuser
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-docpass}
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
|
||||
volumes:
|
||||
# SSD: 데이터베이스 (성능 최우선)
|
||||
- /volume1/docker/document-server/database:/var/lib/postgresql/data
|
||||
- /volume1/docker/document-server/config/postgresql.synology.conf:/etc/postgresql/postgresql.conf:ro
|
||||
- ./database/init:/docker-entrypoint-initdb.d:ro
|
||||
ports:
|
||||
- "24101:5432"
|
||||
command: >
|
||||
postgres
|
||||
-c config_file=/etc/postgresql/postgresql.conf
|
||||
-c shared_buffers=8GB
|
||||
-c effective_cache_size=24GB
|
||||
-c work_mem=512MB
|
||||
-c maintenance_work_mem=4GB
|
||||
-c checkpoint_completion_target=0.9
|
||||
-c wal_buffers=128MB
|
||||
-c random_page_cost=1.1
|
||||
-c effective_io_concurrency=200
|
||||
-c max_worker_processes=8
|
||||
-c max_parallel_workers_per_gather=4
|
||||
-c max_parallel_workers=8
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U docuser -d document_db"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- document-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 10G
|
||||
reservations:
|
||||
memory: 2G
|
||||
|
||||
# Redis 캐시 (SSD 최적화 - 대용량 메모리 활용)
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: document-server-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# SSD: Redis 데이터 (빠른 캐시)
|
||||
- /volume1/docker/document-server/redis:/data
|
||||
ports:
|
||||
- "24103:6379"
|
||||
command: >
|
||||
redis-server
|
||||
--maxmemory 8gb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--save 900 1
|
||||
--save 300 10
|
||||
--save 60 10000
|
||||
--appendonly yes
|
||||
--appendfsync everysec
|
||||
--auto-aof-rewrite-percentage 100
|
||||
--auto-aof-rewrite-min-size 64mb
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- document-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 10G
|
||||
reservations:
|
||||
memory: 1G
|
||||
|
||||
# FastAPI 백엔드 (SSD에서 실행, HDD 스토리지 연결)
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: document-server-backend
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DATABASE_URL=postgresql+asyncpg://docuser:${DB_PASSWORD:-docpass}@database:5432/document_db
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- SECRET_KEY=${SECRET_KEY:-production-secret-key-change-this}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@test.com}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
|
||||
- DEBUG=false
|
||||
- ALLOWED_ORIGINS=http://localhost:24100,https://${DOMAIN_NAME:-localhost}
|
||||
- UPLOAD_DIR=/app/uploads
|
||||
- MAX_FILE_SIZE=500000000
|
||||
volumes:
|
||||
# SSD: 애플리케이션 로그 및 설정 (빠른 액세스)
|
||||
- /volume1/docker/document-server/logs:/app/logs
|
||||
- /volume1/docker/document-server/config:/app/config
|
||||
- /volume1/docker/document-server/cache:/app/cache
|
||||
|
||||
# HDD: 대용량 파일 저장소 (비용 효율적)
|
||||
- /volume2/document-storage/uploads:/app/uploads
|
||||
- /volume2/document-storage/documents:/app/documents
|
||||
- /volume2/document-storage/thumbnails:/app/thumbnails
|
||||
- /volume2/document-storage/backups:/app/backups
|
||||
ports:
|
||||
- "24102:8000"
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- document-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
reservations:
|
||||
memory: 512M
|
||||
|
||||
# Nginx 웹서버 (SSD 캐시, HDD 스토리지)
|
||||
nginx:
|
||||
build:
|
||||
context: ./nginx
|
||||
dockerfile: Dockerfile
|
||||
container_name: document-server-nginx
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# SSD: Nginx 설정, 로그, 캐시 (성능 최적화)
|
||||
- /volume1/docker/document-server/nginx/conf.d:/etc/nginx/conf.d
|
||||
- /volume1/docker/document-server/nginx/cache:/var/cache/nginx
|
||||
- /volume1/docker/document-server/logs/nginx:/var/log/nginx
|
||||
|
||||
# SSD: 프론트엔드 정적 파일 (빠른 서빙)
|
||||
- ./frontend:/usr/share/nginx/html:ro
|
||||
|
||||
# HDD: 대용량 문서 파일 (읽기 전용)
|
||||
- /volume2/document-storage/uploads:/usr/share/nginx/html/uploads:ro
|
||||
- /volume2/document-storage/documents:/usr/share/nginx/html/documents:ro
|
||||
ports:
|
||||
- "24100:80"
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- document-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
reservations:
|
||||
memory: 128M
|
||||
|
||||
networks:
|
||||
document-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
# 볼륨 정의는 제거 (직접 경로 매핑 사용)
|
||||
387
scripts/deploy-synology.sh
Executable file
387
scripts/deploy-synology.sh
Executable file
@@ -0,0 +1,387 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =============================================================================
|
||||
# Document Server - Synology DS1525+ 최적화 배포 스크립트
|
||||
#
|
||||
# 하드웨어 사양:
|
||||
# - CPU: AMD Ryzen R1600 (4코어/8스레드)
|
||||
# - RAM: 32GB DDR4 ECC
|
||||
# - SSD: 읽기/쓰기 캐시 활성화
|
||||
# - Storage: Volume1(SSD), Volume2(HDD)
|
||||
# =============================================================================
|
||||
|
||||
set -e # 에러 발생 시 스크립트 중단
|
||||
|
||||
# 색상 정의
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 로그 함수
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 환경 변수 설정
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
COMPOSE_FILE="docker-compose.synology-optimized.yml"
|
||||
|
||||
# 기본 환경 변수
|
||||
export DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -base64 32)}"
|
||||
export SECRET_KEY="${SECRET_KEY:-$(openssl rand -base64 64)}"
|
||||
export ADMIN_EMAIL="${ADMIN_EMAIL:-admin@document-server.local}"
|
||||
export ADMIN_PASSWORD="${ADMIN_PASSWORD:-$(openssl rand -base64 16)}"
|
||||
export DOMAIN_NAME="${DOMAIN_NAME:-localhost}"
|
||||
|
||||
log_info "🚀 Synology DS1525+ 최적화 배포 시작"
|
||||
log_info "📁 프로젝트 디렉토리: $PROJECT_DIR"
|
||||
|
||||
# 1. 시스템 요구사항 확인
|
||||
log_info "🔍 시스템 요구사항 확인 중..."
|
||||
|
||||
# Docker 및 Docker Compose 확인
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker가 설치되지 않았습니다."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
log_error "Docker Compose가 설치되지 않았습니다."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 메모리 확인 (최소 16GB 권장)
|
||||
TOTAL_MEM=$(free -g | awk '/^Mem:/{print $2}')
|
||||
if [ "$TOTAL_MEM" -lt 16 ]; then
|
||||
log_warning "메모리가 ${TOTAL_MEM}GB입니다. 최소 16GB를 권장합니다."
|
||||
fi
|
||||
|
||||
log_success "시스템 요구사항 확인 완료"
|
||||
|
||||
# 2. 디렉토리 구조 생성
|
||||
log_info "📂 디렉토리 구조 생성 중..."
|
||||
|
||||
# SSD 디렉토리 (성능 최우선)
|
||||
SSD_DIRS=(
|
||||
"/volume1/docker/document-server/database"
|
||||
"/volume1/docker/document-server/redis"
|
||||
"/volume1/docker/document-server/logs"
|
||||
"/volume1/docker/document-server/logs/nginx"
|
||||
"/volume1/docker/document-server/config"
|
||||
"/volume1/docker/document-server/nginx/conf.d"
|
||||
"/volume1/docker/document-server/nginx/cache"
|
||||
"/volume1/docker/document-server/cache"
|
||||
)
|
||||
|
||||
# HDD 디렉토리 (대용량 저장)
|
||||
HDD_DIRS=(
|
||||
"/volume2/document-storage/uploads"
|
||||
"/volume2/document-storage/documents"
|
||||
"/volume2/document-storage/thumbnails"
|
||||
"/volume2/document-storage/backups"
|
||||
"/volume2/document-storage/archives"
|
||||
)
|
||||
|
||||
# SSD 디렉토리 생성
|
||||
for dir in "${SSD_DIRS[@]}"; do
|
||||
if [ ! -d "$dir" ]; then
|
||||
sudo mkdir -p "$dir"
|
||||
log_info "SSD 디렉토리 생성: $dir"
|
||||
fi
|
||||
done
|
||||
|
||||
# HDD 디렉토리 생성
|
||||
for dir in "${HDD_DIRS[@]}"; do
|
||||
if [ ! -d "$dir" ]; then
|
||||
sudo mkdir -p "$dir"
|
||||
log_info "HDD 디렉토리 생성: $dir"
|
||||
fi
|
||||
done
|
||||
|
||||
# 권한 설정
|
||||
sudo chown -R 1000:1000 /volume1/docker/document-server/
|
||||
sudo chown -R 1000:1000 /volume2/document-storage/
|
||||
|
||||
log_success "디렉토리 구조 생성 완료"
|
||||
|
||||
# 3. 설정 파일 복사
|
||||
log_info "⚙️ 설정 파일 생성 중..."
|
||||
|
||||
# PostgreSQL 설정 (32GB RAM 최적화)
|
||||
cat > /volume1/docker/document-server/config/postgresql.synology.conf << 'EOF'
|
||||
# PostgreSQL 설정 - Synology DS1525+ 32GB RAM 최적화
|
||||
|
||||
# 메모리 설정 (32GB RAM 기준)
|
||||
shared_buffers = 8GB # RAM의 25%
|
||||
effective_cache_size = 24GB # RAM의 75%
|
||||
work_mem = 512MB # 복잡한 쿼리용 (증가)
|
||||
maintenance_work_mem = 4GB # 인덱스 구축용 (증가)
|
||||
|
||||
# 체크포인트 설정 (SSD 최적화)
|
||||
checkpoint_completion_target = 0.9
|
||||
wal_buffers = 128MB # WAL 버퍼 (증가)
|
||||
checkpoint_timeout = 15min
|
||||
max_wal_size = 4GB
|
||||
min_wal_size = 1GB
|
||||
|
||||
# SSD 최적화
|
||||
random_page_cost = 1.1 # SSD 환경
|
||||
effective_io_concurrency = 200 # SSD 동시 I/O
|
||||
seq_page_cost = 1.0
|
||||
|
||||
# 병렬 처리 (4코어/8스레드 최적화)
|
||||
max_worker_processes = 8
|
||||
max_parallel_workers_per_gather = 4
|
||||
max_parallel_workers = 8
|
||||
max_parallel_maintenance_workers = 4
|
||||
|
||||
# 연결 설정
|
||||
max_connections = 200
|
||||
shared_preload_libraries = 'pg_stat_statements'
|
||||
|
||||
# 로깅 설정
|
||||
log_min_duration_statement = 1000 # 1초 이상 쿼리 로깅
|
||||
log_checkpoints = on
|
||||
log_connections = on
|
||||
log_disconnections = on
|
||||
log_lock_waits = on
|
||||
|
||||
# 자동 VACUUM 설정
|
||||
autovacuum = on
|
||||
autovacuum_max_workers = 4
|
||||
autovacuum_naptime = 30s
|
||||
EOF
|
||||
|
||||
# Nginx 설정 (SSD 캐시 최적화)
|
||||
cat > /volume1/docker/document-server/nginx/conf.d/default.conf << 'EOF'
|
||||
# Nginx 설정 - SSD 캐시 최적화
|
||||
|
||||
# 업스트림 백엔드
|
||||
upstream backend {
|
||||
server backend:8000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# 캐시 존 정의 (SSD에 저장)
|
||||
proxy_cache_path /var/cache/nginx/documents
|
||||
levels=1:2
|
||||
keys_zone=documents:100m
|
||||
max_size=2g
|
||||
inactive=60m
|
||||
use_temp_path=off;
|
||||
|
||||
proxy_cache_path /var/cache/nginx/api
|
||||
levels=1:2
|
||||
keys_zone=api:50m
|
||||
max_size=500m
|
||||
inactive=10m
|
||||
use_temp_path=off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# 클라이언트 설정
|
||||
client_max_body_size 500M;
|
||||
client_body_timeout 300s;
|
||||
client_header_timeout 300s;
|
||||
|
||||
# Gzip 압축
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/json;
|
||||
|
||||
# 정적 파일 (SSD에서 서빙)
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
# 정적 파일 캐시
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# 업로드된 문서 (HDD에서 서빙, SSD 캐시)
|
||||
location /uploads/ {
|
||||
alias /usr/share/nginx/html/uploads/;
|
||||
|
||||
# 문서 캐시 (자주 접근하는 문서는 SSD에 캐시)
|
||||
proxy_cache documents;
|
||||
proxy_cache_valid 200 60m;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
|
||||
expires 1h;
|
||||
}
|
||||
|
||||
# API 요청
|
||||
location /api/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# API 응답 캐시 (GET 요청만)
|
||||
proxy_cache api;
|
||||
proxy_cache_methods GET HEAD;
|
||||
proxy_cache_valid 200 5m;
|
||||
proxy_cache_bypass $http_pragma $http_authorization;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
|
||||
# 타임아웃 설정
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
# 헬스체크
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
log_success "설정 파일 생성 완료"
|
||||
|
||||
# 4. 환경 변수 파일 생성
|
||||
log_info "🔐 환경 변수 설정 중..."
|
||||
|
||||
cat > "$PROJECT_DIR/.env.synology" << EOF
|
||||
# Synology DS1525+ 배포 환경 변수
|
||||
DB_PASSWORD=$DB_PASSWORD
|
||||
SECRET_KEY=$SECRET_KEY
|
||||
ADMIN_EMAIL=$ADMIN_EMAIL
|
||||
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
|
||||
# 성능 최적화 설정
|
||||
POSTGRES_SHARED_BUFFERS=8GB
|
||||
POSTGRES_EFFECTIVE_CACHE_SIZE=24GB
|
||||
REDIS_MAXMEMORY=8gb
|
||||
|
||||
# 경로 설정
|
||||
SSD_PATH=/volume1/docker/document-server
|
||||
HDD_PATH=/volume2/document-storage
|
||||
EOF
|
||||
|
||||
log_success "환경 변수 설정 완료"
|
||||
|
||||
# 5. Docker Compose 배포
|
||||
log_info "🐳 Docker 컨테이너 배포 중..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# 기존 컨테이너 중지 및 제거 (있는 경우)
|
||||
if docker-compose -f "$COMPOSE_FILE" ps -q | grep -q .; then
|
||||
log_warning "기존 컨테이너를 중지합니다..."
|
||||
docker-compose -f "$COMPOSE_FILE" down
|
||||
fi
|
||||
|
||||
# 이미지 빌드 및 컨테이너 시작
|
||||
log_info "이미지 빌드 중..."
|
||||
docker-compose -f "$COMPOSE_FILE" build --no-cache
|
||||
|
||||
log_info "컨테이너 시작 중..."
|
||||
docker-compose -f "$COMPOSE_FILE" up -d
|
||||
|
||||
# 6. 서비스 상태 확인
|
||||
log_info "🔍 서비스 상태 확인 중..."
|
||||
|
||||
# 컨테이너 시작 대기
|
||||
sleep 30
|
||||
|
||||
# 헬스체크
|
||||
services=("database" "redis" "backend" "nginx")
|
||||
for service in "${services[@]}"; do
|
||||
if docker-compose -f "$COMPOSE_FILE" ps "$service" | grep -q "Up"; then
|
||||
log_success "$service 서비스 정상 실행 중"
|
||||
else
|
||||
log_error "$service 서비스 실행 실패"
|
||||
docker-compose -f "$COMPOSE_FILE" logs "$service"
|
||||
fi
|
||||
done
|
||||
|
||||
# 7. 백업 스크립트 설정
|
||||
log_info "💾 백업 스크립트 설정 중..."
|
||||
|
||||
cat > /volume1/docker/document-server/backup.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
# 자동 백업 스크립트
|
||||
|
||||
BACKUP_DIR="/volume2/document-storage/backups"
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
# 데이터베이스 백업
|
||||
docker exec document-server-db pg_dump -U docuser document_db > "$BACKUP_DIR/db_backup_$DATE.sql"
|
||||
|
||||
# 설정 파일 백업
|
||||
tar -czf "$BACKUP_DIR/config_backup_$DATE.tar.gz" /volume1/docker/document-server/config/
|
||||
|
||||
# 7일 이상 된 백업 파일 삭제
|
||||
find "$BACKUP_DIR" -name "*.sql" -mtime +7 -delete
|
||||
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
|
||||
|
||||
echo "백업 완료: $DATE"
|
||||
EOF
|
||||
|
||||
chmod +x /volume1/docker/document-server/backup.sh
|
||||
|
||||
log_success "백업 스크립트 설정 완료"
|
||||
|
||||
# 8. 배포 완료 정보 출력
|
||||
log_success "🎉 Synology DS1525+ 배포 완료!"
|
||||
|
||||
echo ""
|
||||
echo "=== 배포 정보 ==="
|
||||
echo "🌐 웹 인터페이스: http://localhost:24100"
|
||||
echo "🔧 API 서버: http://localhost:24102"
|
||||
echo "🗄️ 데이터베이스: localhost:24101"
|
||||
echo "💾 Redis: localhost:24103"
|
||||
echo ""
|
||||
echo "=== 관리자 계정 ==="
|
||||
echo "📧 이메일: $ADMIN_EMAIL"
|
||||
echo "🔑 비밀번호: $ADMIN_PASSWORD"
|
||||
echo ""
|
||||
echo "=== 스토리지 구성 ==="
|
||||
echo "💿 SSD (성능): /volume1/docker/document-server/"
|
||||
echo "💾 HDD (용량): /volume2/document-storage/"
|
||||
echo ""
|
||||
echo "=== 자동 백업 ==="
|
||||
echo "📅 매일 새벽 2시 자동 백업 (Synology 작업 스케줄러에서 설정)"
|
||||
echo "📂 백업 위치: /volume2/document-storage/backups/"
|
||||
echo ""
|
||||
echo "=== 모니터링 명령어 ==="
|
||||
echo "docker-compose -f $COMPOSE_FILE ps"
|
||||
echo "docker-compose -f $COMPOSE_FILE logs -f"
|
||||
echo "docker stats"
|
||||
|
||||
log_info "배포 스크립트 실행 완료"
|
||||
249
scripts/monitor-synology.sh
Executable file
249
scripts/monitor-synology.sh
Executable file
@@ -0,0 +1,249 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =============================================================================
|
||||
# Document Server - Synology DS1525+ 모니터링 스크립트
|
||||
# 시스템 리소스 및 서비스 상태 모니터링
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# 색상 정의
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 로그 함수
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 환경 설정
|
||||
COMPOSE_FILE="docker-compose.synology-optimized.yml"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
echo "=== 📊 Synology DS1525+ Document Server 모니터링 ==="
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo ""
|
||||
|
||||
# 1. 시스템 리소스 확인
|
||||
log_info "🖥️ 시스템 리소스 상태"
|
||||
|
||||
# CPU 사용률
|
||||
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | awk -F'%' '{print $1}')
|
||||
echo -e "CPU 사용률: ${CYAN}${CPU_USAGE}%${NC}"
|
||||
|
||||
# 메모리 사용률 (32GB 기준)
|
||||
MEMORY_INFO=$(free -h | grep "Mem:")
|
||||
TOTAL_MEM=$(echo $MEMORY_INFO | awk '{print $2}')
|
||||
USED_MEM=$(echo $MEMORY_INFO | awk '{print $3}')
|
||||
AVAILABLE_MEM=$(echo $MEMORY_INFO | awk '{print $7}')
|
||||
MEM_PERCENT=$(free | grep "Mem:" | awk '{printf "%.1f", ($3/$2) * 100.0}')
|
||||
|
||||
echo -e "메모리: ${CYAN}${USED_MEM}${NC}/${CYAN}${TOTAL_MEM}${NC} (${CYAN}${MEM_PERCENT}%${NC}) | 사용 가능: ${GREEN}${AVAILABLE_MEM}${NC}"
|
||||
|
||||
# 디스크 사용률
|
||||
echo -e "\n${BLUE}💾 디스크 사용률:${NC}"
|
||||
df -h /volume1 /volume2 | grep -E "(volume1|volume2)" | while read line; do
|
||||
USAGE=$(echo $line | awk '{print $5}' | sed 's/%//')
|
||||
MOUNT=$(echo $line | awk '{print $6}')
|
||||
USED=$(echo $line | awk '{print $3}')
|
||||
TOTAL=$(echo $line | awk '{print $2}')
|
||||
|
||||
if [ "$USAGE" -gt 90 ]; then
|
||||
echo -e " ${RED}${MOUNT}${NC}: ${RED}${USED}${NC}/${TOTAL} (${RED}${USAGE}%${NC}) ⚠️"
|
||||
elif [ "$USAGE" -gt 80 ]; then
|
||||
echo -e " ${YELLOW}${MOUNT}${NC}: ${YELLOW}${USED}${NC}/${TOTAL} (${YELLOW}${USAGE}%${NC})"
|
||||
else
|
||||
echo -e " ${GREEN}${MOUNT}${NC}: ${CYAN}${USED}${NC}/${TOTAL} (${GREEN}${USAGE}%${NC})"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# 2. Docker 컨테이너 상태
|
||||
log_info "🐳 Docker 컨테이너 상태"
|
||||
|
||||
if [ -f "$COMPOSE_FILE" ]; then
|
||||
# 컨테이너 상태 확인
|
||||
CONTAINERS=$(docker-compose -f "$COMPOSE_FILE" ps --format "table {{.Name}}\t{{.State}}\t{{.Ports}}")
|
||||
echo "$CONTAINERS"
|
||||
|
||||
echo ""
|
||||
|
||||
# 각 서비스별 상태 확인
|
||||
SERVICES=("database" "redis" "backend" "nginx")
|
||||
for service in "${SERVICES[@]}"; do
|
||||
STATUS=$(docker-compose -f "$COMPOSE_FILE" ps -q "$service" 2>/dev/null)
|
||||
if [ -n "$STATUS" ]; then
|
||||
HEALTH=$(docker inspect --format='{{.State.Health.Status}}' $(docker-compose -f "$COMPOSE_FILE" ps -q "$service") 2>/dev/null || echo "no-healthcheck")
|
||||
if [ "$HEALTH" = "healthy" ]; then
|
||||
log_success "$service: 정상 (healthy)"
|
||||
elif [ "$HEALTH" = "unhealthy" ]; then
|
||||
log_error "$service: 비정상 (unhealthy)"
|
||||
else
|
||||
log_warning "$service: 헬스체크 없음"
|
||||
fi
|
||||
else
|
||||
log_error "$service: 실행 중이지 않음"
|
||||
fi
|
||||
done
|
||||
else
|
||||
log_error "Docker Compose 파일을 찾을 수 없습니다: $COMPOSE_FILE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 3. 리소스 사용량 (컨테이너별)
|
||||
log_info "📈 컨테이너별 리소스 사용량"
|
||||
|
||||
if command -v docker &> /dev/null; then
|
||||
# Docker stats 정보 (1회성)
|
||||
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}" | head -10
|
||||
else
|
||||
log_error "Docker가 설치되지 않았습니다"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 4. 네트워크 연결 상태
|
||||
log_info "🌐 네트워크 연결 상태"
|
||||
|
||||
# 포트 확인
|
||||
PORTS=("24100:nginx" "24101:database" "24102:backend" "24103:redis")
|
||||
for port_info in "${PORTS[@]}"; do
|
||||
PORT=$(echo $port_info | cut -d: -f1)
|
||||
SERVICE=$(echo $port_info | cut -d: -f2)
|
||||
|
||||
if netstat -tuln | grep -q ":$PORT "; then
|
||||
log_success "$SERVICE (포트 $PORT): 리스닝 중"
|
||||
else
|
||||
log_error "$SERVICE (포트 $PORT): 리스닝하지 않음"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# 5. 로그 파일 크기 확인
|
||||
log_info "📝 로그 파일 상태"
|
||||
|
||||
LOG_DIRS=(
|
||||
"/volume1/docker/document-server/logs"
|
||||
"/volume1/docker/document-server/logs/nginx"
|
||||
)
|
||||
|
||||
for log_dir in "${LOG_DIRS[@]}"; do
|
||||
if [ -d "$log_dir" ]; then
|
||||
LOG_SIZE=$(du -sh "$log_dir" 2>/dev/null | cut -f1)
|
||||
echo -e " ${CYAN}${log_dir}${NC}: ${LOG_SIZE}"
|
||||
|
||||
# 큰 로그 파일 경고 (1GB 이상)
|
||||
LOG_SIZE_MB=$(du -sm "$log_dir" 2>/dev/null | cut -f1)
|
||||
if [ "$LOG_SIZE_MB" -gt 1024 ]; then
|
||||
log_warning "로그 디렉토리가 1GB를 초과했습니다: $log_dir"
|
||||
fi
|
||||
else
|
||||
log_warning "로그 디렉토리가 존재하지 않습니다: $log_dir"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# 6. 데이터베이스 연결 테스트
|
||||
log_info "🗄️ 데이터베이스 연결 테스트"
|
||||
|
||||
if docker-compose -f "$COMPOSE_FILE" ps -q database >/dev/null 2>&1; then
|
||||
DB_STATUS=$(docker-compose -f "$COMPOSE_FILE" exec -T database pg_isready -U docuser -d document_db 2>/dev/null)
|
||||
if echo "$DB_STATUS" | grep -q "accepting connections"; then
|
||||
log_success "PostgreSQL: 연결 가능"
|
||||
|
||||
# 데이터베이스 크기 확인
|
||||
DB_SIZE=$(docker-compose -f "$COMPOSE_FILE" exec -T database psql -U docuser -d document_db -t -c "SELECT pg_size_pretty(pg_database_size('document_db'));" 2>/dev/null | xargs)
|
||||
echo -e " 데이터베이스 크기: ${CYAN}${DB_SIZE}${NC}"
|
||||
else
|
||||
log_error "PostgreSQL: 연결 실패"
|
||||
fi
|
||||
else
|
||||
log_error "데이터베이스 컨테이너가 실행 중이지 않습니다"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 7. Redis 연결 테스트
|
||||
log_info "💾 Redis 연결 테스트"
|
||||
|
||||
if docker-compose -f "$COMPOSE_FILE" ps -q redis >/dev/null 2>&1; then
|
||||
REDIS_STATUS=$(docker-compose -f "$COMPOSE_FILE" exec -T redis redis-cli ping 2>/dev/null)
|
||||
if [ "$REDIS_STATUS" = "PONG" ]; then
|
||||
log_success "Redis: 연결 가능"
|
||||
|
||||
# Redis 메모리 사용량
|
||||
REDIS_MEMORY=$(docker-compose -f "$COMPOSE_FILE" exec -T redis redis-cli info memory | grep "used_memory_human" | cut -d: -f2 | tr -d '\r')
|
||||
echo -e " 메모리 사용량: ${CYAN}${REDIS_MEMORY}${NC}"
|
||||
else
|
||||
log_error "Redis: 연결 실패"
|
||||
fi
|
||||
else
|
||||
log_error "Redis 컨테이너가 실행 중이지 않습니다"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 8. 백업 상태 확인
|
||||
log_info "💾 백업 상태 확인"
|
||||
|
||||
BACKUP_DIR="/volume2/document-storage/backups"
|
||||
if [ -d "$BACKUP_DIR" ]; then
|
||||
BACKUP_COUNT=$(find "$BACKUP_DIR" -name "*.sql" -mtime -1 | wc -l)
|
||||
LATEST_BACKUP=$(find "$BACKUP_DIR" -name "*.sql" -type f -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -1 | cut -d' ' -f2- | xargs basename 2>/dev/null || echo "없음")
|
||||
|
||||
echo -e " 백업 디렉토리: ${CYAN}${BACKUP_DIR}${NC}"
|
||||
echo -e " 최근 24시간 백업: ${CYAN}${BACKUP_COUNT}개${NC}"
|
||||
echo -e " 최신 백업: ${CYAN}${LATEST_BACKUP}${NC}"
|
||||
|
||||
if [ "$BACKUP_COUNT" -eq 0 ]; then
|
||||
log_warning "최근 24시간 내 백업이 없습니다"
|
||||
fi
|
||||
else
|
||||
log_error "백업 디렉토리가 존재하지 않습니다: $BACKUP_DIR"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# 9. 권장 사항
|
||||
log_info "💡 권장 사항"
|
||||
|
||||
# 메모리 사용률이 높은 경우
|
||||
if [ "${MEM_PERCENT%.*}" -gt 80 ]; then
|
||||
log_warning "메모리 사용률이 높습니다 (${MEM_PERCENT}%). 모니터링이 필요합니다."
|
||||
fi
|
||||
|
||||
# 디스크 사용률 확인
|
||||
HIGH_DISK_USAGE=$(df /volume1 /volume2 | awk 'NR>1 {gsub(/%/, "", $5); if ($5 > 85) print $6 " (" $5 "%)"}')
|
||||
if [ -n "$HIGH_DISK_USAGE" ]; then
|
||||
log_warning "디스크 사용률이 높은 볼륨: $HIGH_DISK_USAGE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== 모니터링 완료 ==="
|
||||
echo "다음 명령어로 실시간 모니터링 가능:"
|
||||
echo " watch -n 5 '$0'"
|
||||
echo " docker-compose -f $COMPOSE_FILE logs -f"
|
||||
echo " docker stats"
|
||||
Reference in New Issue
Block a user