Skip to Content

Matrix

한 줄 소개: AXE Labs 내부 인프라 (Docker 컨테이너 · HTTP 엔드포인트 · Cloudflare tunnel · 디스크) 의 health 를 1 분 주기로 수집하여 (a) axe.axelabs.ai/matrix 상태 보드, (b) acked_at IS NULL alert 큐, (c) Blueprint 에이전트가 MCP 5 도구로 조회 — 의 3 가지 surface 로 노출하는 첫 Rust 서비스 (D-matrix-1).

기술 스택

항목
언어Rust 2024 edition (toolchain rust:1.95-slim)
HTTP frameworkaxum 0.8 + tower-http (CORS)
Async runtimetokio 1 (full)
DBPostgreSQL 16 (alpine, ICU ko-KR) + sqlx 0.8 (runtime-tokio + tls-rustls)
Docker APIbollard 0.18 (container health 조회)
HTTP clientreqwest 0.12 (rustls, 5s timeout) — endpoint probe
인증jsonwebtoken 9 (HS256 JWT, MATRIX_JWT_SECRET) — 현재 router 미부착, known-gaps 참조
스케줄링tokio-cron-scheduler 0.13 + tokio sleep loop
로깅tracing + tracing-subscriber (env-filter + json formatter)
Migration코드 인-라인 (db.rs migrate(), CREATE TABLE IF NOT EXISTS)

소스: /Users/axe/matrix/src/ (~600 LOC, 6 modules: api · auth · collector · config · db · mcp)

포트

포트용도
3901PostgreSQL 16 (matrix-postgres)
3910MCP HTTP blue (matrix-mcp-blue, alias matrix-mcp active)
3911MCP HTTP green (matrix-mcp-green, passive)
3912axe-matrix-proxy (Caddy blue/green selector, 127.0.0.1 bind only)

cloudflared origin → 외부 https://axe.axelabs.ai/matrix + https://axelabs.ai/matrix (둘 다 같은 path 라우팅). matrix.axelabs.ai 서브도메인은 미등록 — DNS resolve 실패. 정식 경로는 axe.axelabs.ai/matrix.

3 가지 surface

  1. MCP (POST /matrix/mcp) — JSON-RPC 2.0 over HTTP, 5 tools. Blueprint / Claude 에이전트가 도구로 호출
  2. REST (GET /matrix, /matrix/api/status, /matrix/api/alerts) — 상태 보드 (인증 없음, 의도된 공개)
  3. Health probe (GET /health, /health/ready) — Docker healthcheck + 외부 모니터링

/matrix/mcp 는 코드상 auth.rs::auth_middleware 정의되어 있으나 api.rs::router() 에 부착되지 않음. 현재 anonymous 호출 가능. B-matrix-mcp-auth-enforce 참조.

MCP Tools (5 개)

src/mcp.rs:91-150handle_tools_list() 기준. protocolVersion: 2025-03-26, serverInfo.name: "matrix", serverInfo.version: env!("CARGO_PKG_VERSION") (현재 0.1.0).

Tool입력설명
get_status가장 최근 collector cycle 의 전체 health 보고 (in-memory last_check). 한 번도 안 돈 직후엔 "no check results yet"
get_service_historyservice (string, required), hours (int, default 24)특정 서비스의 시계열 — check_results.report JSONB 에서 해당 name 의 status/detail 추출 (최근 100 rows)
list_alertsinclude_acked (bool, default false)unacked alert 50 개 (or 전체 50). UUID + service + severity + message + created_at + acked_at/by
acknowledge_alertalert_id (UUID, required), acked_by (string, default "operator")UPDATE alerts SET acked_at = now(), acked_by = $1 WHERE id = $2 AND acked_at IS NULL — 이미 ack 된 항목은 no-op
get_uptime_reportdays (int, default 7)기간 내 모든 cycle 의 per-service pass/total 카운트 + uptime% (소수점 2 자리)

REST endpoints

