feat(docker): readable names, CPU in cores and memory in bytes, failures listed with since-times (#5209)
#5209 "Docker views: readable names, CPU/memory in cores and bytes, failures listed with since-time" (milestone 477 "UI problems first"). - A swarm task reads as its service and slot ("codex_db · 1", or the node for a global service), with the raw name in the title: Docker page, host panel, busiest widget, container detail. - CPU reads in cores (Docker's 100% = one core), toned by its share of the host's CPUs from the agent's per-core series. Memory reads in bytes, against a limit only when one is really set (Docker reports host RAM otherwise). - Exit 137/143 without an OOM kill is a stop, not a failure: no exited_nonzero, no crash-loop death, no "failed (24h)", dim exit code. - "Failed (24h)" is a list (Docker page #failures, linked from the widget and the tile): plain containers by their deaths, swarm services by Swarm's failed tasks; a second manager's copy of a task death counts once. - Failing swarm services lead Needs attention; services sort problems first with since-times on the page, the widget and the Swarm page; nodes that are down or drained sort first. - Busiest widget orders by a 5-minute CPU average so the list holds still. - Host panel: a table, problems first with what is wrong and since when; replaced swarm tasks hidden and counted. - Container detail: node hostname, I/O labelled "since start", Restarts hidden for swarm tasks with a note on where task failures are. - Widget names: "Docker — Services & failures", "Docker — Busiest containers". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
{# docker/container_detail.html — full detail page for one container #}
|
||||
{# docker/container_detail.html — full detail page for one container. A swarm
|
||||
task is titled by its service and slot, with the raw container name under
|
||||
it; CPU reads in cores and memory in bytes (see _usage.html). #}
|
||||
{% extends "base.html" %}
|
||||
{% from "_macros.html" import crumbs %}
|
||||
{% block title %}{{ name }} — Docker — Steward{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Docker", "/plugins/docker/"), (name, "")]) }}{% endblock %}
|
||||
{% from "docker/_usage.html" import cpu, mem %}
|
||||
{% block title %}{{ label or name }} — Docker — Steward{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Docker", "/plugins/docker/"), (label or name, "")]) }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
{% if container is none %}
|
||||
@@ -18,11 +21,14 @@
|
||||
{# ── Header ──────────────────────────────────────────────────────────────── #}
|
||||
<div style="display:flex;align-items:center;gap:0.6rem;margin-bottom:0.35rem;flex-wrap:wrap;">
|
||||
<span class="dot {% if container.status == 'running' %}dot-up{% elif container.status == 'paused' %}dot-warn{% else %}dot-down{% endif %}"></span>
|
||||
<h1 class="page-title" style="margin-bottom:0;">{{ container.name }}</h1>
|
||||
<h1 class="page-title" style="margin-bottom:0;">{{ label }}</h1>
|
||||
{% if container.health == 'healthy' %}<span style="font-size:0.72rem;color:var(--green);border:1px solid var(--green);border-radius:3px;padding:0.05rem 0.4rem;">healthy</span>
|
||||
{% elif container.health == 'unhealthy' %}<span style="font-size:0.72rem;color:var(--red);border:1px solid var(--red);border-radius:3px;padding:0.05rem 0.4rem;">unhealthy</span>
|
||||
{% elif container.health == 'starting' %}<span style="font-size:0.72rem;color:var(--orange);border:1px solid var(--orange);border-radius:3px;padding:0.05rem 0.4rem;">starting</span>{% endif %}
|
||||
</div>
|
||||
{% if label != container.name %}
|
||||
<div style="font-size:0.75rem;color:var(--text-dim);font-family:ui-monospace,monospace;margin-bottom:0.25rem;overflow-wrap:anywhere;">{{ container.name }}</div>
|
||||
{% endif %}
|
||||
<div style="font-size:0.82rem;color:var(--text-muted);margin-bottom:1.5rem;">
|
||||
{{ container.status }}{% if uptime %} · up {{ uptime }}{% endif %}
|
||||
{% if host %} · on <a href="/hosts/{{ host.id }}" style="color:var(--text-muted);">{{ host.name }}</a>{% endif %}
|
||||
@@ -38,16 +44,27 @@
|
||||
{% endmacro %}
|
||||
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:0.75rem;margin-bottom:1.5rem;">
|
||||
{{ fact("CPU", "%.1f%%" | format(container.cpu_pct) if container.cpu_pct is not none else "—") }}
|
||||
{{ fact("Memory", "%.1f%%" | format(container.mem_pct) if container.mem_pct is not none else "—") }}
|
||||
{{ fact("CPU", cpu(usage) if container.status == 'running' else "—") }}
|
||||
{{ fact("Memory", mem(usage) if container.status == 'running' else "—") }}
|
||||
{#- Swarm never restarts a task's container: it replaces the task with a new
|
||||
one, so restart_count is always 0 there and the service's task failures
|
||||
(Swarm page) are the count that means something. #}
|
||||
{% if not container.service_name %}
|
||||
{{ fact("Restarts", container.restart_count, "var(--orange)" if container.restart_count else "") }}
|
||||
{% endif %}
|
||||
{{ fact("Last exit", (container.exit_code ~ (" (OOM)" if container.oom_killed else "")) if container.exit_code is not none else "—",
|
||||
"var(--red)" if (container.exit_code is not none and container.exit_code != 0) else "") }}
|
||||
{{ fact("Net in", net_rx) }}
|
||||
{{ fact("Net out", net_tx) }}
|
||||
{{ fact("Block read", blk_read) }}
|
||||
{{ fact("Block write", blk_write) }}
|
||||
"var(--red)" if exit_failed else "") }}
|
||||
{{ fact("Net in since start", net_rx) }}
|
||||
{{ fact("Net out since start", net_tx) }}
|
||||
{{ fact("Disk read since start", blk_read) }}
|
||||
{{ fact("Disk written since start", blk_write) }}
|
||||
</div>
|
||||
{% if container.service_name %}
|
||||
<div style="font-size:0.78rem;color:var(--text-muted);margin:-0.75rem 0 1.5rem;">
|
||||
Swarm replaces a failed task with a new container rather than restarting it; the
|
||||
service's failed tasks are on the <a href="/plugins/docker/swarm">Swarm page</a>.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# ── Image / placement ───────────────────────────────────────────────────── #}
|
||||
<div class="card" style="margin-bottom:1.5rem;">
|
||||
@@ -61,7 +78,9 @@
|
||||
<span style="color:var(--text-muted);">Swarm service</span><span>{{ container.service_name }}</span>
|
||||
{% endif %}
|
||||
{% if container.node_id %}
|
||||
<span style="color:var(--text-muted);">Node</span><span style="font-family:ui-monospace,monospace;">{{ container.node_id }}</span>
|
||||
<span style="color:var(--text-muted);">Node</span>
|
||||
{% if node_name %}<span title="node id {{ container.node_id }}">{{ node_name }}</span>
|
||||
{% else %}<span style="font-family:ui-monospace,monospace;">{{ container.node_id }}</span>{% endif %}
|
||||
{% endif %}
|
||||
{% if ports %}
|
||||
<span style="color:var(--text-muted);">Ports</span>
|
||||
|
||||
Reference in New Issue
Block a user