Monitor 백엔드Antigravity Server Monitor · 수집 서버·대시보드·알림 매뉴얼
호스트 에이전트 매뉴얼
Antigravity Server Monitor › Monitor 백엔드

Monitor 백엔드 매뉴얼

각 호스트의 에이전트가 보내는 메트릭을 수집·저장하고, 실시간 대시보드와 텔레그램 알림을 제공하는 중앙 관제 서버(FastAPI)의 설치·설정·운영 방법을 설명합니다.

1.개요

Monitor 백엔드는 이 시스템의 중앙 수집·관제 서버입니다. 각 호스트의 통합 호스트 에이전트가 push 방식으로 보내는 메트릭을 받아 SQLite에 저장하고, 실시간 대시보드·조회 API·텔레그램 알림을 제공합니다.

host-agent (prod-01) ─┐ host-agent (prod-02) ─┼─ POST /api/v1/host/metrics ─▶ ┌────────────────────────────┐ host-agent (db-01) ─┘ (X-API-Key 인증) │ Monitor 백엔드 (:8009) │ │ ├─ 수집·저장 (SQLite) │ 브라우저 ◀── 대시보드 / (5초 자동 갱신, HTMX) ──── │ ├─ 상태 레벨 판정 │ 외부 시스템 ◀── 조회 API /api/v1/hosts ──────────── │ ├─ 알림 엔진 (전이 감지) │ 텔레그램 ◀── 상태 전이 알림 · 일일 리포트 ──────── │ └─ 일일 리포트 스케줄러 │ └────────────────────────────┘
항목내용
기술 스택Python 3.12 · FastAPI · SQLite(aiosqlite) · Jinja2 + HTMX (대시보드)
포트8009 — 대시보드·수집·API 모두 단일 포트
인증수집·조회 API는 요청 헤더 X-API-Key (환경변수 MONITORING_API_KEY)
데이터 저장SQLite 파일 1개 (data/monitors.db) — 외부 DB 불필요
호스트 등록사전 등록 없음 — 에이전트 첫 전송 시 hostname 기준 자동 등록
알림상태 전이 시에만 텔레그램 전송(스팸 방지) + 하루 2회 일일 리포트

1.1내부 모듈 구조

모듈역할
app/main.pyFastAPI 진입점. .env 로드, 백그라운드 태스크 2종(오프라인 스윕·일일 리포트 스케줄러) 관리, 매뉴얼 정적 서빙(/manual)
app/database.pySQLite 연결 관리. 기동 시 테이블·인덱스 자동 생성 + 컬럼 마이그레이션
app/routes/host.py수집 엔드포인트 POST /api/v1/host/metrics — 호스트/서비스 upsert + 메트릭 적재 + 알림 평가
app/routes/dashboard.py대시보드 화면(/), HTMX 부분 갱신, 조회 API, 텔레그램 전송 API
manuals/사용 매뉴얼 정적 HTML — /manual(랜딩) · /manual/monitor/(이 문서) · /manual/host_agent/
app/levels.py상태 레벨(ok/warn/crit) 산정 규칙 — 9.1절 표의 구현체
app/categories.py서비스 type → 카테고리(웹서버/캐시/DB/기타) 분류표
app/alerts.py알림 엔진 — 전이 감지, 진단 사유 문구 생성, 문제 지속 시간 추적, 인시던트 누적(최근 알림 타임라인·/api/v1/incidents), 호스트 상세·일일 리포트 메시지 작성
app/telegram.py텔레그램 Bot API 전송(표준 라이브러리만 사용). 토큰 미설정 시 조용히 비활성화
app/schemas.py수집 페이로드 Pydantic 스키마
setup_db.py스키마 수동 생성 스크립트(선택 — 앱 기동 시 자동 생성되므로 보통 불필요)

2.빠른 시작

Docker가 있는 서버라면 3분 안에 기동할 수 있습니다.

# 1) monitor 폴더로 이동
cd monitor

# 2) 환경 설정 — 최소한 API 키는 교체 (4장 참고)
cat > .env <<'EOF'
MONITORING_API_KEY=강력한_임의_문자열
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
EOF

# 3) 빌드 + 백그라운드 기동
docker compose up -d --build

# 4) 확인
docker logs -f monitor-backend     # "Uvicorn running on ..." 확인
curl -s http://localhost:8009/api/v1/hosts -H "X-API-Key: 강력한_임의_문자열"
# → []  (아직 등록된 호스트가 없으면 빈 배열 — 정상)

브라우저에서 열어보세요:

주소화면
http://서버주소:8009/실시간 대시보드
http://서버주소:8009/manual내장 사용 매뉴얼
http://서버주소:8009/docsSwagger API 문서 (자동 생성)