메서드경로인증설명
GET/health{"status":"ok","service":"matrix"} (DB 미점검)
GET/health/ready{"status":"ok","db":"connected"} 또는 503 + {"db":"<err>"}. Docker healthcheck 가 사용
GET/matrixlanding (상태 보드, 미구현 placeholder 가능성)
GET/matrix/api/status최근 cycle 의 JSON 전체 — get_status MCP 와 동일 데이터
GET/matrix/api/alertsunacked 20 개 alert
POST/matrix/mcp— (의도는 JWT)MCP JSON-RPC. initialize / tools/list / tools/call 처리

데이터 모델

src/db.rs:14-39 의 인-라인 migration (CREATE TABLE IF NOT EXISTS). 3 테이블 + 2 인덱스.

테이블컬럼역할
check_resultsid UUID PK · ts TIMESTAMPTZ · duration_ms INT · overall TEXT (pass/fail) · report JSONBcollector cycle 의 전체 보고서 (모든 service check 결과 array 포함)
servicesname PK · svc_type · config JSONB · created_at(현재 미사용 — 향후 동적 등록용)
alertsid UUID PK · service · severity (default error) · message · created_at · acked_at · acked_byfailure 1 회 발생 시 INSERT, 동일 서비스의 unacked alert 이 있으면 no-op (중복 방지)

인덱스: idx_check_results_ts (DESC), idx_alerts_unacked (partial WHERE acked_at IS NULL).

Collector — 무엇을 보는가

src/collector.rs::run_loop()MATRIX_CHECK_INTERVAL 초마다 (default 30, D-matrix-2 에서 60→30), run_check() 가 5 종류 점검 병합:

종류함수대상판정
Docker containercheck_dockerbollard 로 all=false (실행 중) 컨테이너 list. status 문자열에 healthy / unhealthy 포함 검사. matrix- 접두는 자가 모니터링 회피로 skipunhealthy = fail, healthy or running = pass
HTTP endpointcheck_http2 개 — blueprint-http (host:3100/api/health) + frame-mcp-http (host:3710/health, alive-only). cortex-fe/cortex-be 는 개발 중이라 제거 (commit 96cf758, 재가동 시 재활성)상태코드 일치 = pass; frame 만 응답 있으면 pass
Cloudflare tunnelcheck_tunnels3 개 — tunnel-artemis, tunnel-blueprint, tunnel-mysrt (*.axellc.com)200/301/302 = pass, 그 외 = warn, unreachable = fail
Diskcheck_diskdf -h / 의 root 디스크 사용률≥90% = warn
WAN/인터넷check_wan3 프로브 동시(tokio::join!) — wan-gateway (공유기 ICMP), wan-internet (MATRIX_WAN_TARGET ICMP, RTT+손실%), wan-dns (MATRIX_DNS_HOST 해석 시간). D-matrix-2unreachable = fail. 귀책 판별: gateway ↑ + internet ↓ ⇒ ISP/WAN fault (warning 발생), gateway ↓ + internet ↓ ⇒ 댁내 링크/WiFi

호스트 도달은 모두 host.docker.internal 경유. failure 시 create_alert() 가 동일 서비스의 unacked alert 가 없을 때만 INSERT (중복 방지). cycle 결과는 항상 check_results 에 INSERT.

WAN 프로브 (D-matrix-2): wan-* 결과는 기존 check_results JSONB 에 그대로 들어가 별도 스키마 변경 없이 get_service_history / get_uptime_report / 상태 보드 / alert 에 자동 노출. ICMP 는 컨테이너에 cap_add: NET_RAW + 런타임 이미지의 iputils-ping 으로 권한상승 없이 가능 (Docker Desktop NAT 통과 + 공유기/외부 도달 검증 2026-06-03). 게이트웨이 IP 는 노드별로 다르므로 MATRIX_LAN_GATEWAY env 로 주입.

함정 (2026-05-26 발견 → 같은 날 fix): blueprint-http URL 이 :3110 (미 listening) 으로 25 분+ 연속 FAILED 누적. 정정: :3100/api/health (Blueprint Next.js dev). 동일 세션에서 cortex-fe/cortex-be 도 검증 — cortex backend (:3210) 는 실제 down, cortex frontend (:3200) 는 listening 하지만 root path 빈 응답 → 두 항목은 valid alert (cortex 측 점검 별도 필요). B-matrix-collector-port-fix

