Discovery & Monitoring (Agent)
1. Architecture générale et flux
Section titled “1. Architecture générale et flux”flowchart LR
API[Berth API\nCQRS + PostgreSQL 18 + Redis 8.10] <-->|gRPC mTLS\ncommands / state / metrics / logs| A[Berth Agent Go]
A <-->|Docker Engine API\n/var/run/docker.sock| D[Docker daemon]
D --> C[Containers locaux]
A -->|heartbeat + snapshots| API
API -->|audit asynchrone| RS[(Redis Streams)]
Flux principaux
Section titled “Flux principaux”- Démarrage : l’Agent charge sa configuration, valide ses certificats, ouvre Docker, établit le canal mTLS et s’enregistre.
- Discovery :
ContainerListfournit un snapshot initial ;Eventssuit ensuite create/start/stop/die/destroy/rename. - Observation : une collecte périodique envoie des métriques et l’état utile. Les événements ne remplacent pas le snapshot périodique, qui corrige les éventuelles pertes de connexion au daemon.
- Commande : l’API authentifie l’utilisateur, enregistre l’intention, envoie une commande idempotente à l’Agent ; l’Agent vérifie le contexte, exécute via Docker et renvoie le résultat.
- Logs : l’API ouvre un stream pour un container ; l’Agent lit
ContainerLogsavecFollow=trueet transmet des chunks bornés. - Persistance : l’Agent ne persiste pas l’état métier. L’API écrit PostgreSQL 18 et publie son audit selon le pattern déjà défini.
2. Discovery et monitoring des containers
Section titled “2. Discovery et monitoring des containers”La discovery combine :
- un snapshot
ContainerList(ctx, types.ContainerListOptions{All: true})au démarrage puis à intervalle lent configurable ; Eventsavec filtrestype=containerpour recevoir rapidement les changements ;- une réconciliation après reconnexion, car un stream d’événements interrompu ne doit pas laisser un état obsolète.
package docker
import ( "context" "io" "log/slog"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client")
type Discovery struct { cli *client.Client log *slog.Logger}
func (d *Discovery) Snapshot(ctx context.Context) ([]types.Container, error) { return d.cli.ContainerList(ctx, types.ContainerListOptions{All: true})}
func (d *Discovery) Watch(ctx context.Context, onEvent func(types events.Message)) error { f := filters.NewArgs(filters.Arg("type", "container")) msgs, errs := d.cli.Events(ctx, types.EventsOptions{Filters: f}) for { select { case <-ctx.Done(): return ctx.Err() case msg, ok := <-msgs: if !ok { return io.EOF } onEvent(msg) case err := <-errs: if err != nil { return err } } }}Exemple conceptuel : selon la version du SDK, importer
github.com/docker/docker/api/types/eventspour le typeevents.Messageet adapter la signature. Le wrapper interne masque ces détails au reste de l’Agent.
Les événements déclenchent une mise à jour légère (état, nom, labels). Un snapshot périodique vérifie également que chaque container géré est toujours présent, récupère les nouveaux containers éligibles et supprime les entrées disparues.
