DEV Community

Benjamin Touchard
Benjamin Touchard

Posted on Originally published at maintenant.dev

How container auto-discovery works with the Docker SDK and client-go

A monitoring tool can find your containers on its own, with no list of targets to write. There is no magic involved: it relies on the Docker and Kubernetes APIs, which already know everything about what is running. This post walks through how Maintenant, a Go monitoring tool, does it with the Docker SDK for Go and client-go.

Runtime detection

On startup, the tool runs a detection sequence:

  1. If the MAINTENANT_RUNTIME environment variable is set, it forces the mode
  2. Otherwise, if KUBERNETES_SERVICE_HOST is set, it switches to Kubernetes mode with in-cluster config
  3. Otherwise, it tries a kubeconfig (KUBECONFIG or ~/.kube/config) and uses it if the cluster answers
  4. Otherwise, it connects to the Docker socket (/var/run/docker.sock) and switches to Docker mode

Docker mode

In Docker mode, the official Docker SDK for Go connects to the Unix socket, mounted read-only. Three things happen.

Initial listing

A call to ContainerList retrieves every container, stopped ones included. For each container, the tool extracts Docker labels, the Compose project name (via the com.docker.compose.project label), exposed ports, and health check configuration.

Unified dashboard: all discovered containers at a glance

Event listening

A dedicated goroutine listens to Docker events in real time via Events. Every start, stop, die, and health_status event is captured and processed immediately, which is what lets the dashboard update in real time over SSE.

Metrics collection

The Docker ContainerStats API provides CPU, memory, network, and disk I/O metrics per container. They are collected at regular intervals and stored in SQLite.

System resources: CPU, memory, disk, network monitoring

Kubernetes mode

In Kubernetes mode, the tool uses the official client-go library with in-cluster configuration (service account). The required RBAC is minimal and read-only:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: maintenant
rules:
  - apiGroups: [""]
    resources: ["namespaces", "nodes", "pods", "events", "services"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]
  - apiGroups: ["apps"]
    resources: ["deployments", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["metrics.k8s.io"]
    resources: ["pods", "nodes"]
    verbs: ["get", "list"]
Enter fullscreen mode Exit fullscreen mode

Nothing is created, modified, or deleted in the cluster: observation only.

Workloads

Unlike Docker mode, which operates at the container level, Kubernetes mode operates at the workload level: Deployments, DaemonSets, StatefulSets. Pods are grouped under their parent workload, which gives a more meaningful view of a service's health than a flat list of pods.

Storage: SQLite in WAL mode

All collected data is stored in SQLite using WAL mode (Write-Ahead Logging). Readers do not block the writer and the writer does not block readers, which matters for a process that continuously collects metrics while serving a real-time dashboard.

Memory stays low (under 30 MB at rest) thanks to strict goroutine management and Go's garbage collector.

Summary

Auto-discovery is the use of existing Docker and Kubernetes APIs (list, then watch events, then poll stats), combined with a lightweight Go architecture and simple storage choices.


Originally published on maintenant.dev.

Maintenant is an open-source, self-hosted monitoring tool for Docker and Kubernetes: containers, endpoints, cron heartbeats, TLS certificates and alerts, in one container that discovers your stack on its own. Install it in a minute: https://maintenant.dev

This project was funded by the French Government as part of the France 2030 plan operated by Bpifrance.

France 2030 and Cap Digital

Top comments (0)