환경 변수

src/config.rs::Config::from_env() 기준. .env.local (env_file) 으로 vault → 컨테이너 dump (D-ops-18 패턴).

MATRIX_PORT=3910 # default 3910 MATRIX_DATABASE_URL=postgres://matrix:<pw>@postgres:5432/matrix MATRIX_DB_PASSWORD= # compose 가 ${MATRIX_DB_PASSWORD:?required} MATRIX_JWT_SECRET= # default "dev-secret-change-me" — production 미설정 시 위험 MATRIX_CHECK_INTERVAL=30 # 초 (D-matrix-2: 60→30, 끊김 해상도 향상) MATRIX_CUSTOMER_ID=axe # multi-tenant 마커 MATRIX_DEPLOY_COLOR=blue|green # blue/green 식별 MATRIX_LAN_GATEWAY=192.168.55.1 # wan-gateway 프로브 대상 (공유기 IP, 노드별 상이) MATRIX_WAN_TARGET=1.1.1.1 # wan-internet 프로브 대상 (공인 anycast) MATRIX_DNS_HOST=google.com # wan-dns 해석 테스트 호스트

MATRIX_LAN_GATEWAY / MATRIX_WAN_TARGET / MATRIX_DNS_HOST 는 비밀이 아니라 노드별 설정값 — secrets 표/vault 등재 불필요 (default 존재). 단 MATRIX_LAN_GATEWAY 는 DHCP 로 바뀔 수 있어 노드 셋업 시 확인 (D-matrix-2).

/architecture/secrets 의 service secrets 표 등재 (matrix .env.local = DB password + JWT secret + console API token 3 종).

Blue/green 운영

  • matrix-mcp-bluematrix-mcp-green 가 동일 image (compose 의 build: .) 로 동시 실행. blue 만 matrix-mcp network alias 보유 → axe-matrix-proxy (Caddyfile 의 reverse_proxy matrix-mcp:3910) 가 항상 blue 로 forward.
  • swap = compose 의 alias 를 green 으로 옮긴 후 docker compose up -d --no-deps matrix-mcp-green → 검증 → blue 도 업데이트. frame · hive 와 동일 패턴.
  • 현재 상태 (2026-05-26): 두 컨테이너 동일 코드 (build 동시), 둘 다 healthy, 3 일 가동.

운영 노트 · 알려진 함정

  • Git 미커밋 ✅ — f73492d (initial) + 48a301b (fix) 두 commit 으로 history 회복 (2026-05-26).
  • Stale build (2026-05-23) ✅ — matrix_info 함수 미정의 (E0425) 였던 게 root cause. 같은 날 stub 추가 + 무중단 rebuild.
  • JWT 미적용 ✅ — /matrix/mcpmiddleware::from_fn(auth_middleware) 부착 (commit 96cf758). REST + health 는 anonymous 유지 (의도된 공개 status board). 검증: no-auth POST → 401 “missing bearer token”, REST → 200. production 호출 client 0 (access log 0 + Blueprint repo 미참조) 확인 후 안전 부착.
  • 자가 모니터링 회피: collector 가 matrix- 접두 컨테이너를 skip. matrix-postgres 도 skip 됨 — 의도된 단순화, 그러나 DB 가 죽으면 /health/ready 자체가 503 떨어지므로 외부 healthcheck 로 보완.
  • 39xx 범위 공유: axelabs 회사 홈 (3900) 과 matrix (3901/3910/3911/3912) 가 같은 범위에서 공존. CLAUDE.md / /ops/inventory#포트-할당 에 명시.
  • 부수 발견 — cortex 측 valid alert ✅ resolved by removal — cortex 가 개발 중이라 collector endpoint list 에서 cortex-fe / cortex-be 제거 (commit 96cf758, src/collector.rs:181). 재가동 시 다시 활성화. 누적 unacked alert 2 row (acked_by='cortex-removed-from-collector-2026-05-26') ack 처리.

관련 문서

Last updated on