이후 각 감시 대상 서버에 호스트 에이전트를 배포하면 대시보드에 호스트 카드가 자동으로 나타납니다.

i

방화벽에서 8009 포트 인바운드를 에이전트가 있는 서버 대역과 대시보드 사용자에게만 열어 주세요.

3.설치와 실행

3.1Docker Compose (권장)

monitor/docker-compose.yml에 운영 구성이 준비되어 있습니다.

cd monitor
docker compose up -d --build   # 기동
docker compose down            # 중지 (데이터는 ./data에 보존)
docker logs -f monitor-backend # 로그

compose가 구성하는 것들:

항목내용
포트8009:8009
데이터 볼륨./data:/app/data — SQLite 파일이 호스트에 남아 컨테이너를 재생성해도 데이터 유지
.env 마운트./.env:/app/.env:ro — 앱이 직접 읽음(이중 안전장치). compose의 environment: 값이 우선
재시작 정책restart: unless-stopped — 서버 재부팅 시 자동 기동

3.2로컬 가상환경 실행 (개발용)

cd monitor

# 1) 가상환경 + 의존성
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# 2) 기동 — 스키마는 첫 기동 때 자동 생성됩니다
uvicorn app.main:app --host 0.0.0.0 --port 8009

# (개발 중 자동 리로드가 필요하면)
uvicorn app.main:app --host 0.0.0.0 --port 8009 --reload

데이터 파일은 monitor/data/monitors.db에 생성됩니다. python setup_db.py로 스키마를 미리 만들 수도 있지만, 앱이 기동 시 자동 생성·마이그레이션하므로 보통 필요 없습니다.

3.3업데이트와 재기동

cd monitor
git pull                          # 코드 갱신
docker compose up -d --build      # 이미지 재빌드 + 재기동 (데이터 유지)
i

스키마가 바뀌는 업데이트도 기동 시 자동 반영됩니다(CREATE TABLE IF NOT EXISTS + 컬럼 추가 마이그레이션). 별도 DB 작업이 필요 없습니다.

!

백엔드가 재시작되면 알림 엔진의 인메모리 상태가 초기화되어, 현재 이상 상태인 항목의 알림이 1회 다시 올 수 있습니다(데이터 유실은 없음). 에이전트들은 백엔드 재기동 중의 페이로드를 버퍼에 보관했다가 재전송하므로 그래프 공백도 생기지 않습니다.

4.환경변수 (.env)

monitor/.env 파일에 작성합니다. 앱이 기동 시 직접 읽으며, 이미 설정된 OS/컨테이너 환경변수가 우선합니다.

변수기본값설명
MONITORING_API_KEYsecret_monitoring_key 수집·조회 API 인증 키. 모든 에이전트의 MONITOR_API_KEY와 동일해야 함. 운영에서는 반드시 교체
DATABASE_URLsqlite+aiosqlite:///./data/monitors.db SQLite 파일 경로 (compose에서는 /app/data/monitors.db로 지정됨)
DASHBOARD_POLL_INTERVAL5대시보드 자동 갱신 주기(초)
OFFLINE_THRESHOLD_SEC15 마지막 수신 후 이 시간(초)이 지나면 호스트를 오프라인으로 판정. 에이전트 수집 주기보다 커야 함
OFFLINE_SWEEP_INTERVAL5오프라인 검사 주기(초)
OFFLINE_ALERT_CONFIRM_SEC60 텔레그램 오프라인 알림 확정 시간(초). 이 시간 이상 연속으로 수신이 없어야 알림을 보냅니다 — 수집 지연으로 생기는 순간 공백 오탐 방지. 화면의 오프라인 표시는 OFFLINE_THRESHOLD_SEC 기준으로 더 빠르게 반영됩니다
TELEGRAM_BOT_TOKEN(없음)텔레그램 봇 토큰 — 6.1절. 미설정 시 알림 기능 전체가 조용히 비활성화
TELEGRAM_CHAT_ID(없음)알림을 받을 대화방 ID (개인/그룹/채널)
ALERT_RECOVERYtruefalse면 "복구" 알림을 보내지 않음 (악화 알림만)
DAILY_REPORT_TIMES09:00,18:00일일 리포트 전송 시각(KST, 쉼표 구분). 비우면 미전송

작성 예시

# monitor/.env — 운영 예시
MONITORING_API_KEY=1c9a7e...강력한_임의_문자열

# 텔레그램 알림 (6장 참고 — 비우면 알림 비활성)
TELEGRAM_BOT_TOKEN=123456789:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TELEGRAM_CHAT_ID=-1001234567890

