티스토리 뷰

 

“상면 배치도”를 그래픽처럼 시각화하고 모니터링할 수 있는 툴을 만들고자 하시는군요.
이를 위해 웹 기반 툴을 만드는 것이 일반적이며, 다음과 같은 구성으로 개발할 수 있습니다:


✅ 기능 요약

  1. 랙(Rack) 배치 시각화 – 실제 IDC 상면 배치도처럼 랙/서버 표시
  2. 서버 상태 실시간 모니터링 – CPU, 메모리, 디스크, 온도 등
  3. 서버 클릭 시 상세 정보 표시
  4. 이상 상태 알림 – 색상 변경, 경고 아이콘 등
  5. Drag & Drop 으로 배치 조정 가능 (옵션)

✅ 기술 스택 제안

역할기술
프론트엔드 React + TailwindCSS + D3.js / Konva.js (그래픽 표현)
백엔드 Go 또는 Python (FastAPI)
실시간 통신 WebSocket or SSE
모니터링 데이터 수집 Node Exporter + Prometheus
데이터 저장 PostgreSQL or Prometheus
배포 환경 Docker + Kubernetes (이미 익숙하시니)

✅ 예시 화면 구조


✅ 백엔드 간단 설계 예시 (Go)

go
 
 
// 서버 상태를 받아오는 API
GET /api/racks           // 전체 랙 정보
GET /api/rack/:id        // 특정 랙 정보
GET /api/server/:id      // 서버 상세

✅ 프론트엔드 예시 (React + Konva.js)

<Stage width={window.innerWidth} height={window.innerHeight}>
  <Layer>
    {racks.map(rack => (
      <Group key={rack.id}>
        <Rect
          x={rack.x}
          y={rack.y}
          width={rackWidth}
          height={rackHeight}
          fill={rack.status === 'error' ? 'red' : 'green'}
          onClick={() => selectRack(rack.id)}
        />
        <Text text={rack.name} x={rack.x} y={rack.y - 20} />
      </Group>
    ))}
  </Layer>
</Stage>

 

✅ 추가 아이디어

  • Prometheus exporter에서 데이터 실시간 수집
  • Grafana 임베딩하여 리소스 모니터링 UI 연동
  • 알람 조건 설정 및 Slack/메일 연동

원하신다면 전체 프로젝트 템플릿 형태로 만들어드릴 수 있어요.
React + Go 기반 초기 구조부터 시작

 

// src/App.jsx
import { useEffect, useState } from "react";
import { Stage, Layer, Rect, Text, Group } from "react-konva";

export default function App() {
  const [racks, setRacks] = useState([]);
  const [selectedRack, setSelectedRack] = useState(null);

  useEffect(() => {
    fetch("http://localhost:8080/api/racks")
      .then((res) => res.json())
      .then(setRacks);
  }, []);

  return (
    <div className="w-full h-screen flex">
      <div className="flex-1">
        <Stage width={window.innerWidth * 0.75} height={window.innerHeight}>
          <Layer>
            {racks.map((rack, index) => (
              <Group key={rack.id}>
                <Rect
                  x={rack.x}
                  y={rack.y}
                  width={60}
                  height={200}
                  fill={rack.status === "error" ? "red" : "green"}
                  onClick={() => setSelectedRack(rack)}
                />
                <Text text={rack.name} x={rack.x} y={rack.y - 20} />
              </Group>
            ))}
          </Layer>
        </Stage>
      </div>
      <div className="w-1/4 bg-gray-100 p-4">
        {selectedRack ? (
          <div>
            <h2 className="text-xl font-bold mb-2">{selectedRack.name}</h2>
            <p>Status: {selectedRack.status}</p>
            <p>Location: ({selectedRack.x}, {selectedRack.y})</p>
          </div>
        ) : (
          <p>랙을 선택하세요.</p>
        )}
      </div>
    </div>
  );
}
초기 React 구조를 설정했습니다.
이 코드는 react-konva를 사용하여 상면 배치도 형태로 랙을 시각화하고, 클릭 시 상세 정보를 우측에 표시합니다.
 

 


