docs: 트러블슈팅 문서 추가
- 관리자 대시보드 구축 과정 - Gitea Actions 설정 - GitHub에서 마이그레이션 - 시스템 메트릭 구현 - Docker 네트워크 격리 문제 해결 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
573cdb99cb
commit
ba52ee2200
256
docs/troubleshooting/20250714_admin_dashboard_setup.md
Normal file
256
docs/troubleshooting/20250714_admin_dashboard_setup.md
Normal file
@ -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에 의해 자동 생성되었습니다.*
|
||||
102
docs/troubleshooting/20250714_docker_network_isolation.md
Normal file
102
docs/troubleshooting/20250714_docker_network_isolation.md
Normal file
@ -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 네트워크 격리는 보안을 위한 의도된 동작
|
||||
- 같은 네트워크에 있는 컨테이너끼리만 직접 통신 가능
|
||||
- 서로 다른 네트워크 간 통신은 명시적인 설정 필요
|
||||
127
docs/troubleshooting/20250714_system_metrics_implementation.md
Normal file
127
docs/troubleshooting/20250714_system_metrics_implementation.md
Normal file
@ -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. 성능 최적화 및 에러 핸들링 개선
|
||||
Loading…
x
Reference in New Issue
Block a user