← 뒤로가기

Go와 NATS로 라즈베리파이 실시간 하드웨어 대시보드를 만든 과정

Go를 설치하고, 라즈베리파이 상태를 수집해 NATS로 발행한 뒤 브라우저에 실시간으로 뿌리는 /info 대시보드를 만든 과정을 정리했다.

이번에는 muabow.com/info에 라즈베리파이 하드웨어 대시보드를 붙였다.

목표는 단순했다.

  • Go로 라즈베리파이의 현재 상태를 수집한다.
  • 수집한 지표를 NATS에 발행한다.
  • 웹 브라우저는 그 지표를 실시간으로 받아서 대시보드로 보여준다.
  • 누구나 바로 열어볼 수 있는 공개 상태판으로 둔다.

즉 이번 작업은 Go + NATS + Server-Sent Events를 이용한 작은 실시간 관측 화면이다.

왜 Go로 만들었는가

시스템 상태를 읽는 작은 데몬은 Go와 잘 맞는다.

Go는 단일 바이너리로 빌드하기 쉽고, 라즈베리파이 같은 작은 서버에서도 부담이 적다.
/proc, systemctl, 파일시스템 상태 같은 리눅스 정보를 읽어 웹 서버로 내보내기에도 충분히 단순하다.

이번에는 라즈베리파이에 공식 Go tarball을 설치했다.

Go 1.26.3
linux/arm64

소스는 Go 프로젝트 디렉터리로 분리해 관리했다.

전체 구조

이번 대시보드의 흐름은 이렇다.

Go collector
  -> NATS subject
  -> Go web server subscriber
  -> SSE /info/events
  -> Browser dashboard

처음에는 Go 웹 서버가 직접 지표를 읽어도 됐지만, 일부러 NATS를 사이에 넣었다.

이유는 앞으로 확장하기 좋기 때문이다.

  • 다른 앱도 같은 지표를 구독할 수 있다.
  • 알림이나 로그 저장 같은 기능을 나중에 붙이기 쉽다.
  • 대시보드와 수집 흐름을 느슨하게 분리할 수 있다.

수집하는 정보

현재 Go 앱은 아래 정보를 수집한다.

  • CPU 사용률
  • CPU 코어 수
  • 메모리 사용량
  • 디스크 사용량
  • load average
  • uptime
  • 장치 온도
  • 주요 서비스 상태

서비스 상태는 현재 아래 항목을 본다.

서비스 상태는 공개 서비스와 내부 앱 몇 개를 함께 본다.

리눅스 정보를 어떻게 읽는가

대부분의 값은 리눅스 표준 파일에서 읽는다.

CPU는 /proc/stat을 두 번 읽어 짧은 간격의 차이를 계산한다.

메모리는 /proc/meminfo에서 MemTotal, MemAvailable을 읽는다.

부하는 /proc/loadavg를 읽는다.

업타임은 /proc/uptime을 읽는다.

온도는 라즈베리파이에서 흔히 쓰는 아래 경로를 확인한다.

/sys/class/thermal/thermal_zone0/temp
/sys/class/hwmon/hwmon0/temp1_input

디스크는 Go의 syscall.Statfs/ 파일시스템 상태를 읽는다.

NATS로 발행하는 방식

Go 앱은 2초마다 상태를 수집해서 NATS에 JSON으로 발행한다.

subject는 다음과 같다.

metrics subject

실제로 확인한 메시지는 이런 형태다.

{
  "hostname": "muabow",
  "os": "linux",
  "arch": "arm64",
  "cpu": {
    "usagePercent": 0,
    "cores": 4
  },
  "memory": {
    "usedPercent": 16.26
  },
  "disk": {
    "usedPercent": 16.81
  },
  "temperatureC": 52.35
}

NATS CLI로도 직접 구독 확인을 했다.

nats sub <metrics-subject> --count 1

메시지가 정상적으로 들어오는 것을 확인했다.