🔧 준비사항

  1. 의존성 설치 (프론트엔드)
npm install react-konva konva
 
  1. API 엔드포인트 예시 (GET /api/racks) Go 백엔드는 다음처럼 구성할 수 있습니다:
package main

import (
"encoding/json"
"net/http"
)

type Rack struct {
ID     string `json:"id"`
Name   string `json:"name"`
X      int    `json:"x"`
Y      int    `json:"y"`
Status string `json:"status"` // e.g., "normal", "error"
}

func getRacks(w http.ResponseWriter, r *http.Request) {
racks := []Rack{
{ID: "r1", Name: "Rack 1", X: 50, Y: 50, Status: "normal"},
{ID: "r2", Name: "Rack 2", X: 150, Y: 50, Status: "error"},
{ID: "r3", Name: "Rack 3", X: 250, Y: 50, Status: "normal"},
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(racks)
}

func main() {
http.HandleFunc("/api/racks", getRacks)
http.ListenAndServe(":8080", nil)
}
 

다음 단계

  • 랙 내부 서버 구성 추가
  • 실시간 상태 WebSocket 연동
  • Prometheus 연동 및 자동 데이터 수집

원하시는 방향 알려주시면 계속 확장해드릴게요. Go 백엔드 쪽도 정식으로 프로젝트 구조 만들어드릴까요?

 

나의 말:

ChatGPT의 말:

Rack-monitoring-backend

Go 백엔드 기본 구조도 설정해드렸습니다. 현재 구성은 매우 단순한 정적 데이터 API 서버입니다.


✅ 현재 구성 요약

  • /api/racks 요청 시 랙 3개의 더미 정보를 JSON으로 응답
  • localhost:8080 포트에서 실행됨

📁 향후 디렉토리 구조 예시 (확장 시)

 

rack-monitoring-backend/
├── main.go
├── handlers/
│   └── rack.go
├── models/
│   └── rack.go
├── services/
│   └── monitor.go
└── go.mod

 

🔜 다음 단계 제안

  1. 랙 상세 정보 API 추가 /api/rack/:id
  2. 서버 단위 정보 포함 (랙 내부 서버 상태)
  3. Prometheus 연동 (Node Exporter 등과 통신)
  4. WebSocket으로 실시간 데이터 전달

어떤 기능부터 확장해드릴까요?

  • 🔍 랙 내부 서버 정보 포함
  • 📡 실시간 상태 업데이트 (WebSocket)
  • 📈 Prometheus 연동

 

✅ 추가된 기능

  1. Rack 구조체 내부에 Server 리스트 포함
  2. 서버의 CPU/Memory 사용률 및 상태 포함
  3. 신규 API /api/rack/{id}
    → 특정 랙의 전체 상세 정보 (서버 목록 포함)를 응답합니다.

🔍 예시 응답 (GET /api/rack/r1)

 

{
  "id": "r1",
  "name": "Rack 1",
  "x": 50,
  "y": 50,
  "status": "normal",
  "servers": [
    {
      "id": "s1",
      "name": "Server 1",
      "cpu": 30,
      "memory": 40,
      "status": "normal"
    },
    {
      "id": "s2",
      "name": "Server 2",
      "cpu": 80,
      "memory": 90,
      "status": "warning"
    }
  ]
}
 

📌 다음 확장 제안

  • 프론트엔드에서 클릭 시 해당 랙의 서버 리스트 출력
  • 서버별 상태를 색상 아이콘으로 표현
  • 각 서버 클릭 시 리소스 차트 표시
  • Prometheus에서 실시간 데이터 수집 연동

어떤 기능부터 확장해볼까요? 프론트엔드에 이 서버 정보를 띄워보는 것부터 진행해도 좋습니다.

 

나의 말:

실시간 상태 업데이트 (WebSocket) 확장해줘

ChatGPT의 말:

Edited Rack-monitoring-backend

WebSocket을 통한 실시간 상태 업데이트 기능을 백엔드에 추가했습니다. 주요 내용은 다음과 같습니다:


✅ 추가된 API

  • GET /ws/status
    • WebSocket 업그레이드 후 일정 주기(3초)마다 서버들의 CPU/Memory 상태를 임의로 변경하고 클라이언트에 전송합니다.

🔧 사용 라이브러리

go get github.com/gorilla/websocket

📦 클라이언트 예시 (React)

 

useEffect(() => {
  const socket = new WebSocket("ws://localhost:8080/ws/status");
  socket.onmessage = (event) => {
    const updatedRacks = JSON.parse(event.data);
    setRacks(updatedRacks);
  };
  return () => socket.close();
}, []);
 

📌 다음 단계 제안

  • 클라이언트에서 상태 변화에 따라 색상/아이콘 등 시각 효과 반영
  • Prometheus 연동으로 실제 메트릭 기반으로 WebSocket 송출
  • 알림(예: Slack, 이메일) 기능 추가

원하시는 방향으로 계속 확장해드릴게요! 프론트에 WebSocket 적용할까요?

 

나의 말:

 

// main.go
package main

import (
"encoding/json"
"log"
"math/rand"
"net/http"
"os/exec"
"strings"
"time"

"github.com/gorilla/websocket"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

type PodStatus struct {
Name      string `json:"name"`
Namespace string `json:"namespace"`
CPU       int    `json:"cpu"`
Memory    int    `json:"memory"`
Status    string `json:"status"`
}

type K8sRack struct {
ID     string      `json:"id"`
Name   string      `json:"name"`
X      int         `json:"x"`
Y      int         `json:"y"`
Pods   []PodStatus `json:"pods"`
Status string      `json:"status"`
}

var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}

func getK8sDashboard(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("WebSocket upgrade error:", err)
return
}
defer conn.Close()

config, err := rest.InClusterConfig()
if err != nil {
log.Println("Failed to get in-cluster config, falling back to default")
config, err = rest.InClusterConfig()
if err != nil {
log.Fatal(err)
}
}

clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}

ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()

