agent: add separate glibc build with NVML support (#1618)

purego requires dynamic linking, so split the agent builds:
- Default: static binary without NVML (works on musl/alpine)
- Glibc: dynamic binary with NVML support via purego

Changes:
- Add glibc build tag to conditionally include NVML code
- Add beszel-agent-linux-amd64-glibc build/archive in goreleaser
- Update ghupdate to use glibc binary on glibc systems
- Switch nvidia dockerfile to golang:bookworm with -tags glibc
This commit is contained in:
henrygd
2026-01-12 15:38:13 -05:00
parent 6a1a98d73f
commit 3279a6ca53
8 changed files with 57 additions and 9 deletions

View File

@@ -76,6 +76,18 @@ builds:
- goos: windows
goarch: riscv64
- id: beszel-agent-linux-amd64-glibc
binary: beszel-agent
main: internal/cmd/agent/agent.go
env:
- CGO_ENABLED=0
flags:
- -tags=glibc
goos:
- linux
goarch:
- amd64
archives:
- id: beszel-agent
formats: [tar.gz]
@@ -89,6 +101,15 @@ archives:
- goos: windows
formats: [zip]
- id: beszel-agent-linux-amd64-glibc
formats: [tar.gz]
ids:
- beszel-agent-linux-amd64-glibc
name_template: >-
{{ .Binary }}_
{{- .Os }}_
{{- .Arch }}_glibc
- id: beszel
formats: [tar.gz]
ids:

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"maps"
"os/exec"
"regexp"
@@ -14,8 +15,6 @@ import (
"time"
"github.com/henrygd/beszel/internal/entities/system"
"log/slog"
)
const (

View File

@@ -1,4 +1,4 @@
//go:build (linux || windows) && amd64
//go:build amd64 && (windows || (linux && glibc))
package agent

View File

@@ -1,4 +1,4 @@
//go:build linux && amd64
//go:build glibc && linux && amd64
package agent

View File

@@ -1,4 +1,4 @@
//go:build (!linux && !windows) || !amd64
//go:build (!linux && !windows) || !amd64 || (linux && !glibc)
package agent

View File

@@ -19,11 +19,11 @@ func TestSystemdManagerGetServiceStats(t *testing.T) {
assert.NoError(t, err)
// Test with refresh = true
result := manager.getServiceStats(true)
result := manager.getServiceStats("any-service", true)
assert.Nil(t, result)
// Test with refresh = false
result = manager.getServiceStats(false)
result = manager.getServiceStats("any-service", false)
assert.Nil(t, result)
}

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:alpine AS builder
FROM --platform=$BUILDPLATFORM golang:bookworm AS builder
WORKDIR /app
@@ -10,7 +10,7 @@ COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags glibc -ldflags "-w -s" -o /agent ./internal/cmd/agent
# --------------------------
# Smartmontools builder stage

View File

@@ -11,6 +11,7 @@ import (
"log/slog"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@@ -345,5 +346,32 @@ func archiveSuffix(binaryName, goos, goarch string) string {
if goos == "windows" {
return fmt.Sprintf("%s_%s_%s.zip", binaryName, goos, goarch)
}
// Use glibc build for agent on glibc systems (includes NVML support via purego)
if binaryName == "beszel-agent" && goos == "linux" && goarch == "amd64" && isGlibc() {
return fmt.Sprintf("%s_%s_%s_glibc.tar.gz", binaryName, goos, goarch)
}
return fmt.Sprintf("%s_%s_%s.tar.gz", binaryName, goos, goarch)
}
func isGlibc() bool {
for _, path := range []string{
"/lib64/ld-linux-x86-64.so.2", // common on many distros
"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2", // Debian/Ubuntu
"/lib/ld-linux-x86-64.so.2", // alternate
} {
if _, err := os.Stat(path); err == nil {
return true
}
}
// Fallback to ldd output when present (musl ldd reports musl, glibc reports GNU libc/glibc).
if lddPath, err := exec.LookPath("ldd"); err == nil {
out, err := exec.Command(lddPath, "--version").CombinedOutput()
if err == nil {
s := strings.ToLower(string(out))
if strings.Contains(s, "gnu libc") || strings.Contains(s, "glibc") {
return true
}
}
}
return false
}