feat(docker): per-container enrichment — health, restarts, exit code, I/O, grouping
First slice of milestone 77 (Docker monitoring depth). Surfaces real per-container
stats beyond basic state, all read-only on the existing push model.
- agent (→1.4.0): collect_docker now inspects each container (health, restart
count, exit code, OOM) and reads net + block I/O from the stats payload; pulls
compose project + swarm service/task/node from container labels. Per-container
inspect+stats calls run over a small bounded ThreadPool so the ~1s-per-stats
blocking doesn't stretch the sample on a busy host.
- schema (docker_003): additive columns on docker_containers — health, exit_code,
oom_killed, compose_project, service_name, task_id, node_id, and BigInteger
net/blk byte counters.
- ingest: persists the enrichment + restart_count (.get keeps older agents working).
- ui: Docker page rows now show health badge, uptime ("up 3d 4h"), restart count,
exit code (+OOM) for stopped containers, and compose/service grouping label.
- tests: agent helpers (grouping, inspect fields, net/IO sum) + collect_docker
assembly incl. inspect; integration asserts enrichment round-trips.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, Index, Integer, String, Text
|
||||
from sqlalchemy import (
|
||||
BigInteger, Boolean, DateTime, Float, ForeignKey, Index, Integer, String, Text,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from steward.models.base import Base
|
||||
|
||||
@@ -38,6 +40,23 @@ class DockerContainer(Base):
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
# ── Enrichment (agent ≥ 1.4.0) ────────────────────────────────────────────
|
||||
# Health/exit/restart come from `docker inspect` (not the list endpoint);
|
||||
# exit_code is only meaningful for stopped containers.
|
||||
health: Mapped[str | None] = mapped_column(String(16), nullable=True) # healthy|unhealthy|starting
|
||||
exit_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
oom_killed: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
# Grouping: compose project + swarm placement, read off container labels.
|
||||
compose_project: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
service_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
task_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
node_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
# Cumulative-since-start I/O counters (BigInteger — they exceed 2^31 quickly).
|
||||
net_rx_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||
net_tx_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||
blk_read_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||
blk_write_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||
|
||||
|
||||
class DockerMetric(Base):
|
||||
"""Time-series CPU/memory per container — one row per sample per running
|
||||
|
||||
Reference in New Issue
Block a user