kube-state-metrics (NodePort 30808) und ServiceAccount prometheus-infra (nur nodes/metrics) im Cluster; Prometheus auf infra liest kubelet/cAdvisor per TLS gegen die k3s-CA. Ziele per file_sd aus kubectl get nodes, cAdvisor auf die nötigen Reihen begrenzt. Dashboard "k3s – Pods" (Vorgabe nex), Alerts K3s* nur mit notify. Playbook monitoring-k3s.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
abf4a75063
commit
4ac251715e
@@ -18,6 +18,11 @@ Registry (die kennt je Slot nur eine VM, die zweite Embedding-Instanz fehlt dort
|
||||
`--llamacpp '{"gpu-pve44": ["embed"], ...}'`. Die Slots eines Dienstes kommen aus der Registry
|
||||
(engine llamacpp, gleicher Container). Labels zusätzlich docker_host (= VM) und container, damit der
|
||||
Healer die tatsächliche VM trifft. Diese Slots zählen auch für node/gpu der VM.
|
||||
|
||||
k3s (Task 6.5): Mit `--k3s-nodes DATEI` (Ausgabe von `kubectl get nodes -o json`) entstehen zusätzlich
|
||||
DIR/kubelet.json (jeder Knoten, Port 10250, für die Jobs kubelet und cadvisor) und
|
||||
DIR/kube-state-metrics.json (ein Ziel: NodePort auf der Dienst-VM k3s, sonst auf dem ersten bereiten Knoten).
|
||||
Ohne die Option bleiben beide Listen leer.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -35,6 +40,9 @@ LLAMACPP_PROFILES = {
|
||||
"embed": [("llamacpp-embed", 8081), ("llamacpp-rerank", 8082)],
|
||||
"chat": [("llamacpp-chat", 8080)],
|
||||
}
|
||||
KUBELET_PORT = 10250
|
||||
KSM_NODEPORT = 30808 # deploy/k8s/monitoring/kube-state-metrics.yaml
|
||||
K3S_SERVER = "k3s" # Dienst-VM mit der Steuerung (HA), bevorzugtes Ziel für kube-state-metrics
|
||||
|
||||
|
||||
def slots_by_vmid(registry: dict) -> dict[str, list[str]]:
|
||||
@@ -89,11 +97,41 @@ def build_targets(gpu_vms: dict, registry: dict,
|
||||
return result
|
||||
|
||||
|
||||
def _internal_ip(node: dict) -> str | None:
|
||||
return next((a["address"] for a in node.get("status", {}).get("addresses", [])
|
||||
if a.get("type") == "InternalIP"), None)
|
||||
|
||||
|
||||
def _ready(node: dict) -> bool:
|
||||
return any(c.get("type") == "Ready" and c.get("status") == "True"
|
||||
for c in node.get("status", {}).get("conditions", []))
|
||||
|
||||
|
||||
def build_k3s_targets(nodes: dict) -> dict[str, list[dict]]:
|
||||
"""Ziele aus `kubectl get nodes -o json`. instance ist der Knotenname (bleibt bei IP-Wechsel gleich)."""
|
||||
kubelet: list[dict] = []
|
||||
ready: list[tuple[str, str]] = []
|
||||
for node in sorted(nodes.get("items", []), key=lambda n: n["metadata"]["name"]):
|
||||
name, ip = node["metadata"]["name"], _internal_ip(node)
|
||||
if not ip:
|
||||
print(f"Warnung: k3s-Knoten {name} ohne InternalIP, übersprungen", file=sys.stderr)
|
||||
continue
|
||||
kubelet.append({"targets": [f"{ip}:{KUBELET_PORT}"], "labels": {"instance": name, "node": name}})
|
||||
if _ready(node):
|
||||
ready.append((name, ip))
|
||||
ksm: list[dict] = []
|
||||
if ready:
|
||||
_, ip = next((r for r in ready if r[0] == K3S_SERVER), ready[0])
|
||||
ksm.append({"targets": [f"{ip}:{KSM_NODEPORT}"], "labels": {"instance": "kube-state-metrics"}})
|
||||
return {"kubelet": kubelet, "kube-state-metrics": ksm}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
ap.add_argument("--registry", required=True, type=Path)
|
||||
ap.add_argument("--out", required=True, type=Path)
|
||||
ap.add_argument("--llamacpp", default="{}", help='JSON {"<vm>": ["embed"|"chat", ...]} aus dem Inventar')
|
||||
ap.add_argument("--k3s-nodes", type=Path, help="Ausgabe von `kubectl get nodes -o json` (Task 6.5)")
|
||||
args = ap.parse_args()
|
||||
|
||||
gpu_vms = json.load(sys.stdin)
|
||||
@@ -103,6 +141,8 @@ def main() -> int:
|
||||
if unknown:
|
||||
ap.error(f"unbekannte llama.cpp-Profile: {sorted(unknown)}")
|
||||
targets = build_targets(gpu_vms, registry, llamacpp)
|
||||
k3s_nodes = json.loads(args.k3s_nodes.read_text(encoding="utf-8")) if args.k3s_nodes else {}
|
||||
targets.update(build_k3s_targets(k3s_nodes))
|
||||
args.out.mkdir(parents=True, exist_ok=True)
|
||||
for job, entries in targets.items():
|
||||
path = args.out / f"{job}.json"
|
||||
|
||||
Reference in New Issue
Block a user