# 하루 2회 리포트 (KST)
DAILY_REPORT_TIMES=09:00,18:00

# 복구 알림도 받기
ALERT_RECOVERY=true
!

.env에는 실제 토큰·키가 들어가므로 git에 커밋하지 마세요. API 키를 바꾸면 모든 에이전트의 MONITOR_API_KEY도 함께 바꿔야 합니다.

5.대시보드 사용법

http://서버주소:8009/ — 별도 로그인 없이 접근하며, 5초마다 자동 갱신됩니다(HTMX 부분 갱신 — 새로고침 불필요).

5.1화면 구성

대시보드 전체 화면 — 상단바, 통계 스트립(총계·호스트 상태 필터 칩·서버 상태·분류), 호스트 카드 그리드
대시보드 전체 화면 (화면의 호스트·수치는 예시 데이터입니다)

화면은 위에서부터 네 구역으로 나뉩니다.

  1. 상단바 — 현재 시각(KST)과 Live 뱃지 (다음 자동 갱신까지 남은 시간을 초 단위로 카운트다운 — 5→4→…→0으로 줄다가 갱신 순간 리셋), 현황 전송(전체 요약을 즉시 텔레그램으로), 테마 전환(달/해 아이콘), API(/docs Swagger), Manual(/manual 내장 매뉴얼) 버튼이 있습니다.
  2. 통계 스트립 — 한 줄 요약 바. 전체 호스트·서버 수 → 호스트 상태 칩(정상/주의/위험/오프라인) → 서비스 인스턴스 단위 서버 상태(온라인/주의/오프라인) → 분류(웹서버/캐시/DB) 순서입니다. 호스트 상태 칩은 클릭하면 아래 목록이 해당 상태의 호스트만 필터링되고, 같은 칩을 다시 클릭하면 해제됩니다. 서버 수십 대 중 문제 호스트만 빠르게 추릴 때 사용하세요.
  3. 호스트 그리드 — 호스트 1대 = 카드 1장. 우측 상단 토글로 컴팩트(카드) / 테이블 뷰를 전환할 수 있습니다(5.4절).
  4. 최근 알림 타임라인 — 그리드 아래에 상태가 바뀐 순간의 기록이 최신순으로 표시됩니다(시각 · 아이콘 · 대상 · 사유). 텔레그램으로 발송된 전이 알림과 같은 소스라서, 알림을 놓쳤어도 화면에서 "방금 무슨 일이 있었나"를 확인할 수 있습니다. 일일 리포트 발송 시 초기화되며(6.3절), 백엔드 재시작 시에도 비워집니다.

지표 설명 툴팁

대시보드의 모든 데이터 요소에 설명 툴팁이 붙어 있습니다. 수치·상태 뱃지·차트 위에 마우스를 올리면 해당 지표의 의미와 함께 주의/위험 판정 기준이 말풍선으로 표시됩니다 — 통계 스트립, 호스트 카드, 테이블, 상세 모달의 서비스 지표까지 모두 동일하게 동작합니다. 화면의 노랑/빨강 강조가 그런지 궁금할 때 그 자리에서 바로 확인하세요.

호스트 카드의 CPU 수치에 마우스를 올려 표시된 설명 툴팁 — CPU 사용률의 의미와 75% 주의·90% 위험 임계값 안내
지표 툴팁 — CPU 수치에 마우스를 올리면 의미와 임계값(75% 주의 / 90% 위험)이 표시됩니다

모바일 화면

화면 폭 640px 이하(스마트폰)에서는 별도 주소 없이 같은 URL이 자동으로 모바일 레이아웃으로 전환됩니다. 컴팩트 뷰로 고정되어(뷰 토글 숨김) 카드가 1열로 정렬되고, 상세 모달은 화면 아래에서 올라오는 시트 형태로 열립니다. 모바일에서는 조회 전용으로 동작해 전송·삭제 버튼이 표시되지 않습니다(조작은 PC 화면에서).

모바일 대시보드 — 요약 카드 2열, 호스트 카드 1열 배치
모바일 대시보드 (390px)
모바일 상세 모달 — 화면 하단에서 올라오는 바텀시트, 서비스 지표가 2열로 배치, 조회 전용
모바일 상세 모달 — 바텀시트, 서비스 지표 2열 배치, 조회 전용

5.2호스트 카드 읽는 법

