Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Use .PHONY to declare targets that are not actual files.
# This prevents conflicts with files of the same name and improves performance.
.PHONY: build up down restart logs ps prune rebuild-frontend

# Build the Docker images as defined in docker-compose.yml
build:
docker compose build

# Create and start the containers in detached mode
up:
docker compose up -d

# Stop and remove the containers, networks, and volumes
down:
docker compose down

# A convenient shortcut to restart the services
restart: down up

# Follow the logs of the running services
logs:
docker compose logs -f

# List the running containers
ps:
docker compose ps

prune:
docker container prune
docker image prune

# Rebuild the frontend service specifically and restart it without affecting other services.
# This assumes you have a service named 'frontend' in your docker-compose.yml.
rebuild-frontend:
cd frontend; \
npm run build; \
cd ..; \
docker build -t servstat-frontend frontend; \
64 changes: 43 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,68 @@ ServStat is a robust tool designed to monitor multiple servers for CPU, memory,

![Demonstration Image](https://user-images.githubusercontent.com/17045050/81972895-dfd6bc00-9655-11ea-9e1c-bda752e6b6bc.png)

## Backend Deployment
The backend collects the stats of the machine where it is deployed and one instance should be deployed on each machine to monitor.

Ensure that you are logged in as the root user.
The frontend provides a user-friendly interface to visualize the collected data and should be deployed on only one machine. It periodically queries the hosts specified in `frontend/public/config.json` and displays the collected data in a web interface.

## Docker Deployment (Recommended)

First, build the Docker images through the Makefile.

```shell
cd /root
git clone https://github.com/djosix/servstat.git .servstat
cd .servstat/backend
make build
```

This builds the following services:
- the backend, which is a simple Bottle application that queries the local machine for CPU, memory, and GPU usage,
- the frontend, a Vue.js application that queries a list of backends specified in the config.json file for the collected data and displays it in a user-friendly interface,
- an Nginx reverse proxy server that is used as a unique entry point for the frontend and backend services.

Then, start the services using Docker Compose:

python3 -m pip install -r requirements.txt
```shell
make up
```

To launch the API server:
To stop the services, use:

```shell
python3 main.py --host=0.0.0.0 --port=9989
make down
```

Optionally, you can manage the service with supervisor to ensure it always restarts after system reboots:
To restart the services, use:

```shell
# Install supervisor
apt install supervisor
make restart
```

> :warning: If you modify the frontend code, you will need to rebuild the static files using `make rebuild-frontend` before rebuilding the docker image.

## Manual Deployment

cp servstat.conf /etc/supervisor/conf.d/servstat.conf
vim /etc/supervisor/conf.d/servstat.conf # Customization allowed
### Backend

systemctl reload supervisor
supervisorctl start servstat
Create a virtual environment and install the requirements:

```shell
cd backend
uv venv
source venv/bin/activate
uv pip install -r requirements.txt
```

Launch the API server:

```shell
python main.py --host=0.0.0.0 --port=9989
```

## Frontend Building Process
### Frontend

This process has been tested with Node.js v14.16.0 and Ubuntu 20.04.

```shell
git clone https://github.com/djosix/servstat.git
cd servstat/frontend
cd frontend

npm install

Expand All @@ -60,6 +84,4 @@ After building, serve the `dist/` folder using a web server:
```shell
# Copy files to the document root
cp -r dist/* /var/www/html/
```

These instructions will assist you in getting a copy of the project up and running on your local machines for development and testing purposes.
```
44 changes: 44 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
FROM nvidia/cuda:12.4.1-base-ubuntu22.04

# Set a non-interactive frontend for package installers to avoid prompts
ARG DEBIAN_FRONTEND=noninteractive

# Step 2: Install Python 3.12, pip, and curl.
# The CUDA image doesn't have the specific Python version or uv pre-installed.
# We use the 'deadsnakes' PPA for recent Python versions on Ubuntu.
RUN apt-get update && apt-get install -y \
software-properties-common \
curl \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update && apt-get install -y \
python3.12 \
python3-pip \
python3.12-venv \
&& rm -rf /var/lib/apt/lists/*

# Step 2.5: Rebuild the dynamic linker's cache.
# This makes the container aware of all libraries, including the NVIDIA ones.
RUN ldconfig

# Step 3: Install 'uv', the fast Python package manager from your original image.
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
# Add uv to the PATH
ENV PATH="/root/.local/bin:$PATH"

# Set the working directory to /app
WORKDIR /app
SHELL ["/bin/bash", "-c"]

# Copy your application code into the container
COPY . /app

# Step 4: Create the virtual environment and install dependencies using uv.
# This combines multiple commands into one RUN layer for efficiency.
# Running `uv pip install` from within the venv ensures packages are installed correctly.
RUN uv venv --python 3.12 && \
source .venv/bin/activate && \
uv pip install -r requirements.txt

# Step 5: Run the backend Python script when the container launches.
# This command remains the same. `uv run` will automatically use the .venv.
CMD ["uv", "run", "python", "main.py", "--host", "0.0.0.0", "--port", "9989"]
2 changes: 1 addition & 1 deletion backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def disk_info():
if disk_info_data is None:
disks = []
for part in psutil.disk_partitions():
if part.device.startswith('/dev/loop'):
if part.mountpoint != "/host_root":
continue
usage = psutil.disk_usage(part.mountpoint)
part = dict(part._asdict())
Expand Down
47 changes: 47 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
services:
backend:
image: servstat-backend:latest
hostname: backend
build: ./backend
volumes:
- /:/host_root:ro # Mount host's root at /host_root in container, read-only (ro), to monitor disk usage
networks:
app_net:
ipv4_address: 172.20.0.10
restart: unless-stopped
deploy: # Add gpu allocation
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

frontend:
image: servstat-frontend:latest
hostname: frontend
build: ./frontend
networks:
- app_net
restart: unless-stopped

nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
# Mount the site-specific configuration.
# This will be included by the default nginx.conf.
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- app_net
depends_on:
- backend
restart: unless-stopped

networks:
app_net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
28 changes: 28 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Stage 1: Build the frontend
FROM node:14.16.0 AS builder

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
# You may want to COPY a config.json here if needed

RUN npm run build

# Stage 2: Serve with nginx
FROM nginx:alpine

# Remove default nginx static assets
RUN rm -rf /usr/share/nginx/html/*

# Copy built frontend from builder
COPY --from=builder /app/dist /usr/share/nginx/html

# Optionally copy a custom nginx config
# COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
Loading