for range ticker.C {
pods, err := clientset.CoreV1().Pods("").List(r.Context(), metav1.ListOptions{})
if err != nil {
log.Println("Error fetching pods:", err)
continue
}

// 간단히 네임스페이스를 기준으로 랙처럼 분리 (예시)
rackMap := map[string]*K8sRack{}
x := 50
for _, pod := range pods.Items {
namespace := pod.Namespace
if _, ok := rackMap[namespace]; !ok {
rackMap[namespace] = &K8sRack{
ID:     namespace,
Name:   "Rack - " + namespace,
X:      x,
Y:      50,
Status: "normal",
Pods:   []PodStatus{},
}
x += 150
}
status := string(pod.Status.Phase)
cpu := rand.Intn(100)
mem := rand.Intn(100)
health := "normal"
if cpu > 90 || mem > 90 || status != "Running" {
health = "error"
} else if cpu > 70 || mem > 70 {
health = "warning"
}
rackMap[namespace].Pods = append(rackMap[namespace].Pods, PodStatus{
Name:      pod.Name,
Namespace: pod.Namespace,
CPU:       cpu,
Memory:    mem,
Status:    health,
})
if health == "error" {
rackMap[namespace].Status = "error"
} else if health == "warning" && rackMap[namespace].Status != "error" {
rackMap[namespace].Status = "warning"
}
}

racks := []K8sRack{}
for _, r := range rackMap {
racks = append(racks, *r)
}

if err := conn.WriteJSON(racks); err != nil {
log.Println("WebSocket write error:", err)
break
}
}
}

func main() {
http.HandleFunc("/ws/k8s", getK8sDashboard)
log.Println("Kubernetes 상면 모니터링 대시보드 실행 중: http://localhost:8080/ws/k8s")
http.ListenAndServe(":8080", nil)
}
k8s 모니터링 상면 모니터링 관재 대시보드 만들어줘

ChatGPT의 말:

 

 


다음 단계 제안

  • 프론트에서 K8s Rack 형태로 시각화
  • Pod 상태별 색상 표시
  • 실제 Prometheus 메트릭 연동
  • 워크로드/네임스페이스 필터링

어떤 부분부터 확장할까요? React에서 대시보드 그리는 부분으로 넘어갈까요?

 

댓글