위험 상태 호스트 카드 — 왼쪽 빨간 테두리, 위험 뱃지, CPU/MEM/DISK 수치, 서버 상태 카운트
위험(crit) 상태의 호스트 카드 — 왼쪽 테두리와 뱃지가 상태 색을 따릅니다
  • 헤더 — 호스트명, 상태 뱃지(Online / 주의 / 위험 / Offline), 종이비행기 버튼(이 호스트 현황을 텔레그램으로 전송).
  • CPU / MEM / DISK — 시스템 사용률. 75% 이상이면 노랑, 90% 이상이면 빨강으로 숫자 색이 바뀝니다(9.1절 임계값).
  • 서버 카운트 — 이 호스트에 등록된 서비스 수와 상태별 집계: ● 온라인 · ▲ 주의 · ■ 오프라인(down).
  • 문제 사유 배지 — 주의/위험 서비스가 있으면 카드 하단에 어느 서비스가 · 왜 · 얼마나 오래 문제인지 배지로 바로 표시됩니다. 예: 🔴 payment-server · HTTP 500 · 5분째. 모달을 열지 않아도 대응 판단이 가능합니다. 문제가 3개 이상이면 상위 2개 + "+N건 더"로 접히고, 카드를 클릭하면 전체를 볼 수 있습니다. 오프라인 호스트는 ⚫ 오프라인 — 수신 끊김 · 지속 시간이 표시됩니다. (지속 시간은 인메모리 추적이라 백엔드 재시작 시 다시 계산됩니다)
상태 색의미
초록 (ok)정상
노랑 (warn)주의 — 임계값 초과 (9.1절)
빨강 (crit)위험 — 서비스 down 또는 위험 임계 초과
회색 (offline)오프라인 — 에이전트 수신 끊김 (9.2절)

호스트 카드의 전체 상태는 시스템 상태와 소속 서비스들 중 가장 나쁜 상태로 롤업됩니다. 카드의 IP·OS·서비스별 상세 지표는 카드를 클릭하면 열리는 상세 모달에서 확인합니다.

5.3호스트 상세 모달

카드(또는 테이블 행)를 클릭하면 상세 모달이 열립니다. 모달도 5초 갱신 주기에 맞춰 자동으로 최신화되며, ESC 또는 바깥 영역 클릭으로 닫습니다.

정상 호스트의 상세 모달 — 초록 진단 패널, 리눅스 정보 게이지, CPU 추이, 서비스 패널
정상 호스트의 상세 모달 — 진단 패널이 초록으로 "모든 지표가 정상"을 표시

모달은 위에서부터:

  • 헤더·메타 — 호스트명, 상태 뱃지, 현황 전송·닫기 버튼 (오프라인 상태면 삭제 버튼 추가), IP · OS · 마지막 수신 시각 · 서비스 수.
  • 진단 패널왜 이 상태인지를 임계값 기준으로 항목별로 풀어 주고, 각 항목에 조치 가이드가 붙습니다. 모든 지표가 정상이면 초록 패널 1줄로 표시됩니다.
  • 리눅스 정보 — CPU/Memory/Disk 게이지 바, 네트워크 TX/RX 속도, Load Average(1m/5m/15m), 그리고 최근 폴링에서 적립한 CPU 추이 그래프.
  • 서비스 패널 — 서비스가 웹서버/캐시/DB/기타 카테고리로 묶여 표시됩니다. 각 패널에는 인스턴스명 · type · runtime 배지(🐳 Docker + 컨테이너명 / ⚙️ Native) · status 뱃지(UP 등)와 type별 핵심 지표 셀이 나옵니다. 주의/위험 상태인 서비스는 status 뱃지 옆에 ⏱ 지속 시간(문제가 시작된 후 경과)이 함께 표시됩니다.
서비스 type모달에 표시되는 지표
postgresConnections(활성/최대), DB Size, Cache Hit, Index Hit, Deadlocks, Dead Tuples(비율), Locks
mysqlConnections, Running, Slow Queries, Questions, Uptime
redisMemory, Hit Rate, Clients, Ops/sec, Evicted Keys, Uptime
nginxActive Conn, Requests, Accepts, Reading/Writing/Waiting, Status
HTTP 앱 (fastapi/nodejs/nextjs …)Status Code, Latency, Reachable
+ Docker 컨테이너컨테이너 상태, 컨테이너 CPU/MEM(%), 재시작 횟수, Health

임계값을 초과한 지표는 셀 값이 노랑/빨강으로 강조됩니다. 아래는 위험 상태 호스트의 예 — 진단 패널이 어떤 지표가 어떤 기준을 넘었는지, 무엇을 하면 되는지 알려줍니다.

위험 호스트의 상세 모달 — 빨간 진단 패널에 캐시 히트율·데드락·커넥션 포화 사유와 조치 가이드
위험(crit) 호스트의 상세 모달 — postgres 캐시 히트율 88.2%·커넥션 48/50 등 위험 사유와 조치 가이드가 항목별로 표시됩니다

