HRIS Ops Console ("Pulse")
A self-built, real-time infrastructure dashboard for Shomvob — CI/CD deployments (Jenkins + GitHub Actions), container/disk/CPU health across an EC2 fleet, SSL expiry, and proactive Telegram/Discord alerting, all on one screen.
View on GitHubView full case study
Overview
A self-built, real-time observability dashboard that surfaces the pulse of an entire infrastructure fleet on one screen — CI/CD deployments, container health, EC2 resource usage, service uptime, and SSL expiry — built from scratch rather than assembled from existing tools.
Architecture
A Node.js/Express backend runs several independent collectors in parallel: Jenkins and/or GitHub Actions REST APIs for deployments, HTTP health pings per service, TLS handshakes for SSL expiry, and a host-side cron script (over SSH, not docker.sock) that gathers container/disk/memory/CPU stats across the EC2 fleet into read-only JSON files the app reads. Alerts push to Telegram and Discord only on state transitions.
Tech Stack
Key Features
- Single-screen view of deployments, container health, disk/memory/CPU, service uptime, and SSL expiry across an entire EC2 fleet
- Dual CI/CD support — Jenkins and GitHub Actions side by side, auto-merged into one deployments list
- Alerts fire only on state transitions, not on every poll, plus a daily heartbeat confirming alerting itself is alive
- Never touches docker.sock or runs as root — works correctly under a rootless Docker daemon
Challenges & Solutions
- Rootless Docker breaks the usual docker.sock-mount approach — solved by moving container/resource collection to a host-side cron script over SSH instead, so the container never needs socket access or root.
- An early CPU% reading sometimes measured the collector's own CPU spike instead of the host's real load — fixed by diffing
/proc/statacross the full poll interval, matching how Prometheus/Grafana'srate()works. - One slow Jenkins response was delaying every other panel — fixed by having each collector write its own cache slice the moment it resolves, instead of waiting for all collectors together.
Lessons Learned
The "obvious" implementation of a monitoring tool often breaks quietly under real-world constraints — rootless Docker, a busy CI server, one slow SSH host. The fix is usually to make each piece of the system independent and fail in isolation, rather than adding more error handling around a tightly coupled design.