Skip to content

Commit

Permalink
improve podman support (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
henrygd committed Nov 12, 2024
1 parent db092d2 commit 3cd11d6
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
2 changes: 1 addition & 1 deletion beszel/internal/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (a *Agent) Run(pubKey []byte, addr string) {
a.initializeSystemInfo()
a.initializeDiskInfo()
a.initializeNetIoStats()
a.dockerManager = newDockerManager()
a.dockerManager = newDockerManager(a)

// initialize GPU manager
if os.Getenv("GPU") == "true" {
Expand Down
55 changes: 39 additions & 16 deletions beszel/internal/agent/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,23 @@ type dockerManager struct {
apiContainerList *[]container.ApiInfo // List of containers from Docker API
containerStatsMap map[string]*container.Stats // Keeps track of container stats
validIds map[string]struct{} // Map of valid container ids, used to prune invalid containers from containerStatsMap
goodDockerVersion bool // Whether docker version is at least 25.0.0 (one-shot works correctly)
}

// Add goroutine to the queue
func (d *dockerManager) queue() {
d.sem <- struct{}{}
d.wg.Add(1)
if d.goodDockerVersion {
d.sem <- struct{}{}
}
}

// Remove goroutine from the queue
func (d *dockerManager) dequeue() {
<-d.sem
d.wg.Done()
if d.goodDockerVersion {
<-d.sem
}
}

// Returns stats for all running containers
Expand Down Expand Up @@ -75,6 +80,7 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
go func() {
defer dm.dequeue()
err := dm.updateContainerStats(ctr)
// if error, delete from map and add to failed list to retry
if err != nil {
dm.containerStatsMutex.Lock()
delete(dm.containerStatsMap, ctr.IdShort)
Expand All @@ -89,11 +95,10 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
// retry failed containers separately so we can run them in parallel (docker 24 bug)
if len(failedContainters) > 0 {
slog.Debug("Retrying failed containers", "count", len(failedContainters))
// time.Sleep(time.Millisecond * 1100)
for _, ctr := range failedContainters {
dm.wg.Add(1)
dm.queue()
go func() {
defer dm.wg.Done()
defer dm.dequeue()
err = dm.updateContainerStats(ctr)
if err != nil {
slog.Error("Error getting container stats", "err", err)
Expand Down Expand Up @@ -201,12 +206,13 @@ func (dm *dockerManager) deleteContainerStatsSync(id string) {
delete(dm.containerStatsMap, id)
}

// Creates a new http client for Docker API
func newDockerManager() *dockerManager {
dockerHost := "unix:///var/run/docker.sock"
if dockerHostEnv, exists := os.LookupEnv("DOCKER_HOST"); exists {
slog.Info("DOCKER_HOST", "host", dockerHostEnv)
dockerHost = dockerHostEnv
// Creates a new http client for Docker or Podman API
func newDockerManager(a *Agent) *dockerManager {
dockerHost, exists := os.LookupEnv("DOCKER_HOST")
if exists {
slog.Info("DOCKER_HOST", "host", dockerHost)
} else {
dockerHost = getDockerHost()
}

parsedURL, err := url.Parse(dockerHost)
Expand Down Expand Up @@ -251,11 +257,15 @@ func newDockerManager() *dockerManager {
Transport: transport,
},
containerStatsMap: make(map[string]*container.Stats),
sem: make(chan struct{}, 5),
}

// Make sure sem is initialized
concurrency := 200
defer func() { dockerClient.sem = make(chan struct{}, concurrency) }()
// If using podman, return client
if strings.Contains(dockerHost, "podman") {
a.systemInfo.Podman = true
dockerClient.goodDockerVersion = true
return dockerClient
}

// Check docker version
// (versions before 25.0.0 have a bug with one-shot which requires all requests to be made in one batch)
Expand All @@ -273,9 +283,22 @@ func newDockerManager() *dockerManager {

// if version > 24, one-shot works correctly and we can limit concurrent operations
if dockerVersion, err := semver.Parse(versionInfo.Version); err == nil && dockerVersion.Major > 24 {
concurrency = 5
dockerClient.goodDockerVersion = true
} else {
slog.Info(fmt.Sprintf("Docker %s is outdated. Upgrade if possible. See https://github.com/henrygd/beszel/issues/58", versionInfo.Version))
}
slog.Debug("Docker", "version", versionInfo.Version, "concurrency", concurrency)

return dockerClient
}

// Test docker / podman sockets and return if one exists
func getDockerHost() string {
scheme := "unix://"
socks := []string{"/var/run/docker.sock", "/run/user/1000/podman/podman.sock", "/run/podman/podman.sock"}
for _, sock := range socks {
if _, err := os.Stat(sock); err == nil {
return scheme + sock
}
}
return scheme + socks[0]
}
1 change: 1 addition & 0 deletions beszel/internal/entities/system/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type Info struct {
DiskPct float64 `json:"dp"`
Bandwidth float64 `json:"b"`
AgentVersion string `json:"v"`
Podman bool `json:"p,omitempty"`
}

// Final data structure to return to the hub
Expand Down
19 changes: 13 additions & 6 deletions beszel/site/src/components/routes/system.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ async function getStats<T>(collection: string, system: SystemRecord, chartTime:
})
}

function dockerOrPodman(str: string, system: SystemRecord) {
if (system.info.p) {
str = str.replace("docker", "podman").replace("Docker", "Podman")
}
return str
}

export default function SystemDetail({ name }: { name: string }) {
const direction = useStore($direction)
const { _ } = useLingui()
Expand Down Expand Up @@ -385,7 +392,7 @@ export default function SystemDetail({ name }: { name: string }) {
<ChartCard
empty={dataEmpty}
grid={grid}
title={t`Docker CPU Usage`}
title={dockerOrPodman(t`Docker CPU Usage`, system)}
description={t`Average CPU utilization of containers`}
cornerEl={containerFilterBar}
>
Expand All @@ -406,8 +413,8 @@ export default function SystemDetail({ name }: { name: string }) {
<ChartCard
empty={dataEmpty}
grid={grid}
title={t`Docker Memory Usage`}
description={t`Memory usage of docker containers`}
title={dockerOrPodman(t`Docker Memory Usage`, system)}
description={dockerOrPodman(t`Memory usage of docker containers`, system)}
cornerEl={containerFilterBar}
>
<ContainerChart chartData={chartData} chartName="mem" dataKey="m" unit=" MB" />
Expand Down Expand Up @@ -447,8 +454,8 @@ export default function SystemDetail({ name }: { name: string }) {
>
<ChartCard
empty={dataEmpty}
title={t`Docker Network I/O`}
description={t`Network traffic of docker containers`}
title={dockerOrPodman(t`Docker Network I/O`, system)}
description={dockerOrPodman(t`Network traffic of docker containers`, system)}
cornerEl={containerFilterBar}
>
{/* @ts-ignore */}
Expand Down Expand Up @@ -649,7 +656,7 @@ function ChartCard({
<CardDescription>{description}</CardDescription>
{cornerEl && <div className="relative py-1 block sm:w-44 sm:absolute sm:top-2.5 sm:end-3.5">{cornerEl}</div>}
</CardHeader>
<div className="ps-0 w-[calc(100%-1.6em)] h-52 relative">
<div className="ps-0 w-[calc(100%-1.5em)] h-52 relative">
{<Spinner msg={empty ? t`Waiting for enough records to display` : undefined} />}
{isIntersecting && children}
</div>
Expand Down
2 changes: 2 additions & 0 deletions beszel/site/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface SystemInfo {
b: number
/** agent version */
v: string
/** system is using podman */
p?: boolean
}

export interface SystemStats {
Expand Down

0 comments on commit 3cd11d6

Please sign in to comment.