5.4화면 동작과 버튼

동작설명
상태 필터통계 스트립의 호스트 상태 칩(정상/주의/위험/오프라인) 클릭 — 해당 상태의 호스트만 표시, 재클릭 시 해제. 컴팩트/테이블 뷰 모두 적용되며 5초 자동 갱신에도 유지됩니다
컴팩트 / 테이블 뷰우측 상단 토글 — 카드 그리드와 한눈에 보는 표 형태를 전환. 선택은 브라우저에 저장됩니다
지표 툴팁모든 수치·뱃지·차트에 마우스를 올리면 지표의 의미와 주의/위험 임계값이 말풍선으로 표시됩니다 (5.1절)
자동 갱신 카운트다운상단 Live 뱃지의 숫자가 다음 갱신까지 남은 초를 표시 — 데이터가 다시 로드되는 순간 리셋됩니다
현황 전송상단 버튼 — 전체 요약 리포트를 텔레그램으로 전송 (POST /notify/summary). 실수 방지를 위해 확인 모달에서 "전송"을 눌러야 실제 전송되며, 결과는 화면 하단 토스트로 안내
호스트별 전송카드·테이블·모달의 종이비행기 버튼 — 해당 호스트 상세 현황을 텔레그램으로 전송 (POST /notify/host/{id}). 역시 확인 모달을 거칩니다
API / 매뉴얼상단바 링크 — /docs(Swagger)와 /manual(내장 사용 매뉴얼)
테마라이트/다크 전환 (브라우저에 저장, 최초에는 OS 설정을 따름)
테이블 뷰 — 호스트별 상태, CPU/MEM/DISK, 서버 카운트, 최근 수신 시각을 표로 표시
테이블 뷰 — 호스트가 많을 때 상태·수치를 한눈에 비교하기 좋습니다. 행 클릭 시 동일한 상세 모달이 열립니다
다크 테마 대시보드
다크 테마 — 상단바의 달/해 아이콘으로 전환합니다

5.5호스트 삭제

퇴역한 서버는 삭제 버튼(휴지통)으로 제거합니다. 실수 방지를 위해 오프라인 상태의 호스트만 삭제할 수 있고, 삭제 전에 호스트명을 똑같이 입력해 확인해야 합니다.

  1. 대상 서버에서 에이전트 중지 (./stop.sh 또는 systemctl stop host-agent)
  2. 15초 뒤 카드가 오프라인(회색)으로 바뀌면, 상세 모달 헤더 또는 테이블 뷰 행 끝의 휴지통 버튼 클릭
  3. 확인 창에 호스트명을 정확히 입력하면 삭제됩니다
오프라인 호스트의 상세 모달 — 헤더에 휴지통(삭제) 버튼이 나타나고, 진단 패널에 마지막 수신 시각과 조치 안내가 표시
오프라인 호스트의 상세 모달 — 헤더에 삭제(휴지통) 버튼이 나타나고, 진단 패널이 마지막 수신 시각과 점검 방법을 안내합니다
!

삭제하면 해당 호스트의 모든 메트릭 이력이 함께 삭제됩니다(CASCADE). 온라인 상태에서 삭제를 시도하면 409로 거절됩니다.

6.텔레그램 알림

6.1봇 생성과 연결

  1. 봇 만들기 — 텔레그램에서 @BotFather를 검색해 대화 시작 → /newbot 입력 → 봇 이름과 사용자명(…bot으로 끝나야 함) 지정 → 발급된 토큰(123456789:AAxx... 형태)을 복사
  2. 대화방 준비 — 알림을 받을 곳을 정합니다.
    • 개인으로 받기: 방금 만든 봇에게 아무 메시지나 1번 보내기
    • 그룹으로 받기: 그룹에 봇을 초대하고 그룹에서 아무 메시지나 1번 보내기
  3. chat_id 알아내기 — 아래 명령의 응답에서 "chat":{"id": ...} 값을 찾습니다. 그룹은 음수(-100...)입니다.
    curl -s "https://api.telegram.org/bot<토큰>/getUpdates" | python3 -m json.tool | grep -A2 '"chat"'
  4. .env에 설정 후 재기동
    TELEGRAM_BOT_TOKEN=123456789:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    TELEGRAM_CHAT_ID=-1001234567890
    docker compose up -d   # 재기동 — 로그에 "[telegram] 알림 활성화됨" 확인
  5. 전송 테스트
    curl -s -X POST http://localhost:8009/api/v1/notify/message \
      -H "X-API-Key: 설정한_키" -H "Content-Type: application/json" \
      -d '{"text": "<b>테스트</b> 모니터링 알림 연결 확인"}'
    # → {"sent": true}

