22 KiB
22 KiB
Fleet Management 시스템 구축 계획서
개요
목표: 10,000개 이상의 온프레미스 공장 서버를 중앙에서 효율적으로 관리
현재 상태: 1개 업체 (스피폭스), Watchtower 기반 자동 업데이트
목표 상태: 10,000개 업체, 실시간 모니터링 & 원격 제어 가능
목차
1. 아키텍처 설계
1.1 전체 아키텍처
┌─────────────────────────────────────────────────────────────────────────┐
│ Vexplor 글로벌 플랫폼 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Web UI │ │ Fleet API │ │ Config │ │ Monitoring │ │
│ │ (Dashboard) │ │ Gateway │ │ Server │ │ & Alerts │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ └────────────────┼────────────────┼────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Message │ │ Device │ │
│ │ Broker │ │ Registry │ │
│ │ (MQTT) │ │ (Redis) │ │
│ └──────┬──────┘ └─────────────┘ │
│ │ │
└──────────────────────────┼────────────────────────────────────────────┘
│
│ MQTT (TLS)
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Agent │ │ Agent │ │ Agent │
│ 스피폭스 │ │ 엔키드 │ │ 고객 N │
└─────────┘ └─────────┘ └─────────┘
│ │ │
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Vexplor │ │ Vexplor │ │ Vexplor │
│ Backend │ │ Backend │ │ Backend │
│Frontend │ │Frontend │ │Frontend │
│ DB │ │ DB │ │ DB │
└─────────┘ └─────────┘ └─────────┘
1.2 통신 흐름
[공장 서버 → 글로벌]
1. Agent 시작 시 MQTT 연결 (Outbound Only)
2. 주기적 Heartbeat 전송 (30초)
3. 상태/메트릭 보고 (5분)
4. 로그 전송 (선택적)
[글로벌 → 공장 서버]
1. 업데이트 명령
2. 설정 변경
3. 재시작 명령
4. 데이터 요청
2. Phase별 구현 계획
Phase 1: 기반 구축 (1~10개 업체)
기간: 2주
| 구현 항목 | 설명 | 우선순위 |
|---|---|---|
| Device Registry API | 디바이스 등록/조회 | P0 |
| Heartbeat API | 상태 보고 수신 | P0 |
| 기본 대시보드 | 디바이스 목록/상태 표시 | P1 |
| Agent 기본 버전 | Heartbeat 전송 기능 | P0 |
산출물:
POST /api/fleet/devices/registerPOST /api/fleet/devices/heartbeatGET /api/fleet/devices- Agent Docker 이미지
Phase 2: 실시간 통신 (10~100개 업체)
기간: 4주
| 구현 항목 | 설명 | 우선순위 |
|---|---|---|
| MQTT 브로커 설치 | Eclipse Mosquitto | P0 |
| Agent MQTT 연결 | 상시 연결 유지 | P0 |
| 원격 명령 기능 | 업데이트/재시작 명령 | P1 |
| 실시간 상태 업데이트 | WebSocket → 대시보드 | P1 |
산출물:
- MQTT 브로커 (Docker)
- Agent v2 (MQTT 지원)
- 원격 명령 UI
Phase 3: 배포 관리 (100~500개 업체)
기간: 6주
| 구현 항목 | 설명 | 우선순위 |
|---|---|---|
| 버전 관리 시스템 | 릴리즈 버전 관리 | P0 |
| 단계적 롤아웃 | Canary 배포 | P0 |
| 롤백 기능 | 이전 버전 복구 | P0 |
| 그룹 관리 | 지역/업종별 그룹핑 | P1 |
| 배포 스케줄링 | 시간대별 배포 | P2 |
산출물:
- Release Management UI
- Deployment Pipeline
- Rollback 자동화
Phase 4: 모니터링 강화 (500~2,000개 업체)
기간: 6주
| 구현 항목 | 설명 | 우선순위 |
|---|---|---|
| 메트릭 수집 | CPU/Memory/Disk | P0 |
| 알림 시스템 | Slack/Email/SMS | P0 |
| 로그 중앙화 | 원격 로그 수집 | P1 |
| 이상 탐지 | 자동 장애 감지 | P1 |
| SLA 대시보드 | 가용성 리포트 | P2 |
산출물:
- Prometheus + Grafana
- Alert Manager
- Log Aggregator (Loki)
Phase 5: 대규모 확장 (2,000~10,000개 업체)
기간: 8주
| 구현 항목 | 설명 | 우선순위 |
|---|---|---|
| MQTT 클러스터링 | 고가용성 브로커 | P0 |
| 샤딩 | 지역별 분산 | P0 |
| 자동 프로비저닝 | 신규 업체 자동 설정 | P1 |
| API Rate Limiting | 과부하 방지 | P1 |
| 멀티 리전 | 글로벌 분산 | P2 |
산출물:
- MQTT Cluster (EMQX)
- Regional Gateway
- Auto-provisioning System
3. 핵심 컴포넌트 상세
3.1 Fleet Agent (공장 서버에 설치)
┌─────────────────────────────────────────┐
│ Fleet Agent │
├─────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ │
│ │ MQTT │ │ Command │ │
│ │ Client │ │ Executor │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ │
│ │ Core Controller │ │
│ └─────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Metrics │ │ Docker │ │
│ │ Collector │ │ Manager │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────┘
주요 기능:
- MQTT 연결 유지 (자동 재연결)
- Heartbeat 전송 (30초)
- 시스템 메트릭 수집
- Docker 컨테이너 관리
- 원격 명령 실행
3.2 Fleet Manager (글로벌 서버)
주요 기능:
- 디바이스 등록/인증
- 상태 모니터링
- 배포 오케스트레이션
- 설정 관리
- 알림 발송
3.3 Message Broker (MQTT)
선택지:
| 옵션 | 장점 | 단점 | 추천 규모 |
|---|---|---|---|
| Mosquitto | 가볍고 간단 | 클러스터링 어려움 | ~1,000 |
| EMQX | 클러스터링, 고성능 | 복잡함 | 1,000~100,000 |
| HiveMQ | 엔터프라이즈급 | 비용 | 100,000+ |
권장: Phase 13은 Mosquitto, Phase 45는 EMQX
4. 데이터베이스 스키마
4.1 디바이스 테이블
-- 디바이스 (공장 서버) 정보
CREATE TABLE fleet_devices (
id SERIAL PRIMARY KEY,
device_id VARCHAR(50) UNIQUE NOT NULL, -- 고유 식별자
company_code VARCHAR(20) NOT NULL, -- 회사 코드
device_name VARCHAR(100), -- 표시 이름
-- 연결 정보
ip_address VARCHAR(45),
last_seen_at TIMESTAMPTZ,
is_online BOOLEAN DEFAULT false,
-- 버전 정보
agent_version VARCHAR(20),
app_version VARCHAR(20),
-- 시스템 정보
os_info JSONB,
hardware_info JSONB,
-- 그룹/태그
device_group VARCHAR(50),
tags JSONB DEFAULT '[]',
-- 메타
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
FOREIGN KEY (company_code) REFERENCES company_info(company_code)
);
CREATE INDEX idx_fleet_devices_company ON fleet_devices(company_code);
CREATE INDEX idx_fleet_devices_online ON fleet_devices(is_online);
CREATE INDEX idx_fleet_devices_group ON fleet_devices(device_group);
4.2 Heartbeat 로그 테이블
-- Heartbeat 기록 (TimescaleDB 권장)
CREATE TABLE fleet_heartbeats (
id BIGSERIAL,
device_id VARCHAR(50) NOT NULL,
received_at TIMESTAMPTZ DEFAULT NOW(),
-- 상태
status VARCHAR(20), -- OK, WARNING, ERROR
uptime_seconds BIGINT,
-- 메트릭
cpu_percent DECIMAL(5,2),
memory_percent DECIMAL(5,2),
disk_percent DECIMAL(5,2),
-- 컨테이너 상태
containers JSONB,
PRIMARY KEY (device_id, received_at)
);
-- TimescaleDB 하이퍼테이블 변환 (선택)
-- SELECT create_hypertable('fleet_heartbeats', 'received_at');
4.3 배포 테이블
-- 릴리즈 버전 관리
CREATE TABLE fleet_releases (
id SERIAL PRIMARY KEY,
version VARCHAR(20) NOT NULL,
release_type VARCHAR(20), -- stable, beta, hotfix
-- 이미지 정보
backend_image VARCHAR(200),
frontend_image VARCHAR(200),
agent_image VARCHAR(200),
-- 변경사항
changelog TEXT,
-- 상태
status VARCHAR(20) DEFAULT 'draft', -- draft, testing, released, deprecated
released_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 배포 작업
CREATE TABLE fleet_deployments (
id SERIAL PRIMARY KEY,
release_id INTEGER REFERENCES fleet_releases(id),
-- 배포 대상
target_type VARCHAR(20), -- all, group, specific
target_value VARCHAR(100), -- 그룹명 또는 device_id
-- 롤아웃 설정
rollout_strategy VARCHAR(20), -- immediate, canary, scheduled
rollout_percentage INTEGER,
scheduled_at TIMESTAMPTZ,
-- 상태
status VARCHAR(20) DEFAULT 'pending',
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
-- 결과
total_devices INTEGER,
success_count INTEGER DEFAULT 0,
failed_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 개별 디바이스 배포 상태
CREATE TABLE fleet_deployment_status (
id SERIAL PRIMARY KEY,
deployment_id INTEGER REFERENCES fleet_deployments(id),
device_id VARCHAR(50),
status VARCHAR(20) DEFAULT 'pending', -- pending, downloading, installing, completed, failed
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
error_message TEXT,
UNIQUE(deployment_id, device_id)
);
4.4 알림 규칙 테이블
-- 알림 규칙
CREATE TABLE fleet_alert_rules (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
-- 조건
condition_type VARCHAR(50), -- offline, version_mismatch, high_cpu, etc.
condition_value JSONB,
threshold_minutes INTEGER, -- 조건 지속 시간
-- 알림 채널
notify_channels JSONB, -- ["slack", "email"]
notify_targets JSONB, -- 수신자 목록
-- 상태
is_enabled BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 알림 기록
CREATE TABLE fleet_alerts (
id SERIAL PRIMARY KEY,
rule_id INTEGER REFERENCES fleet_alert_rules(id),
device_id VARCHAR(50),
alert_type VARCHAR(50),
message TEXT,
severity VARCHAR(20), -- info, warning, critical
-- 해결 상태
status VARCHAR(20) DEFAULT 'open', -- open, acknowledged, resolved
resolved_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
5. API 설계
5.1 Device Management API
# 디바이스 등록
POST /api/fleet/devices/register
Request:
device_id: string (required)
company_code: string (required)
device_name: string
agent_version: string
os_info: object
Response:
success: boolean
data:
device_id: string
mqtt_credentials:
broker_url: string
username: string
password: string
# 디바이스 목록 조회
GET /api/fleet/devices
Query:
company_code: string
is_online: boolean
device_group: string
page: number
limit: number
Response:
success: boolean
data: Device[]
pagination: { total, page, limit }
# 디바이스 상세 조회
GET /api/fleet/devices/:deviceId
Response:
success: boolean
data:
device: Device
recent_heartbeats: Heartbeat[]
recent_alerts: Alert[]
5.2 Heartbeat API
# Heartbeat 전송
POST /api/fleet/devices/:deviceId/heartbeat
Request:
status: string
uptime_seconds: number
metrics:
cpu_percent: number
memory_percent: number
disk_percent: number
containers:
- name: string
status: string
version: string
Response:
success: boolean
data:
commands: Command[] # 대기 중인 명령 반환
5.3 Deployment API
# 배포 생성
POST /api/fleet/deployments
Request:
release_id: number
target_type: "all" | "group" | "specific"
target_value: string
rollout_strategy: "immediate" | "canary" | "scheduled"
rollout_percentage: number
scheduled_at: datetime
Response:
success: boolean
data:
deployment_id: number
estimated_devices: number
# 배포 상태 조회
GET /api/fleet/deployments/:deploymentId
Response:
success: boolean
data:
deployment: Deployment
status_summary:
pending: number
in_progress: number
completed: number
failed: number
device_statuses: DeploymentStatus[]
# 배포 롤백
POST /api/fleet/deployments/:deploymentId/rollback
Response:
success: boolean
data:
rollback_deployment_id: number
5.4 Command API
# 원격 명령 전송
POST /api/fleet/devices/:deviceId/commands
Request:
command_type: "update" | "restart" | "config" | "logs"
payload: object
Response:
success: boolean
data:
command_id: string
status: "queued"
# 명령 결과 조회
GET /api/fleet/commands/:commandId
Response:
success: boolean
data:
command_id: string
status: "queued" | "sent" | "executing" | "completed" | "failed"
result: object
6. 기술 스택
6.1 글로벌 플랫폼
| 컴포넌트 | 기술 | 비고 |
|---|---|---|
| Fleet API | Node.js (기존 backend-node 확장) | 기존 코드 재사용 |
| Message Broker | Mosquitto → EMQX | 단계적 전환 |
| Device Registry | Redis | 빠른 조회 |
| Database | PostgreSQL | 기존 DB 확장 |
| Time-series DB | TimescaleDB | Heartbeat 저장 |
| Monitoring | Prometheus + Grafana | 메트릭 시각화 |
| Log | Loki | 로그 중앙화 |
| Alert | AlertManager | 알림 관리 |
6.2 Fleet Agent
| 컴포넌트 | 기술 | 비고 |
|---|---|---|
| Runtime | Go 또는 Node.js | 가볍고 안정적 |
| MQTT Client | Paho MQTT | 표준 라이브러리 |
| Docker SDK | Docker API | 컨테이너 관리 |
| Metrics | gopsutil | 시스템 메트릭 |
6.3 대시보드
| 컴포넌트 | 기술 | 비고 |
|---|---|---|
| UI Framework | Next.js (기존) | 기존 코드 확장 |
| Real-time | Socket.io | 실시간 상태 |
| Charts | Recharts | 메트릭 시각화 |
| Map | Leaflet | 지역별 표시 |
7. 일정 및 마일스톤
7.1 전체 일정
2025 Q1 2025 Q2 2025 Q3
│ │ │
├── Phase 1 (2주) ─────────┤ │
│ Device Registry │ │
│ Heartbeat API │ │
│ 기본 대시보드 │ │
│ │ │
│ ├── Phase 2 (4주) ──────────┤ │
│ │ MQTT 브로커 │ │
│ │ Agent v2 │ │
│ │ 원격 명령 │ │
│ │ │ │
│ │ ├── Phase 3 (6주) ──────┤
│ │ │ 버전 관리 │
│ │ │ Canary 배포 │
│ │ │ 롤백 │
│ │ │ │
7.2 상세 마일스톤
| 마일스톤 | 목표 | 완료 기준 | 예상 일정 |
|---|---|---|---|
| M1 | Device Registry | 디바이스 등록/조회 API 완료 | 1주차 |
| M2 | Heartbeat | 상태 보고 & 저장 완료 | 2주차 |
| M3 | Basic Dashboard | 디바이스 목록 UI 완료 | 2주차 |
| M4 | MQTT Setup | 브로커 설치 & 연결 테스트 | 4주차 |
| M5 | Agent v2 | MQTT 기반 Agent 완료 | 6주차 |
| M6 | Remote Command | 업데이트/재시작 명령 완료 | 8주차 |
| M7 | Release Mgmt | 버전 관리 UI 완료 | 10주차 |
| M8 | Canary Deploy | 단계적 배포 완료 | 14주차 |
8. 리스크 및 대응
8.1 기술적 리스크
| 리스크 | 영향 | 확률 | 대응 |
|---|---|---|---|
| MQTT 연결 불안정 | 높음 | 중간 | 자동 재연결, 오프라인 큐 |
| 대량 동시 접속 | 높음 | 높음 | 클러스터링, 로드밸런싱 |
| 보안 취약점 | 높음 | 낮음 | TLS 필수, 인증 강화 |
| 네트워크 단절 | 중간 | 높음 | 로컬 캐시, 재전송 로직 |
8.2 운영 리스크
| 리스크 | 영향 | 확률 | 대응 |
|---|---|---|---|
| 잘못된 배포 | 높음 | 중간 | Canary 배포, 자동 롤백 |
| 모니터링 누락 | 중간 | 중간 | 다중 알림 채널 |
| 버전 파편화 | 중간 | 높음 | 강제 업데이트 정책 |
9. 다음 단계
즉시 시작할 작업 (Phase 1)
-
Device Registry 테이블 생성
fleet_devices테이블 마이그레이션
-
Fleet API 엔드포인트 개발
POST /api/fleet/devices/registerPOST /api/fleet/devices/:deviceId/heartbeatGET /api/fleet/devices
-
Agent 기본 버전 개발
- Docker 이미지로 배포
- 주기적 Heartbeat 전송
-
대시보드 기본 화면
- 디바이스 목록
- 온라인/오프라인 상태 표시
부록
A. MQTT 토픽 설계
vexplor/
├── devices/
│ ├── {device_id}/
│ │ ├── status # 상태 보고 (Agent → Server)
│ │ ├── metrics # 메트릭 보고 (Agent → Server)
│ │ ├── commands # 명령 수신 (Server → Agent)
│ │ └── responses # 명령 응답 (Agent → Server)
│ │
├── broadcasts/
│ ├── all # 전체 공지
│ └── groups/{group} # 그룹별 공지
│
└── system/
├── announcements # 시스템 공지
└── maintenance # 점검 알림
B. Agent 설정 파일
# /opt/vexplor/agent/config.yaml
device:
id: "SPIFOX-001"
company_code: "SPIFOX"
name: "스피폭스 메인 서버"
mqtt:
broker: "mqtts://mqtt.vexplor.com:8883"
username: "${MQTT_USERNAME}"
password: "${MQTT_PASSWORD}"
keepalive: 60
reconnect_interval: 5
heartbeat:
interval: 30 # seconds
metrics:
enabled: true
interval: 300 # 5 minutes
collect:
- cpu
- memory
- disk
- network
docker:
socket: "/var/run/docker.sock"
managed_containers:
- vexplor-backend
- vexplor-frontend
- vexplor-db