initial commit
flake-check / flake-check (push) Canceled after 0s
lint / lint (push) Canceled after 0s
diff-tag / dix (push) Canceled after 0s

This commit is contained in:
Floweynt
2026-08-31 08:41:45 -05:00
commit 76fa38e34c
54 changed files with 6747 additions and 0 deletions
+386
View File
@@ -0,0 +1,386 @@
{
name,
hostInfo,
dsl,
pkgs,
lib,
containers,
...
}:
let
inherit (dsl) mkContainer;
inherit (hostInfo.paths) data;
nodePort = 9100;
cadvPort = 9200;
containerNetworkRulesFile =
let
mkRules =
metric: record:
lib.mapAttrsToList (cname: c: {
inherit record;
expr = "rate(${metric}{device=\"${c.iface}\"}[5m])";
labels = {
container = cname;
};
}) containers;
in
pkgs.writeText "container-network.yml" (
builtins.toJSON {
groups = [
{
name = "container-network";
rules =
mkRules "node_network_receive_bytes_total" "container_network_receive_rate"
++ mkRules "node_network_transmit_bytes_total" "container_network_transmit_rate";
}
];
}
);
containerDefinedRulesFile = pkgs.writeText "container-defined.yml" (
builtins.toJSON {
groups = [
{
name = "container-defined";
rules = lib.mapAttrsToList (cname: _: {
record = "container_defined";
expr = "1";
labels = {
container = cname;
};
}) containers;
}
];
}
);
alloyConfig = pkgs.writeText "config.alloy" ''
loki.source.journal "journal" {
max_age = "12h"
path = "/var/log/journal"
labels = { job = "systemd-journal" }
relabel_rules = loki.relabel.journal.rules
forward_to = [loki.write.local.receiver]
}
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
rule {
source_labels = ["__journal__hostname"]
target_label = "host"
}
rule {
source_labels = ["__journal_syslog_identifier"]
target_label = "syslog_id"
}
rule {
source_labels = ["__journal_priority_keyword"]
target_label = "level"
}
rule {
source_labels = ["__journal__systemd_machine_name"]
target_label = "container"
}
}
loki.write "local" {
endpoint {
url = "http://127.0.0.1:3100/loki/api/v1/push"
}
}
'';
dashboards = lib.filterAttrs (name: _: lib.hasSuffix "-dashboard" name) (
dsl.listMap ./overseer (_: path: import path { inherit pkgs lib; })
);
dashboardDir = pkgs.linkFarm "grafana-dashboards" (
lib.mapAttrsToList (name: dashboard: {
name = "${lib.removeSuffix "-dashboard" name}.json";
path = dashboard;
}) dashboards
);
landingRoot = pkgs.writeTextDir "index.html" ''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Overseer</title>
<style>
body { font-family: sans-serif; max-width: 480px; margin: 4rem auto; }
ul { padding: 0; list-style: none; }
li { margin: .5rem 0; }
</style>
</head>
<body>
<h1>Overseer</h1>
<ul>
<li><a data-host="stats.localhost">stats.localhost</a> — Grafana</li>
<li><a data-host="prometheus.localhost">prometheus.localhost</a> — Prometheus</li>
</ul>
<script>
const p = location.port && location.port !== "80" ? ":" + location.port : "";
document.querySelectorAll("a[data-host]").forEach(a => {
const h = a.dataset.host;
a.href = "http://" + h + p;
a.textContent = h + p;
});
</script>
</body>
</html>
'';
in
let
c =
mkContainer {
inherit name;
net.access = [
{
to = "@host";
tcp = [
nodePort
cadvPort
];
}
];
svc.autoStart = true;
resources.fs = {
"/var/lib/loki" = {
hostPath = "${data}/overseer/loki/data";
isReadOnly = false;
};
"/var/lib/prometheus2" = {
hostPath = "${data}/overseer/prometheus/data";
isReadOnly = false;
};
"/var/lib/grafana" = {
hostPath = "${data}/overseer/grafana";
isReadOnly = false;
};
"/var/log/journal" = {
hostPath = "/var/log/journal";
isReadOnly = true;
};
};
containerConfig = _: {
services.loki = {
enable = true;
configuration = {
auth_enabled = false;
server = {
http_listen_port = 3100;
grpc_listen_port = 9096;
};
common = {
instance_addr = "127.0.0.1";
path_prefix = "/var/lib/loki";
storage.filesystem = {
chunks_directory = "/var/lib/loki/chunks";
rules_directory = "/var/lib/loki/rules";
};
replication_factor = 1;
ring.kvstore.store = "inmemory";
};
schema_config.configs = [
{
from = "2020-10-24";
store = "tsdb";
object_store = "filesystem";
schema = "v13";
index = {
prefix = "index_";
period = "24h";
};
}
];
};
};
services.alloy = {
enable = true;
configPath = alloyConfig;
};
services.prometheus = {
enable = true;
port = 9090;
globalConfig.scrape_interval = "15s";
scrapeConfigs = [
{
job_name = "node";
static_configs = [ { targets = [ "${hostAddr}:${toString nodePort}" ]; } ];
}
{
job_name = "cadvisor";
static_configs = [ { targets = [ "${hostAddr}:${toString cadvPort}" ]; } ];
}
{
job_name = "prometheus";
static_configs = [ { targets = [ "localhost:9090" ]; } ];
}
];
ruleFiles = [
containerNetworkRulesFile
containerDefinedRulesFile
(dsl.mkContainerLimitsRuleFile pkgs containers)
];
rules = [
''
groups:
- name: containers
rules:
- alert: ContainerFailed
expr: node_systemd_unit_state{name=~"container@.*",state="failed"} == 1
for: 1m
labels:
severity: critical
annotations:
summary: "{{ $labels.name }} entered failed state"
- alert: ContainerOOMKill
expr: increase(container_oom_events_total{id=~"/machine.slice/container@.+\\.service.*"}[5m]) > 0
labels:
severity: warning
annotations:
summary: "OOM kill in {{ $labels.id }}"
''
];
};
services.grafana = {
enable = true;
dataDir = "/var/lib/grafana";
settings = {
server.http_port = 3000;
server.http_addr = "127.0.0.1";
# WORKAROUND: Grafana 10+ requires an explicit secret_key; omitting it
# causes auth session tokens to be regenerated on every restart
security.secret_key = "SW2YcwTIb9zpOOhoPsMm";
"auth".disable_login_form = true;
"auth.anonymous" = {
enabled = true;
org_role = "Admin";
};
};
provision = {
enable = true;
datasources.settings = {
apiVersion = 1;
datasources = [
{
name = "Prometheus";
type = "prometheus";
uid = "prometheus";
access = "proxy";
url = "http://localhost:9090";
isDefault = true;
jsonData.timeInterval = "15s";
}
{
name = "Loki";
type = "loki";
uid = "loki";
access = "proxy";
url = "http://127.0.0.1:3100";
}
];
};
dashboards.settings = {
apiVersion = 1;
providers = [
{
name = "default";
type = "file";
disableDeletion = true;
options.path = toString dashboardDir;
}
];
};
};
};
services.nginx = {
enable = true;
virtualHosts."_" = {
listen = [
{
addr = "0.0.0.0";
port = 80;
ssl = false;
extraParameters = [ "default_server" ];
}
];
root = "${landingRoot}";
};
virtualHosts."stats.localhost" = {
listen = [
{
addr = "0.0.0.0";
port = 80;
ssl = false;
}
];
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
proxyWebsockets = true;
extraConfig = "proxy_set_header Host $host;";
};
};
virtualHosts."prometheus.localhost" = {
listen = [
{
addr = "0.0.0.0";
port = 80;
ssl = false;
}
];
locations."/" = {
proxyPass = "http://127.0.0.1:9090";
};
};
};
systemd.services = lib.genAttrs [ "loki" "alloy" "prometheus" "grafana" "nginx" ] (_: {
serviceConfig.FailureAction = "exit-force";
});
};
net.expose.tcp = [ 80 ];
resources.mem = "2G";
}
// {
hostConfig = {
services.prometheus.exporters.node = {
enable = true;
listenAddress = "0.0.0.0";
port = nodePort;
enabledCollectors = [
"systemd"
"processes"
];
disabledCollectors = [
"netstat"
"softnet"
];
# radeon sometimes breaks on kexec
extraFlags = [
"--collector.systemd.enable-task-metrics"
"--collector.hwmon.chip-exclude=radeon"
];
};
services.cadvisor = {
enable = true;
listenAddress = "0.0.0.0";
port = cadvPort;
};
};
};
hostAddr = c.hostAddr;
in
c
@@ -0,0 +1,61 @@
{ pkgs, lib }:
let
inherit (import ./helpers.nix { inherit pkgs lib; }) mkRow loki mkDashboard;
mkLogs =
{
title,
expr,
w ? 24,
h ? 10,
}:
{
inherit title;
type = "logs";
datasource = loki;
gridPos = { inherit w h; };
options = {
showTime = true;
showLabels = true;
sortOrder = "Descending";
wrapLogMessage = true;
enableLogDetails = true;
};
targets = [
{
datasource = loki;
inherit expr;
}
];
};
in
mkDashboard {
name = "access-logs.json";
title = "Access Logs";
uid = "access-logs";
from = "now-6h";
panels = [
(mkRow "HTTP")
(mkLogs {
title = "nginx (access + error)";
expr = ''{syslog_id="nginx"}'';
})
(mkRow "SSH")
(mkLogs {
title = "sshpiper (all connections)";
expr = ''{container="sshpiper"}'';
})
(mkLogs {
title = "Failed / invalid auth attempts (all backends, incl. host)";
expr = ''{syslog_id=~"sshd.*"} |~ "Failed|Invalid|error:"'';
})
(mkLogs {
title = "sshd auth events (all backends, incl. host)";
expr = ''{syslog_id=~"sshd.*"}'';
})
(mkLogs {
title = "Host sshd (port 5952)";
expr = ''{syslog_id=~"sshd.*", container=""}'';
})
];
}
@@ -0,0 +1,251 @@
{ pkgs, lib }:
let
inherit (import ./helpers.nix { inherit pkgs lib; }) prom mkDashboard;
in
mkDashboard {
name = "containers.json";
title = "Containers";
uid = "containers";
from = "now-3h";
panels = [
{
title = "Container States";
type = "piechart";
gridPos = {
h = 8;
w = 8;
};
datasource = prom;
options = {
pieType = "donut";
legend = {
displayMode = "table";
placement = "right";
values = [
"value"
"percent"
];
};
tooltip.mode = "single";
};
fieldConfig.overrides = [
{
matcher = {
id = "byName";
options = "active";
};
properties = [
{
id = "color";
value = {
mode = "fixed";
fixedColor = "green";
};
}
];
}
{
matcher = {
id = "byName";
options = "failed";
};
properties = [
{
id = "color";
value = {
mode = "fixed";
fixedColor = "red";
};
}
];
}
{
matcher = {
id = "byName";
options = "inactive";
};
properties = [
{
id = "color";
value = {
mode = "fixed";
fixedColor = "blue";
};
}
];
}
{
matcher = {
id = "byName";
options = "activating";
};
properties = [
{
id = "color";
value = {
mode = "fixed";
fixedColor = "yellow";
};
}
];
}
{
matcher = {
id = "byName";
options = "unknown";
};
properties = [
{
id = "color";
value = {
mode = "fixed";
fixedColor = "gray";
};
}
];
}
];
targets = [
{
datasource = prom;
expr = ''count by (state) ((label_replace(node_systemd_unit_state{name=~"container@.*"} == 1, "container", "$1", "name", "container@(.+)\\.service")) or on(container) label_replace(container_defined, "state", "unknown", "container", ".+"))'';
instant = true;
legendFormat = "{{state}}";
}
];
}
{
title = "Container States";
type = "table";
gridPos = {
h = 16;
w = 24;
};
datasource = prom;
options.footer.show = false;
fieldConfig = {
defaults = { };
overrides = [
{
matcher = {
id = "byName";
options = "State";
};
properties = [
{
id = "custom.displayMode";
value = "color-text";
}
{
id = "mappings";
value = [
{
type = "value";
options.active = {
text = "active";
color = "green";
index = 0;
};
}
{
type = "value";
options.failed = {
text = "failed";
color = "red";
index = 1;
};
}
{
type = "value";
options.activating = {
text = "activating";
color = "yellow";
index = 2;
};
}
{
type = "value";
options.inactive = {
text = "inactive";
color = "blue";
index = 3;
};
}
{
type = "value";
options.unknown = {
text = "unknown";
color = "gray";
index = 4;
};
}
];
}
];
}
];
};
targets = [
{
datasource = prom;
expr = ''
(label_replace(node_systemd_unit_state{name=~"container@.*"} == 1, "container", "$1", "name", "container@(.+)\\.service"))
or on(container)
label_replace(container_defined, "state", "unknown", "container", ".+")
'';
instant = true;
format = "table";
legendFormat = "__auto";
}
];
transformations = [
{
id = "organize";
options = {
excludeByName = {
Time = true;
Value = true;
"__name__" = true;
instance = true;
job = true;
name = true;
};
renameByName = {
container = "Container";
state = "State";
};
};
}
];
}
{
title = "Container State (1 = running, 0 = stopped/failed)";
type = "timeseries";
gridPos = {
h = 8;
w = 24;
};
datasource = prom;
fieldConfig.defaults = {
custom.lineWidth = 2;
color.mode = "palette-classic";
min = 0;
max = 1;
};
options = {
tooltip.mode = "multi";
legend = {
displayMode = "table";
placement = "bottom";
};
};
targets = [
{
datasource = prom;
expr = ''label_replace(node_systemd_unit_state{name=~"container@.*",state="active"}, "container", "$1", "name", "container@(.+).service")'';
legendFormat = "{{container}}";
}
];
}
];
}
+228
View File
@@ -0,0 +1,228 @@
{ pkgs, lib }:
let
prom = {
type = "prometheus";
uid = "prometheus";
};
loki = {
type = "loki";
uid = "loki";
};
autoLayout =
panels:
let
step =
acc: panel:
let
w = panel.gridPos.w;
h = panel.gridPos.h;
wrap = acc.x + w > 24;
x = if wrap then 0 else acc.x;
y = if wrap then acc.y + acc.rowH else acc.y;
rowH = if wrap then h else lib.max acc.rowH h;
in
{
x = x + w;
inherit y rowH;
result = acc.result ++ [
(
panel
// {
gridPos = panel.gridPos // {
inherit x y;
};
}
)
];
};
in
(lib.foldl' step {
x = 0;
y = 0;
rowH = 0;
result = [ ];
} panels).result;
T = expr: legendFormat: {
datasource = prom;
inherit expr legendFormat;
};
mkRow = title: {
inherit title;
type = "row";
collapsed = false;
panels = [ ];
gridPos = {
w = 24;
h = 1;
};
};
mkStat =
{
title,
w ? 4,
h ? 4,
expr,
unit ? "short",
decimals ? 2,
}:
{
inherit title;
type = "stat";
datasource = prom;
gridPos = { inherit w h; };
fieldConfig.defaults = {
inherit unit decimals;
color.mode = "thresholds";
thresholds = {
mode = "absolute";
steps = [
{
color = "blue";
value = null;
}
];
};
};
options = {
reduceOptions.calcs = [ "lastNotNull" ];
colorMode = "value";
textMode = "value";
};
targets = [
{
datasource = prom;
inherit expr;
instant = true;
legendFormat = "";
}
];
};
mkGauge =
{
title,
w ? 4,
h ? 4,
expr,
unit ? "percent",
min ? 0,
max ? 100,
}:
{
inherit title;
type = "gauge";
datasource = prom;
gridPos = { inherit w h; };
fieldConfig.defaults = {
inherit unit min max;
thresholds = {
mode = "absolute";
steps = [
{
color = "green";
value = null;
}
{
color = "yellow";
value = 70;
}
{
color = "red";
value = 90;
}
];
};
};
options = {
reduceOptions.calcs = [ "lastNotNull" ];
orientation = "auto";
showThresholdLabels = false;
showThresholdMarkers = true;
};
targets = [
{
datasource = prom;
inherit expr;
instant = true;
legendFormat = "";
}
];
};
mkTs =
{
title,
w ? 24,
h ? 8,
unit ? "short",
targets,
}:
{
inherit title targets;
type = "timeseries";
datasource = prom;
gridPos = { inherit w h; };
fieldConfig.defaults = {
inherit unit;
custom = {
lineWidth = 1;
fillOpacity = 5;
};
color.mode = "palette-classic";
};
options = {
tooltip.mode = "multi";
legend = {
displayMode = "table";
placement = "bottom";
calcs = [
"mean"
"max"
"lastNotNull"
];
};
};
};
mkDashboard =
{
name,
title,
uid,
from ? "now-1h",
panels,
templating ? [ ],
}:
pkgs.writeText name (
builtins.toJSON (
{
inherit title uid;
schemaVersion = 37;
refresh = "30s";
time = {
inherit from;
to = "now";
};
panels = lib.imap1 (id: p: p // { inherit id; }) (autoLayout panels);
}
// lib.optionalAttrs (templating != [ ]) { templating.list = templating; }
)
);
in
{
inherit
prom
loki
autoLayout
T
mkRow
mkStat
mkGauge
mkTs
mkDashboard
;
}
@@ -0,0 +1,167 @@
{ pkgs, lib }:
let
inherit (import ./helpers.nix { inherit pkgs lib; })
T
mkRow
mkStat
mkGauge
mkTs
mkDashboard
;
in
mkDashboard {
name = "host.json";
title = "Host";
uid = "host";
panels = [
(mkRow "Overview")
(mkGauge {
title = "CPU";
expr = ''100 * (1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])))'';
})
(mkGauge {
title = "Memory used";
expr = "100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)";
})
(mkStat {
title = "Load (1m)";
unit = "short";
decimals = 2;
expr = "node_load1";
})
(mkStat {
title = "Load (5m)";
unit = "short";
decimals = 2;
expr = "node_load5";
})
(mkStat {
title = "Uptime";
unit = "dtdurations";
decimals = 0;
expr = "node_time_seconds - node_boot_time_seconds";
})
(mkRow "CPU")
(mkTs {
title = "CPU usage (%)";
unit = "percent";
targets = [
(T ''avg(rate(node_cpu_seconds_total{mode="user"}[5m])) * 100'' "user")
(T ''avg(rate(node_cpu_seconds_total{mode="system"}[5m])) * 100'' "system")
(T ''avg(rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100'' "iowait")
(T ''avg(rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100'' "steal")
(T ''avg(rate(node_cpu_seconds_total{mode="softirq"}[5m])) * 100'' "softirq")
];
})
(mkTs {
title = "Per-core usage (%)";
unit = "percent";
targets = [
(T ''(1 - rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100'' "cpu{{cpu}}")
];
})
(mkTs {
title = "CPU temperatures";
unit = "celsius";
targets = [
(T "node_hwmon_temp_celsius" "{{chip}} {{sensor}}")
];
})
(mkTs {
title = "Load average";
targets = [
(T "node_load1" "1m")
(T "node_load5" "5m")
(T "node_load15" "15m")
];
})
(mkRow "Memory")
(mkTs {
title = "Memory";
unit = "bytes";
targets = [
(T "node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes" "used")
(T "node_memory_Cached_bytes + node_memory_Buffers_bytes" "cache + buffers")
(T "node_memory_MemAvailable_bytes" "available")
(T "node_memory_MemTotal_bytes" "total")
];
})
(mkTs {
title = "Swap";
unit = "bytes";
targets = [
(T "node_memory_SwapTotal_bytes - node_memory_SwapFree_bytes" "used")
(T "node_memory_SwapTotal_bytes" "total")
];
})
(mkRow "Disk")
(mkTs {
title = "Filesystem usage (%)";
unit = "percent";
targets = [
(T ''100 * (1 - node_filesystem_avail_bytes{fstype=~"btrfs|ext4|xfs|vfat|f2fs"} / node_filesystem_size_bytes{fstype=~"btrfs|ext4|xfs|vfat|f2fs"})'' "{{mountpoint}}")
];
})
(mkTs {
title = "Disk IO (bytes/s)";
unit = "Bps";
targets = [
(T ''rate(node_disk_read_bytes_total{device!~"loop.*"}[5m])'' "{{device}} read")
(T ''rate(node_disk_written_bytes_total{device!~"loop.*"}[5m])'' "{{device}} write")
];
})
(mkTs {
title = "Disk IO utilisation (%)";
unit = "percent";
targets = [
(T ''rate(node_disk_io_time_seconds_total{device!~"loop.*"}[5m]) * 100'' "{{device}}")
];
})
(mkRow "Network")
(mkTs {
title = "Network (bytes/s)";
unit = "Bps";
targets = [
(T ''rate(node_network_receive_bytes_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} rx")
(T ''rate(node_network_transmit_bytes_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} tx")
];
})
(mkTs {
title = "Network errors + drops (pps)";
targets = [
(T ''rate(node_network_receive_errs_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} rx err")
(T ''rate(node_network_transmit_errs_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} tx err")
(T ''rate(node_network_receive_drop_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} rx drop")
(T ''rate(node_network_transmit_drop_total{device!~"lo|br-.*|vh-.*|vc-.*"}[5m])'' "{{device}} tx drop")
];
})
(mkRow "System")
(mkTs {
title = "Context switches + forks (ops/s)";
targets = [
(T "rate(node_context_switches_total[5m])" "context switches")
(T "rate(node_forks_total[5m])" "forks")
];
})
(mkTs {
title = "File descriptors";
targets = [
(T "node_filefd_allocated" "allocated")
(T "node_filefd_maximum" "limit")
];
})
(mkTs {
title = "Processes";
targets = [
(T "node_procs_running" "running")
(T "node_procs_blocked" "blocked on IO")
];
})
];
}
@@ -0,0 +1,203 @@
{ pkgs, lib }:
let
inherit (import ./helpers.nix { inherit pkgs lib; })
T
mkRow
mkStat
mkTs
prom
mkDashboard
;
ctid = "id=~\"/machine.slice/container@.+\\\\.service/payload/.+\"";
ctsel = "id=~\"/machine.slice/container@$container\\\\.service/payload/.+\"";
ctall = "id=~\"/machine.slice/container@.+\\\\.service.*\"";
ctnet = "id=~\"/machine.slice/container@$container\\\\.service.*\"";
labeled =
m:
"label_replace(${m}, \"container\", \"$1\", \"id\", \"/machine.slice/container@(.+)\\\\.service/payload.+\")";
byContainer = m: "sum by (container) (${labeled m})";
labeledAll =
m:
"label_replace(${m}, \"container\", \"$1\", \"id\", \"/machine.slice/container@(.+)\\\\.service.*\")";
byContainerAll = m: "sum by (container) (${labeledAll m})";
nmSvc = m: "label_replace(${m}, \"container\", \"$1\", \"name\", \"container@(.+)\\\\.service\")";
orZero = m: fb: "(${m}) or on(container) (${fb} * 0)";
cpuAll =
rate:
orZero (byContainer "rate(container_cpu_usage_seconds_total{${ctid}}[${rate}])") "container_limit_cpu_cores";
memAll = orZero (byContainerAll "container_memory_rss{${ctall}}") "container_limit_memory_bytes";
taskAll = nmSvc "node_systemd_unit_tasks_current{name=~\"container@.+\"}";
in
mkDashboard {
name = "resources.json";
title = "Container Resources";
uid = "container-resources";
templating = [
{
name = "container";
type = "query";
datasource = prom;
query = "label_values(container_limit_cpu_cores, container)";
refresh = 2;
sort = 1;
includeAll = true;
multi = true;
current = {
selected = true;
text = [ "All" ];
value = [ "$__all" ];
};
}
];
panels = [
(mkRow "Overview")
(mkStat {
title = "Running";
decimals = 0;
expr = "count(node_systemd_unit_state{name=~\"container@.*\",state=\"active\"} == 1) or vector(0)";
})
(mkStat {
title = "CPU used";
decimals = 2;
expr = "sum(${cpuAll "5m"}) or vector(0)";
})
(mkStat {
title = "CPU limit";
decimals = 2;
expr = "sum(container_limit_cpu_cores) or vector(0)";
})
(mkStat {
title = "Mem RSS";
decimals = 1;
unit = "bytes";
expr = "sum(${memAll}) or vector(0)";
})
(mkStat {
title = "Mem limit";
decimals = 1;
unit = "bytes";
expr = "sum(container_limit_memory_bytes) or vector(0)";
})
(mkStat {
title = "Tasks";
decimals = 0;
expr = "sum(${taskAll}) or vector(0)";
})
(mkRow "All Containers")
(mkTs {
title = "CPU (cores)";
h = 24;
targets = [ (T (cpuAll "5m") "{{container}}") ];
})
(mkTs {
title = "Memory RSS";
unit = "bytes";
h = 24;
targets = [ (T memAll "{{container}}") ];
})
(mkTs {
title = "Tasks";
h = 24;
targets = [ (T taskAll "{{container}}") ];
})
(mkTs {
title = "CPU throttled %";
unit = "percent";
h = 12;
targets = [
(T "(${byContainer "rate(container_cpu_cfs_throttled_periods_total{${ctid}}[5m])"} / ${byContainer "rate(container_cpu_cfs_periods_total{${ctid}}[5m])"}) * 100 or on(container) (container_limit_cpu_cores * 0)" "{{container}}")
];
})
(mkTs {
title = "Network egress (bytes/s)";
unit = "Bps";
h = 24;
targets = [ (T "sum by (container) (container_network_receive_rate)" "{{container}}") ];
})
(mkTs {
title = "Network ingress (bytes/s)";
unit = "Bps";
h = 24;
targets = [ (T "sum by (container) (container_network_transmit_rate)" "{{container}}") ];
})
(mkTs {
title = "Disk read (bytes/s)";
unit = "Bps";
h = 24;
targets = [ (T (byContainer "rate(container_fs_reads_bytes_total{${ctid}}[5m])") "{{container}}") ];
})
(mkTs {
title = "Disk write (bytes/s)";
unit = "Bps";
h = 24;
targets = [
(T (byContainer "rate(container_fs_writes_bytes_total{${ctid}}[5m])") "{{container}}")
];
})
{
type = "row";
title = "$container";
repeat = "container";
collapsed = true;
panels = [ ];
gridPos = {
w = 24;
h = 1;
};
}
(mkTs {
title = "CPU (cores)";
targets = [
(T "sum(rate(container_cpu_usage_seconds_total{${ctsel}}[5m]))" "used")
(T "container_limit_cpu_cores{container=\"$container\"}" "limit")
];
})
(mkTs {
title = "CPU throttled %";
unit = "percent";
targets = [
(T "(sum(rate(container_cpu_cfs_throttled_periods_total{${ctsel}}[5m])) / sum(rate(container_cpu_cfs_periods_total{${ctsel}}[5m]))) * 100 or vector(0)" "throttled %")
];
})
(mkTs {
title = "Memory";
unit = "bytes";
targets = [
(T "sum(container_memory_rss{${ctnet}})" "RSS")
(T "sum(container_memory_working_set_bytes{${ctnet}})" "working set")
(T "container_limit_memory_bytes{container=\"$container\"}" "limit")
];
})
(mkTs {
title = "Network (bytes/s)";
unit = "Bps";
targets = [
(T "container_network_receive_rate{container=\"$container\"}" "{{device}} ↑")
(T "container_network_transmit_rate{container=\"$container\"}" "{{device}} ↓")
];
})
(mkTs {
title = "Disk IO (bytes/s)";
unit = "Bps";
targets = [
(T "sum(rate(container_fs_reads_bytes_total{${ctsel}}[5m]))" "read")
(T "sum(rate(container_fs_writes_bytes_total{${ctsel}}[5m]))" "write")
];
})
(mkTs {
title = "Tasks";
targets = [ (T "node_systemd_unit_tasks_current{name=\"container@$container.service\"}" "tasks") ];
})
];
}