6.2알림 동작 원리 — 전이 기반

임계값을 초과했다고 매 수신(5초)마다 알리는 것이 아니라, 상태가 바뀌는 순간에만 1회 알립니다. 같은 상태가 지속되면 추가 알림이 없습니다(알림 스팸 방지).

정상(ok) ──▶ 주의(warn) : 🟡 [주의] 알림 1회 주의(warn) ──▶ 위험(crit) : 🔴 [위험] 알림 1회 위험(crit) ──▶ 정상(ok) : 🟢 [복구] 알림 1회 (ALERT_RECOVERY=false면 생략) 수신 끊김 60초 확정 : ⚫ [오프라인] 알림 1회 → 재수신 시 [복구]

오프라인 알림은 OFFLINE_ALERT_CONFIRM_SEC(기본 60초) 이상 연속으로 수신이 없어야 발송됩니다. 화면 표시는 15초부터 오프라인으로 바뀌지만, 수집 지연으로 생기는 몇 초의 공백에는 알림을 보내지 않아 오탐을 방지합니다. 알림 메시지에는 마지막 수신 후 경과 시간이 함께 표시됩니다.

알림 메시지에는 구체적 사유가 함께 옵니다 — 예:

🔴 [위험] prod-01 · payment-db (postgres)
• 캐시 히트율 88.0%
• 커넥션 48/50 (96%)
2026-07-08 14:03:22 KST

전이 판정 단위(각각 독립적으로 추적됩니다):

  • 호스트 시스템 (CPU/MEM/DISK)
  • 서비스 인스턴스 각각 (type·name 단위)
  • 호스트 온라인/오프라인

발생한 전이 알림은 텔레그램 발송과 동시에 대시보드 하단 "최근 알림" 타임라인 (5.1절)과 GET /api/v1/incidents(7장)에도 같은 내용으로 기록됩니다. 또 전이가 시작된 시각을 기억해 두었다가, 문제가 지속되는 동안 호스트 카드 배지와 상세 모달에 지속 시간("5분째")으로 표시합니다.

6.3일일 리포트

DAILY_REPORT_TIMES(기본 09:00, 18:00 KST)에 전체 현황 요약이 자동 전송됩니다.

  • 전체 집계 — 호스트 온라인/오프라인 수, 서비스 정상/주의/위험/오프라인 수
  • 기간 내 발생 알림 건수 (리포트 전송 시 카운터 초기화)
  • 호스트별 요약 — 상태가 나쁜 호스트가 위로 정렬, 문제 서비스와 사유 표시

같은 내용을 수동으로 받으려면 대시보드의 "현황 전송" 버튼 또는 POST /notify/summary를 호출하세요.

7.REST API 레퍼런스

전체 스키마는 http://서버주소:8009/docs(Swagger)에서 인터랙티브하게 확인할 수 있습니다. KEY 표시는 X-API-Key 헤더가 필요한 API입니다.

자동 생성된 Swagger API 문서 — 인증 방법, 기본 흐름, 호스트 조회·텔레그램 알림 엔드포인트 목록
자동 생성되는 Swagger 문서(/docs) — 각 엔드포인트를 펼쳐 브라우저에서 바로 호출해 볼 수 있습니다
엔드포인트인증설명
POST /api/v1/host/metricsKEY에이전트 수집 (직접 호출할 일 없음)
GET /api/v1/hostsKEY호스트 목록 + 요약 상태
GET /api/v1/hosts/{id}KEY호스트 상세 (서비스별 전체 지표)
GET /api/v1/incidentsKEY최근 발생 알림 목록 (최신순, ?limit=20)
POST /api/v1/notify/messageKEY임의 텍스트 텔레그램 전송
POST /notify/summary없음전체 현황 요약 텔레그램 전송 (대시보드 버튼용)
POST /notify/host/{id}없음호스트 상세 현황 텔레그램 전송 (대시보드 버튼용)
DELETE /hosts/{id}없음오프라인 호스트 삭제 (온라인이면 409)
GET / · /manual · /docs없음대시보드 · 내장 매뉴얼 · Swagger

호스트 목록 조회

curl -s http://localhost:8009/api/v1/hosts -H "X-API-Key: 설정한_키"
[
  {
    "id": "b1f2...", "hostname": "prod-01", "ip_address": "10.0.0.5",
    "os_info": "ubuntu 22.04", "status": "warn", "is_active": true,
    "cpu_usage": 40.0, "memory_usage": 63.0, "disk_usage": 83.0, "load_1m": 0.8,
    "service_count": 3,
    "servers": {"online": 3, "attention": 0, "offline": 0},
    "last_seen": "2026-07-08 14:00:00"
  }
]