브라우저에는 어떻게 실시간으로 뿌리는가

브라우저에는 Server-Sent Events를 사용했다.

대시보드 페이지가 열리면 브라우저는 아래 경로에 연결한다.

/info/events

Go 서버는 NATS에서 받은 최신 지표를 SSE 이벤트로 흘려준다.

브라우저는 EventSource로 이 이벤트를 받아 화면 값을 갱신한다.

이 방식은 WebSocket보다 단순하고, 지금처럼 서버에서 브라우저로 상태를 계속 밀어주는 화면에 잘 맞는다.

지금은 공개 상태판으로 운영한다

처음에는 /info를 사진첩 관리자와 같은 비밀번호로 묶어두었다.

그런데 이 페이지는 관리자 패널보다는 사이트 안의 공개 기능에 가깝다.
그래서 지금은 로그인 없이 바로 열 수 있는 상태판으로 바꾸었다.

브라우저가 EventSource/info/events에 바로 연결해 실시간 값을 받도록 두었기 때문에, 홈의 기능 > 장치 정보 버튼을 누르면 곧바로 상태를 볼 수 있다.

nginx 연결

Go 앱은 라즈베리파이 내부에서만 열린다.

내부 루프백 주소의 앱 포트

nginx는 /info와 방문자 수 집계를 위한 /api/visits 요청을 Go 앱으로 프록시한다.

location /api/visits {
  proxy_pass http://127.0.0.1:<internal-app-port>;
  proxy_http_version 1.1;
  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;
}

location /info {
  proxy_pass http://127.0.0.1:<internal-app-port>;
  proxy_http_version 1.1;
  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;
  proxy_buffering off;
}

proxy_buffering off는 SSE처럼 실시간으로 흘러가는 응답에 중요하다.

systemd 서비스

대시보드는 systemd 서비스로 등록했다.

dashboard.service

서비스는 nats.service 이후에 뜨도록 설정했다.

After=network-online.target nats.service
Wants=network-online.target nats.service

현재 상태는 enabled, active다.

확인 명령은 다음과 같다.

sudo systemctl status <dashboard-service>
sudo journalctl -u <dashboard-service> --no-pager -n 100

접속 주소

대시보드는 아래 주소에서 볼 수 있다.

https://muabow.com/info

이제는 로그인 없이 CPU, 메모리, 디스크, 온도, 서비스 상태가 실시간으로 갱신된다.

같은 Go 서비스는 사이트 footer에 붙인 방문자 수 API도 함께 맡고 있다.

https://muabow.com/api/visits

이번 구조의 장점

가장 마음에 드는 점은 구조가 작지만 확장 가능하다는 것이다.

  • Go는 수집과 대시보드 서버를 담당한다.
  • NATS는 지표 메시지의 통로가 된다.
  • 브라우저는 SSE로 실시간 값을 받는다.
  • nginx는 /info/api/visits를 내부 앱으로 넘긴다.

지금은 하드웨어 대시보드지만, 나중에는 NATS에 흐르는 다른 이벤트도 같은 방식으로 보여줄 수 있다.

예를 들면:

  • 사진 업로드 이벤트
  • 글 배포 이벤트
  • 백업 완료 이벤트
  • 서비스 재시작 이벤트

이렇게 되면 /info는 단순 상태판을 넘어, 라즈베리파이의 작은 관제 화면이 될 수 있다.

정리

이번 작업으로 라즈베리파이에 실시간 하드웨어 대시보드가 생겼다.

핵심은 단순하다.

  1. Go 설치
  2. 장치 상태 수집 앱 작성
  3. NATS에 지표 발행
  4. 브라우저에 SSE로 실시간 전달
  5. /info에 nginx 프록시 연결
  6. 공개 상태판으로 정리하고 사이트 기능과 연결

웹사이트가 조금씩 정적 페이지를 넘어, 작은 개인 서버 운영 도구로 자라나는 중이다.

이어서 보기