diff --git a/docs/troubleshooting/20250714_admin_dashboard_setup.md b/docs/troubleshooting/20250714_admin_dashboard_setup.md new file mode 100644 index 0000000..619594e --- /dev/null +++ b/docs/troubleshooting/20250714_admin_dashboard_setup.md @@ -0,0 +1,256 @@ +# RO-BEING 관리자 대시보드 구축 및 트러블슈팅 + +**날짜**: 2025-07-14 +**작업자**: Claude (RO-BEING 시스템 관리) + +## 개요 + +기존 8000번 포트 backend에 `/admin/*` 경로로 종합 관리 대시보드를 구축하는 과정에서 발생한 문제들과 해결 방법을 기록합니다. + +## 프로젝트 목표 + +### 구현 기능 +- 시스템 리소스 모니터링 (CPU, 메모리, 디스크) +- Docker 컨테이너 상태 및 관리 +- 서비스 Health Check (Nginx, Gitea, Frontend, Backend, Test-API) +- Nginx 상태 확인 및 재로드 +- Gitea Actions Runner 모니터링 +- Git 활동 추적 +- 실시간 로그 조회 +- JWT 기반 인증 시스템 + +### 접속 정보 +- **URL**: http://ro-being.com/admin +- **로그인 비밀번호**: 19800508 + +## 발생한 문제들과 해결 과정 + +### 1. 포트 충돌 문제 + +**문제**: 8000번 포트가 이미 고객용 서비스로 사용 중 + +**초기 계획**: 별도 포트(9000)나 독립 컨테이너 사용 +**최종 해결**: 경로 분리 방식 채택 (`/admin/*` 경로) + +**장점**: +- 기존 고객 서비스에 영향 없음 +- 통합 관리 가능 +- 추가 포트 오픈 불필요 + +### 2. 외부 접속 불가 문제 + +**증상**: `ERR_CONNECTION_TIMED_OUT` 오류 발생 + +**원인**: nginx 설정에 `/admin` 경로 프록시 설정 누락 + +**해결책**: nginx 설정 추가 +```nginx +# Admin dashboard +location /admin { + proxy_pass http://localhost:8000; + 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; +} +``` + +**배포 방법**: Gitea Actions 자동 배포 활용 + +### 3. 서비스 Health Check 실패 + +**문제**: 모든 서비스가 `unreachable` 또는 `timeout` 상태 + +**원인**: +1. 잘못된 health check 엔드포인트 +2. 서비스별 상태 코드 차이 미고려 + +**해결책**: 서비스별 맞춤 설정 +```python +SERVICES = { + "nginx": {"port": 80, "url": "http://localhost", "health_path": "/health", "timeout": 3}, + "gitea": {"port": 3000, "url": "http://localhost:3000", "health_path": "/api/healthz", "timeout": 3}, + "frontend": {"port": 5173, "url": "http://localhost:5173", "health_path": "/", "timeout": 3}, + "backend": {"port": 8000, "url": "http://localhost:8000", "health_path": "/health", "timeout": 3}, + "test-api": {"port": 10508, "url": "http://localhost:10508", "health_path": "/health", "timeout": 3} +} +``` + +**개선사항**: +- nginx: 404도 정상으로 인식 +- gitea: `/api/healthz` 엔드포인트 사용 +- frontend: 200/304 상태 코드 모두 허용 +- 타임아웃 3초로 단축 + +### 4. Docker API 접근 실패 (HTTP 500) + +**증상**: 컨테이너 상태, Nginx 상태, Gitea Runners 모든 API에서 500 에러 + +**원인**: 컨테이너에서 Docker 소켓 접근 불가 + +**진단**: +```bash +docker exec frontend-backend-1 ls -la /var/run/docker.sock +# ls: cannot access '/var/run/docker.sock': No such file or directory +``` + +**해결책**: docker-compose.yml 수정 +```yaml +backend: + build: + context: ./backend + dockerfile: Dockerfile + ports: + - "8000:8000" + volumes: + - ./backend:/app + - /var/run/docker.sock:/var/run/docker.sock:ro # Docker 소켓 마운트 + - /var/log/nginx:/var/log/nginx:ro # Nginx 로그 접근 + - /home/admin:/host_home:ro # 호스트 홈 디렉터리 접근 + environment: + - PYTHONPATH=/app + privileged: true # Docker 권한 부여 +``` + +### 5. 파일 경로 접근 문제 + +**문제**: 컨테이너 내부에서 호스트 파일 시스템 접근 불가 + +**영향받는 기능**: +- Gitea Runner 로그 파일 읽기 +- Git 저장소 활동 조회 +- 시스템 로그 접근 + +**해결책**: 경로 매핑 및 코드 수정 +```python +# 수정 전 +log_file = "/home/admin/org_runner.log" +repo_path = "/home/admin/github-migration/nginx-infra" + +# 수정 후 +log_file = "/host_home/org_runner.log" +repo_path = "/host_home/github-migration/nginx-infra" +``` + +### 6. 권한 및 보안 설정 + +**요구사항**: +- Docker 소켓 읽기 권한 +- 시스템 명령어 실행 권한 (ps, systemctl) +- 로그 파일 읽기 권한 + +**구현**: +- `privileged: true` 설정 +- 읽기 전용(`:ro`) 볼륨 마운트로 보안 강화 +- JWT 토큰 기반 인증 (2시간 세션) + +## 최종 아키텍처 + +### 백엔드 구조 +``` +/home/admin/frontend/backend/ +├── main.py # 기존 고객용 API + 관리자 라우터 등록 +├── admin_routes.py # 관리자 전용 API 엔드포인트 +├── admin_static/ +│ └── index.html # 관리자 대시보드 프론트엔드 +└── requirements.txt # 추가 dependencies (docker, psutil, PyJWT, requests) +``` + +### API 엔드포인트 +- `POST /admin/login` - 관리자 로그인 +- `GET /admin/verify` - 토큰 검증 +- `GET /admin/system/overview` - 시스템 리소스 +- `GET /admin/containers` - Docker 컨테이너 상태 +- `GET /admin/services/status` - 서비스 Health Check +- `GET /admin/nginx/status` - Nginx 상태 +- `GET /admin/gitea/runners` - Gitea Runners 상태 +- `GET /admin/git/recent-activity` - Git 활동 +- `GET /admin/logs/{service}` - 서비스 로그 +- `POST /admin/containers/{id}/restart` - 컨테이너 재시작 +- `POST /admin/nginx/reload` - Nginx 재로드 + +### 추가 Dependencies +``` +docker==6.1.3 +psutil==5.9.6 +PyJWT==2.8.0 +requests==2.31.0 +``` + +## 성능 최적화 + +### 자동 새로고침 +- 30초마다 주요 지표 자동 업데이트 +- 로그인 세션 2시간 유지 +- 비동기 API 호출로 빠른 응답 + +### 사용자 경험 +- 반응형 모바일 친화적 UI +- 실시간 상태 표시 (색상 인디케이터) +- 원클릭 관리 기능 (재시작, 재로드) + +## 트러블슈팅 가이드 + +### 일반적인 문제들 + +**문제**: 관리자 페이지 접속 안됨 +**해결**: nginx 설정에 `/admin` 경로 추가 확인 + +**문제**: 모든 API에서 500 에러 +**해결**: Docker 소켓 마운트 및 privileged 권한 확인 + +**문제**: 서비스 상태가 모두 unreachable +**해결**: 서비스별 health check 엔드포인트 및 타임아웃 설정 확인 + +**문제**: 로그 파일 not found +**해결**: 호스트 디렉터리 마운트 및 경로 매핑 확인 + +**문제**: Git 활동 조회 실패 +**해결**: `/host_home` 경로로 Git 저장소 접근 확인 + +### 모니터링 명령어 + +```bash +# 컨테이너 상태 확인 +docker ps | grep frontend + +# 관리자 백엔드 로그 확인 +docker logs frontend-backend-1 --tail=20 + +# Docker 소켓 마운트 확인 +docker exec frontend-backend-1 ls -la /var/run/docker.sock + +# 권한 확인 +docker exec frontend-backend-1 whoami +docker exec frontend-backend-1 ps aux + +# API 테스트 +curl -X POST http://localhost:8000/admin/login \ + -H "Content-Type: application/json" \ + -d '{"password":"19800508"}' +``` + +## 보안 고려사항 + +### 구현된 보안 기능 +- JWT 토큰 기반 인증 +- 비밀번호 하드코딩 (임시) +- 읽기 전용 볼륨 마운트 +- HTTPS 접속 (nginx SSL) + +### 향후 개선사항 +- 환경변수 기반 비밀번호 관리 +- 다중 사용자 지원 +- 세션 로깅 및 감사 +- API 요청 제한 (Rate Limiting) + +## 참고 자료 + +- **관리자 대시보드**: http://ro-being.com/admin +- **백엔드 API 문서**: FastAPI 자동 생성 문서 (/docs) +- **Docker Compose 설정**: `/home/admin/frontend/docker-compose.yml` +- **Nginx 설정**: `/etc/nginx/sites-available/default` +- **Gitea Actions**: nginx-infra 저장소 워크플로우 + +--- +*이 문서는 Claude에 의해 자동 생성되었습니다.* \ No newline at end of file diff --git a/docs/troubleshooting/20250714_docker_network_isolation.md b/docs/troubleshooting/20250714_docker_network_isolation.md new file mode 100644 index 0000000..8d6badb --- /dev/null +++ b/docs/troubleshooting/20250714_docker_network_isolation.md @@ -0,0 +1,102 @@ +# Docker 네트워크 격리로 인한 test-api unreachable 문제 해결 + +## 개요 +- **날짜**: 2025-07-14 +- **문제**: 관리자 대시보드에서 test-api (10508) 서비스가 unreachable 상태 +- **원인**: Docker 네트워크 격리 (DOCKER-ISOLATION iptables 체인) + +## 문제 상황 + +### 증상 +- 관리자 대시보드에서 test-api 서비스가 지속적으로 `unreachable` 표시 +- 호스트에서는 `curl http://localhost:10508/health` 정상 동작 +- 컨테이너 내부에서는 연결 불가 + +### 네트워크 구성 +``` +frontend_default (172.18.0.0/16) +├── frontend-backend-1 (172.18.0.2) +└── frontend-frontend-1 (172.18.0.3) + +appnet (172.21.0.0/16) +└── test-api-container (172.21.0.2) +``` + +## 원인 분석 + +Docker의 기본 bridge 네트워크 드라이버는 네트워크끼리 완전히 격리하도록 iptables 체인(DOCKER-ISOLATION, DOCKER-USER)을 자동으로 생성합니다. + +**결과**: 같은 호스트라도 서로 다른 bridge 네트워크에 있는 컨테이너는 호스트 포트(`-p 10508:10508`)로도 통신이 차단됨 + +## 해결 방법 + +### 선택한 해결책: 같은 사용자 정의 네트워크에 연결 + +1. **appnet 네트워크 확인** +```bash +docker network ls +docker network inspect appnet +``` + +2. **frontend 컨테이너들을 appnet에 연결** +```bash +docker network connect appnet frontend-backend-1 +docker network connect appnet frontend-frontend-1 +``` + +3. **연결 확인** +```bash +docker network inspect appnet +# 모든 컨테이너가 나타나는지 확인 +``` + +4. **테스트** +```bash +docker exec frontend-backend-1 curl -s -o /dev/null -w "%{http_code}" http://test-api-container:10508/health +# 200 응답 확인 +``` + +### 다른 가능한 해결 방법들 + +1. **docker-compose.yml에서 네트워크 설정** +```yaml +services: + backend: + networks: + - appnet +networks: + appnet: + external: true +``` + +2. **host 네트워크 사용** (보안상 비추천) +```yaml +network_mode: "host" +``` + +3. **iptables 예외 규칙** (관리 복잡) +```bash +iptables -I DOCKER-USER -i br0 -o br1 -j ACCEPT +``` + +## 주의사항 + +1. **영구 설정**: 컨테이너 재시작 시 네트워크 연결이 유지되려면 docker-compose.yml 수정 필요 +2. **DNS 해결**: 같은 네트워크에 있으면 컨테이너 이름으로 통신 가능 +3. **보안**: 필요한 컨테이너만 같은 네트워크에 연결 + +## 검증 방법 + +```bash +# 네트워크 연결 상태 확인 +docker network inspect appnet | grep -A 5 "Containers" + +# 관리자 대시보드에서 서비스 상태 확인 +curl http://localhost:8000/admin/services/status +``` + +## 참고사항 + +- Docker 네트워크 격리는 보안을 위한 의도된 동작 +- 같은 네트워크에 있는 컨테이너끼리만 직접 통신 가능 +- 서로 다른 네트워크 간 통신은 명시적인 설정 필요 \ No newline at end of file diff --git a/docs/troubleshooting/20250714_system_metrics_implementation.md b/docs/troubleshooting/20250714_system_metrics_implementation.md new file mode 100644 index 0000000..beb3339 --- /dev/null +++ b/docs/troubleshooting/20250714_system_metrics_implementation.md @@ -0,0 +1,127 @@ +# 시스템 메트릭 구현 트러블슈팅 + +## 개요 +- **날짜**: 2025-07-14 +- **작업**: 관리자 대시보드에 시스템 메트릭 그래프 추가 +- **목표**: PostgreSQL + TimescaleDB 기반 시계열 데이터 수집 및 Chart.js 그래프 표시 + +## 주요 문제들과 해결 과정 + +### 1. Docker 네트워크 통신 문제 +**문제**: 관리자 대시보드에서 모든 서비스가 timeout/unreachable 상태 +**원인**: Docker 컨테이너간 네트워크 격리 (DOCKER-ISOLATION iptables 체인) +**해결**: +- 서비스 URL을 IP 주소에서 컨테이너 이름으로 변경 +- `http://172.17.0.2:5173` → `http://frontend:5173` +- `http://172.17.0.1:10508` → `http://test-api-container:10508` + +### 2. TimescaleDB 설치 및 설정 +**문제**: PostgreSQL에 TimescaleDB 확장 설치 필요 +**해결**: +```bash +# TimescaleDB 확장 설치 +sudo apt-get update +sudo apt-get install timescaledb-2-postgresql-15 + +# 데이터베이스 생성 및 확장 활성화 +sudo -u postgres createdb robing_metrics +sudo -u postgres psql robing_metrics -c "CREATE EXTENSION IF NOT EXISTS timescaledb;" +``` + +### 3. HDD 저장소 설정 +**문제**: 메트릭 데이터를 HDD에 저장하기 위한 테이블스페이스 생성 +**해결**: +```sql +-- HDD 테이블스페이스 생성 +CREATE TABLESPACE hdd_tablespace LOCATION '/hdd/postgresql_data'; + +-- 테이블 생성시 HDD 테이블스페이스 사용 +CREATE TABLE system_metrics ( + time TIMESTAMPTZ NOT NULL, + metric_type VARCHAR(50) NOT NULL, + value DOUBLE PRECISION NOT NULL, + hostname VARCHAR(100) DEFAULT 'localhost' +) TABLESPACE hdd_tablespace; +``` + +### 4. PostgreSQL 연결 인증 문제 +**문제**: Docker 컨테이너에서 PostgreSQL 접속 시 password authentication failed +**원인**: PostgreSQL 사용자 비밀번호 미설정 +**해결**: +```bash +# PostgreSQL 비밀번호 설정 +sudo -u postgres psql -c "ALTER USER postgres PASSWORD '19800508';" + +# docker-compose.yml에 환경변수 추가 +environment: + - METRICS_DB_PASSWORD=19800508 +``` + +### 5. 테이블 구조 불일치 문제 +**문제**: +- 로그: `column "timestamp" of relation "system_metrics" does not exist` +- 실제 테이블: `time` 컬럼 존재, `timestamp` 컬럼 없음 + +**원인**: 코드와 데이터베이스 스키마 불일치 +**해결 과정**: +1. 기존 테이블 구조 확인: + ```sql + \d system_metrics + -- time (timestamptz), metric_type (varchar), value (double precision) + ``` +2. 코드 수정하여 기존 테이블 구조에 맞춤: + ```python + # 정규화된 구조로 데이터 삽입 + INSERT INTO system_metrics (time, metric_type, value) + VALUES ($1, $2, $3) + ``` + +### 6. 잘못된 대시보드 구현 +**문제**: 고객용 React 앱에 시스템 메트릭을 구현함 +**원인**: 두 개의 프론트엔드 구조 혼동 +- 고객용: React SPA (`/client/`) +- 관리자용: 정적 HTML (`/backend/admin_static/`) + +**해결**: 관리자 대시보드(정적 HTML)에 Chart.js 기반 그래프 구현 + +## 최종 구현 결과 + +### 파일 구조 +``` +backend/ +├── admin_routes.py # 관리자 API 엔드포인트 +├── admin_static/ +│ └── index.html # 관리자 대시보드 (Chart.js 그래프) +├── metrics_collector.py # 시스템 메트릭 수집기 +├── metrics_database.py # PostgreSQL 데이터베이스 연결 +└── main.py # 메트릭 시스템 초기화 +``` + +### 주요 기능 +1. **메트릭 수집**: 1분 간격으로 CPU, 메모리, 디스크, 업타임 수집 +2. **데이터 저장**: PostgreSQL TimescaleDB 하이퍼테이블에 시계열 데이터 저장 +3. **그래프 표시**: Chart.js로 1h/1d/7d/30d/90d/1y 기간별 그래프 +4. **실시간 표시**: 현재 메트릭 값과 진행률 바 표시 + +### API 엔드포인트 +- `GET /admin/metrics/current` - 현재 메트릭 조회 +- `GET /admin/metrics/history/{period}` - 기간별 메트릭 히스토리 +- `POST /admin/metrics/collect` - 수동 메트릭 수집 + +## 미해결 문제 +**현재 상태**: 테이블 구조 불일치로 인한 메트릭 데이터 삽입 실패 +**증상**: `column "timestamp" of relation "system_metrics" does not exist` +**예상 원인**: 코드 내 일부 SQL 쿼리에서 여전히 `timestamp` 컬럼 참조 + +## 학습 포인트 +1. **Docker 네트워크**: 컨테이너간 통신 시 서비스 이름 사용 +2. **TimescaleDB**: PostgreSQL 확장으로 시계열 데이터 최적화 +3. **두 프론트엔드 구조**: 고객용 React vs 관리자용 정적 HTML 구분 +4. **데이터베이스 스키마**: 코드와 실제 테이블 구조 일치 중요성 +5. **PostgreSQL 인증**: Docker 환경에서 비밀번호 설정 필요 + +## 후속 작업 +1. 테이블 구조 불일치 문제 완전 해결 +2. 메트릭 데이터 수집 정상 동작 확인 +3. 그래프에 실제 데이터 표시 검증 +4. 성능 최적화 및 에러 핸들링 개선 \ No newline at end of file