호스트 상세 조회

curl -s http://localhost:8009/api/v1/hosts/b1f2... -H "X-API-Key: 설정한_키"
{
  "id": "b1f2...", "hostname": "prod-01", "status": "warn", "is_active": true,
  "cpu_usage": 40, "memory_usage": 63, "disk_usage": 83, "load_1m": 0.8,
  "groups": [
    {"key": "db", "label": "DB", "status": "crit", "services": [
      {"type": "postgres", "name": "payment-db", "runtime": "docker",
       "status": "up", "level": "crit",
       "reasons": ["캐시 히트율 88.0%", "커넥션 48/50 (96%)"], "issue_duration": "5분째",
       "metrics": {"cache_hit_ratio": 88.0, "active_connections": 48, "total_connections": 50}}
    ]}
  ]
}

최근 발생 알림 조회

대시보드 하단 "최근 알림" 타임라인과 같은 데이터입니다. 인메모리 누적분이라 일일 리포트 발송 시 초기화되고, 백엔드 재시작 시 사라집니다.

curl -s "http://localhost:8009/api/v1/incidents?limit=20" -H "X-API-Key: 설정한_키"
[
  {"ts": "2026-07-13 10:30:01", "level": "ok",
   "title": "payment · payment-server (fastapi)",
   "reasons": ["정상으로 복구되었습니다"], "recovered": true},
  {"ts": "2026-07-13 10:22:33", "level": "crit",
   "title": "payment · payment-server (fastapi)",
   "reasons": ["HTTP 500"], "recovered": false}
]

임의 메시지 텔레그램 전송

배포 스크립트·점검 공지 등 외부 시스템에서 알림 채널을 재사용할 수 있습니다. 텔레그램 HTML 서식(<b>, <i>, <code>)을 지원합니다.

curl -s -X POST http://localhost:8009/api/v1/notify/message \
  -H "X-API-Key: 설정한_키" -H "Content-Type: application/json" \
  -d '{"text": "<b>점검 안내</b>\n22:00~22:30 서비스가 잠시 중단됩니다."}'
# → {"sent": true}   (텔레그램 미설정 시 {"sent": false, "detail": "..."})

8.데이터베이스

SQLite 파일 1개(data/monitors.db)에 모든 데이터가 저장됩니다. 스키마는 앱 기동 시 자동 생성·마이그레이션됩니다.

8.1테이블 구조

hosts (호스트 1대 = 1행, hostname 유일) └─ host_metrics : 시스템 메트릭 시계열 (CPU/MEM/DISK/Load/네트워크/디스크I/O) └─ services (호스트당 N개, (host_id, type, name) 유일) └─ service_metrics : 서비스 메트릭 시계열 (status + type별 지표 JSON)
테이블주요 컬럼비고
hostsid(UUID), hostname, ip_address, os_info, is_active호스트 삭제 시 하위 데이터 CASCADE 삭제
host_metricscpu/memory/disk_usage, load_1m/5m/15m, bytes_sent/recv, disk_read/write_bps, timestamptimestamp는 에이전트 수집 시각(버퍼 재전송 시에도 정확)
servicesid(UUID), category, type, name, runtime, container, imagecategory는 type에서 자동 산정
service_metricsstatus, metrics_json, timestamptype별 지표를 JSON 그대로 보존

직접 조회 예시:

sqlite3 monitor/data/monitors.db \
  "SELECT timestamp, cpu_usage, memory_usage FROM host_metrics
   ORDER BY id DESC LIMIT 10;"

8.2백업과 정리

# 온라인 백업 (서비스 중단 없이 안전)
sqlite3 monitor/data/monitors.db ".backup monitor/data/backup-$(date +%Y%m%d).db"

# 오래된 메트릭 정리 (예: 30일 이전) — 필요 시 cron 등록
sqlite3 monitor/data/monitors.db "
  DELETE FROM host_metrics    WHERE timestamp < datetime('now', '-30 days');
  DELETE FROM service_metrics WHERE timestamp < datetime('now', '-30 days');
  VACUUM;"
i

메트릭은 5초 주기로 계속 쌓입니다(호스트당 하루 약 1.7만 행 + 서비스당 1.7만 행). 수개월 이상 운영한다면 위 정리 쿼리를 주기적으로 실행하는 것을 권장합니다.

9.운영

9.1상태 레벨과 임계값

수집된 지표로 ok · warn · crit을 판정합니다. 여러 조건이 겹치면 가장 나쁜 레벨이 적용되고, 호스트 카드는 시스템+서비스 전체의 최악 레벨로 롤업됩니다.

