Compare commits

..

6 Commits

Author SHA1 Message Date
Henry Dollman
345dbeb757 0.0.1 2024-07-24 10:53:49 -04:00
Henry Dollman
29f5d3ae62 update readme 2024-07-24 10:52:55 -04:00
Henry Dollman
d4b0887153 update forgot password cli instructions 2024-07-24 10:32:25 -04:00
Henry Dollman
06e4dd10e0 0.0.1-alpha.9 2024-07-23 22:41:33 -04:00
Henry Dollman
af4d5137d6 lower 55 sec system update check to 50 sec 2024-07-23 22:41:05 -04:00
Henry Dollman
5e255f8f69 use semaphore to limit concurrency in agent
subtract mem cache from container stats
2024-07-23 22:40:39 -04:00
4 changed files with 64 additions and 36 deletions

View File

@@ -10,6 +10,7 @@ import (
"net/http"
"os"
"strings"
"sync"
"time"
sshServer "github.com/gliderlabs/ssh"
@@ -21,11 +22,20 @@ import (
psutilNet "github.com/shirou/gopsutil/v4/net"
)
var Version = "0.0.1-alpha.8"
var Version = "0.0.1"
var containerCpuMap = make(map[string][2]uint64)
var containerCpuMutex = &sync.Mutex{}
// var containerCpuMutex = &sync.Mutex{}
var sem = make(chan struct{}, 15)
func acquireSemaphore() {
sem <- struct{}{}
}
func releaseSemaphore() {
<-sem
}
var diskIoStats = DiskIoStats{
Read: 0,
@@ -48,11 +58,11 @@ var client = &http.Client{
Dial: func(proto, addr string) (net.Conn, error) {
return net.Dial("unix", "/var/run/docker.sock")
},
ForceAttemptHTTP2: false,
IdleConnTimeout: 90 * time.Second,
DisableCompression: true,
MaxIdleConns: 10,
DisableKeepAlives: false,
ForceAttemptHTTP2: false,
IdleConnTimeout: 90 * time.Second,
DisableCompression: true,
MaxIdleConnsPerHost: 50,
DisableKeepAlives: false,
},
}
@@ -156,27 +166,35 @@ func getDockerStats() ([]*ContainerStats, error) {
containerStats := make([]*ContainerStats, 0, len(containers))
// store valid ids to clean up old container ids from map
validIds := make(map[string]struct{}, len(containers))
var wg sync.WaitGroup
for _, ctr := range containers {
ctr.IdShort = ctr.ID[:12]
cstats, err := getContainerStats(ctr)
if err != nil {
// retry once
cstats, err = getContainerStats(ctr)
validIds[ctr.IdShort] = struct{}{}
wg.Add(1)
go func() {
defer wg.Done()
cstats, err := getContainerStats(ctr)
if err != nil {
log.Printf("Error getting container stats: %+v\n", err)
continue
// retry once
cstats, err = getContainerStats(ctr)
if err != nil {
log.Printf("Error getting container stats: %+v\n", err)
return
}
}
}
containerStats = append(containerStats, cstats)
containerStats = append(containerStats, cstats)
}()
}
// clean up old container ids from map
validIds := make(map[string]struct{}, len(containers))
for _, ctr := range containers {
validIds[ctr.IdShort] = struct{}{}
}
wg.Wait()
for id := range containerCpuMap {
if _, exists := validIds[id]; !exists {
// log.Printf("Removing container cpu map entry: %+v\n", id)
delete(containerCpuMap, id)
}
}
@@ -185,6 +203,9 @@ func getDockerStats() ([]*ContainerStats, error) {
}
func getContainerStats(ctr *Container) (*ContainerStats, error) {
// use semaphore to limit concurrency
acquireSemaphore()
defer releaseSemaphore()
resp, err := client.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1")
if err != nil {
return &ContainerStats{}, err
@@ -198,14 +219,18 @@ func getContainerStats(ctr *Container) (*ContainerStats, error) {
name := ctr.Names[0][1:]
// memory
usedMemory := statsJson.MemoryStats.Usage - statsJson.MemoryStats.Cache
// memory (https://docs.docker.com/reference/cli/docker/container/stats/)
memCache := statsJson.MemoryStats.Stats["inactive_file"]
if memCache == 0 {
memCache = statsJson.MemoryStats.Stats["cache"]
}
usedMemory := statsJson.MemoryStats.Usage - memCache
// pctMemory := float64(usedMemory) / float64(statsJson.MemoryStats.Limit) * 100
// cpu
// add default values to containerCpu if it doesn't exist
// containerCpuMutex.Lock()
// defer containerCpuMutex.Unlock()
containerCpuMutex.Lock()
defer containerCpuMutex.Unlock()
if _, ok := containerCpuMap[ctr.IdShort]; !ok {
containerCpuMap[ctr.IdShort] = [2]uint64{0, 0}
}

View File

@@ -30,7 +30,7 @@ import (
"golang.org/x/crypto/ssh"
)
var Version = "0.0.1-alpha.8"
var Version = "0.0.1"
var app *pocketbase.PocketBase
var serverConnections = make(map[string]*Server)
@@ -221,10 +221,10 @@ func updateSystems() {
// app.Logger().Error("Failed to query systems")
return
}
fiftyFiveSecondsAgo := time.Now().UTC().Add(-55 * time.Second)
fiftySecondsAgo := time.Now().UTC().Add(-50 * time.Second)
batchSize := len(records)/4 + 1
for i := 0; i < batchSize; i++ {
if records[i].Get("updated").(types.DateTime).Time().After(fiftyFiveSecondsAgo) {
if records[i].Get("updated").(types.DateTime).Time().After(fiftySecondsAgo) {
break
}
// log.Println("updating", records[i].Get(("name")))

View File

@@ -86,9 +86,12 @@ export default function ForgotPassword() {
<DialogHeader>
<DialogTitle>Command line instructions</DialogTitle>
</DialogHeader>
<p className="text-primary/70 text-[0.95em]">
Use the following command to reset
your password:
<p className="text-primary/70 text-[0.95em] leading-relaxed">
If you've lost the password to your admin account, you may reset it using the following
command.
</p>
<p className="text-primary/70 text-[0.95em] leading-relaxed">
Then log into the backend and reset your user account password in the users table.
</p>
<code className="bg-muted rounded-sm py-0.5 px-2.5 mr-auto text-sm">
beszel admin update youremail@example.com newpassword

View File

@@ -2,8 +2,8 @@
A lightweight server resource monitoring hub with historical data, docker stats, and alerts.
[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel-agent/0.0.1-alpha.6?logo=docker&label=agent%20image%20size)](https://hub.docker.com/r/henrygd/beszel-agent)
[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel/0.0.1-alpha.6?logo=docker&label=hub%20image%20size)](https://hub.docker.com/r/henrygd/beszel)
[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel-agent/0.0.1-alpha.9?logo=docker&label=agent%20image%20size)](https://hub.docker.com/r/henrygd/beszel-agent)
[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel/0.0.1-alpha.9?logo=docker&label=hub%20image%20size)](https://hub.docker.com/r/henrygd/beszel)
![Screenshot of the hub](https://henrygd-assets.b-cdn.net/beszel/screenshot.png)
@@ -15,7 +15,7 @@ A lightweight server resource monitoring hub with historical data, docker stats,
- **Multi-user**: Each user has their own systems. Admins can share systems across users.
- **Simple**: Easy setup and doesn't require anything to be publicly available online.
- **OAuth / OIDC**: Supports many OAuth2 providers. Password auth can be disabled.
- **Automated backups**: Automatically back up your data to disk or S3-compatible storage.
- **Automatic backups**: Save and restore your data to / from disk or S3-compatible storage.
- **REST API**: Use your metrics in your own scripts and applications.
## Introduction
@@ -30,7 +30,7 @@ The agent runs on each system you want to monitor. It creates a minimal SSH serv
If using the binary instead of docker, ignore 4-5 and run the agent using the binary instead.
1. Start the hub (see [Installation](#installation)). The binary command is `beszel serve`.
1. Start the hub (see [installation](#installation)). The binary command is `beszel serve`.
2. Open http://localhost:8090 and create an admin user.
3. Click "Add system." Enter the name and host of the system you want to monitor.
4. Click "Copy docker compose" to copy the agent's docker-compose.yml file to your clipboard.
@@ -136,7 +136,7 @@ The hub and agent communicate over SSH, so they don't need to be exposed to the
When the hub is started for the first time, it generates an ED25519 key pair.
The agent's SSH server is configured to accept connections only using this key. It does not provide a pty or accept any input, so it is not possible to execute commands on the agent even if your private key is compromised.
The agent's SSH server is configured to accept connections only using this key. It does not provide a pseudo-terminal or accept input, so it's not possible to execute commands on the agent even if your private key is compromised.
## User roles
@@ -176,7 +176,7 @@ If it's not set, the agent will try to find the filesystem mounted on `/` and us
### Docker containers are not populating reliably
Try upgrading your docker version on the agent system. I had this issue on a machine running docker 24. It was fixed by upgrading to version 27.
Try upgrading your docker version on the agent system. I had this issue on a machine running version 24. It was fixed by upgrading to version 27.
### Month / week records are not populating reliably