대상주의(warn)위험(crit)
호스트 CPU/MEM/DISK≥ 75%≥ 90%
서비스 statusdegraded, restarting, unhealthydown, exited, dead
컨테이너재시작 ≥ 5회, 메모리 ≥ 75%정지 상태, 메모리 ≥ 90%, 헬스체크 unhealthy
postgres 캐시 히트율< 95%< 90%
postgres 데드락> 0≥ 5
postgres 죽은 튜플1,000개 이상이면서 ≥ 10%1,000개 이상이면서 ≥ 25%
postgres/mysql 연결 사용률≥ 80%≥ 95%
redis 히트율< 95%< 90%
HTTP 앱 상태 코드4xx5xx
HTTP 앱 응답 지연≥ 1,000ms≥ 3,000ms
i

죽은 튜플은 절대량 하한(1,000개)을 함께 봅니다 — 행이 수백 개뿐인 소형 DB에서는 죽은 튜플 몇 개만으로 비율이 10%를 넘어 의미 없는 경고가 반복되기 때문입니다. 하한은 app/levels.pyDEAD_TUPLES_MIN으로 조정합니다 (대시보드 쪽 DEAD_MIN도 동일 값으로).

임계값을 바꾸려면 app/levels.py(레벨 판정)와 app/alerts.py(사유 문구)를 수정한 뒤 재기동하세요.

9.2오프라인 판정

백그라운드 스윕이 OFFLINE_SWEEP_INTERVAL(5초)마다 각 호스트의 마지막 수신 시각을 확인합니다. 판정은 두 단계입니다:

  • 화면 표시OFFLINE_THRESHOLD_SEC(15초)를 넘기면 대시보드에서 오프라인(회색)으로 표시됩니다. 재수신되면 자동 복귀합니다.
  • 텔레그램 알림OFFLINE_ALERT_CONFIRM_SEC(60초) 이상 연속으로 수신이 없어야 ⚫ 알림을 보냅니다. 에이전트는 수집(도커 stats·DB 조회 등)에 걸리는 시간만큼 전송 간격이 벌어질 수 있어, 표시 임계값(15초)만으로 알림을 보내면 살아 있는 호스트에도 오탐 알림이 반복될 수 있기 때문입니다.
i

에이전트의 COLLECT_INTERVAL_SEC보다 두 임계값 모두 충분히 커야 합니다. 실제 전송 간격은 수집 주기 + 수집 소요 시간이므로, 수집 주기를 늘렸다면 OFFLINE_THRESHOLD_SEC은 실제 전송 간격의 3배, OFFLINE_ALERT_CONFIRM_SEC은 6배 정도를 권장합니다.

9.3보안 권장 사항

  • 기본 MONITORING_API_KEY(secret_monitoring_key)를 강력한 값으로 교체하고 모든 에이전트에 동일 적용
  • 8009 포트는 방화벽에서 에이전트 서버 대역과 관리자에게만 허용
  • 대시보드는 인증이 없으므로 외부 공개 시 리버스 프록시(nginx 등)에서 Basic Auth·IP 제한 권장
  • .env(토큰·키 포함)는 git에 커밋 금지

9.4트러블슈팅

증상확인 사항
대시보드가 안 열림 docker ps로 컨테이너 확인 → docker logs monitor-backend에서 기동 오류 확인 → 8009 방화벽
호스트가 안 나타남 에이전트 쪽 문제일 가능성이 높음 — 에이전트 로그에 전송 성공이 찍히는지부터 확인 (에이전트 매뉴얼 6.4)
API가 401을 반환 X-API-Key 헤더 누락 또는 MONITORING_API_KEY 불일치
텔레그램 알림이 안 옴 기동 로그에 [telegram] 알림 활성화됨이 있는지 → 없으면 토큰/chat_id 미설정. POST /api/v1/notify/message로 전송 테스트 → {"sent": false}면 로그의 [telegram] 전송 실패 사유 확인 (잘못된 chat_id는 400, 봇 차단은 403)
알림이 너무 자주 옴 임계값 경계에서 상태가 진동하는 경우 — 해당 지표의 임계값을 조정하거나(app/levels.py), 복구 알림을 끄기(ALERT_RECOVERY=false)
호스트가 온라인인데 삭제하고 싶음 정상 동작 — 먼저 해당 서버의 에이전트를 중지해 오프라인으로 만든 뒤 삭제 (5.5절)
시간이 이상하게 표시됨 저장은 UTC, 표시·알림은 KST 기준 — 서버 시계(NTP) 동기화 확인
데이터 파일이 계속 커짐 오래된 메트릭 정리 쿼리 실행 (8.2절)