Zum Inhalt springen
Deutsch

Management — Überblick

managementRoutes(...) baut einen Route-Baum betrieblicher Endpunkte. Du bindest ihn auf einem eigenen Port (8558 per Konvention), getrennt vom Haupt-HTTP-Server deiner App, und exponierst:

  • Health-Probes — Liveness + Readiness für K8s.
  • Cluster-Info — Mitglieder, Leader, Sharding-Regionen.
  • Metriken — Prometheus-Exposition (optional).
  • Admin-Endpunkte — Leave / Down (optional, standardmäßig aus).
import { managementRoutes } from 'actor-ts/management';
// Build the routes (cluster is optional — pass null to skip /cluster/*),
// then bind them on a dedicated port.
const routes = managementRoutes(system, cluster, {
enableMetricsEndpoint: true,
});
const binding = await system.http(8558, { host: '0.0.0.0' }).bind(routes);
// management endpoints now serve on http://0.0.0.0:8558

managementRoutes gibt den Route-Baum zurück, den du bindest — sonst nichts. Die Checks hinter /health und /ready liegen auf der HealthCheckRegistry des ActorSystems, erreichbar über healthChecksOf(system): die Komponenten, denen ein Gesundheitssignal gehört, registrieren sich dort beim Start — lange bevor irgendwer einen Route-Baum baut — und deine eigenen Checks kommen auf dasselbe Objekt.

Das dritte Argument ist ManagementRoutesOptions — Endpunkt-Schalter und optionale Middleware. Port und Host sind keine Settings: sie gehen an system.http(port, { host }), und der cluster ist das zweite positionale Argument.

type ManagementRoutesOptionsType = {
enableLeaveEndpoint?: boolean; // POST /cluster/leave (default false)
enableDownEndpoint?: boolean; // POST /cluster/down (default false)
enableMetricsEndpoint?: boolean; // GET /metrics (default false)
auth?: Middleware; // guards /cluster/* (+ /metrics)
ipAllowlist?: Middleware; // guards EVERY endpoint, incl. /health + /ready
authProtectHealth?: boolean; // also require `auth` on /health + /ready (default false)
};

Eine typische Produktions-Verdrahtung:

const routes = managementRoutes(system, cluster, {
enableMetricsEndpoint: true, // for Prometheus
enableLeaveEndpoint: false, // admin-only; gate behind auth
enableDownEndpoint: false,
});
await system.http(8558).bind(routes);
EndpunktImmer an?Zweck
GET /health✓Liveness — 200 wenn jeder Liveness-Check besteht.
GET /ready✓Readiness — 200 wenn jeder Readiness-Check besteht (Cluster-Mitgliedschaft + -Konnektivität registriert das Framework selbst).
GET /cluster/membersWenn cluster gesetztMembership-JSON.
GET /cluster/leaderWenn cluster gesetztLeader-Adresse.
GET /cluster/shards?type=<name>Wenn cluster gesetzt, für einen Typ, an dem dieser Node teilnimmtShard-Verteilung für einen sharded Typ.
POST /cluster/leaveOpt-in (enableLeaveEndpoint)Graceful Cluster-Leave auslösen.
POST /cluster/downOpt-in (enableDownEndpoint)Peer per Adresse force-downen.
GET /metricsOpt-in (enableMetricsEndpoint)Prometheus-Textformat.

Siehe HTTP-Endpunkte für die volle Oberfläche + Response-Shapes.

Drei registriert das Framework bereits selbst — einen actor-system-Liveness-Check sowie die Readiness-Checks cluster-membership und cluster-transport, die Cluster.join installiert. Deine kommen dazu:

import { healthChecksOf, managementRoutes } from 'actor-ts/management';
// Readiness — gates traffic; return { name, status, detail? }.
healthChecksOf(system).addReadiness(async () => {
const ok = await database.ping();
return { name: 'database', status: ok, detail: ok ? undefined : 'database unreachable' };
});
await system.http(8558).bind(managementRoutes(system, cluster));

Checks hängen sich in /health (Liveness) und /ready (Readiness). Ein fehlschlagender Check lässt diesen Endpunkt 503 zurückgeben. Siehe Health Checks.

# In deinem Pod-Spec:
readinessProbe:
httpGet:
path: /ready
port: 8558
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8558
initialDelaySeconds: 30
periodSeconds: 10

K8s pollt diese Endpunkte, um zu entscheiden, ob der Pod Traffic bekommen soll (ready) oder neu gestartet werden soll (live). Siehe Kubernetes-Deployment für das vollständige Deployment-Rezept.

App-Port (8080): öffentlich, hinter einem Load Balancer
Management (8558): nur intern, intern firewall'd

Die Management-Endpunkte legen internen Zustand offen — Cluster-Mitgliederadressen, Metrikwerte usw. Sie öffentlich zu exponieren ist ein Sicherheitsrisiko. Binde sie auf einem separaten Port und firewall ihn intern.

In K8s ist das per-Pod — Probes treffen :8558 vom Kubelet (gleicher Node), aber kein Service exponiert es extern.

Für mehr Zugriffskontrolle:

# In deinem Service-/Ingress-Config:
# - 8080 → öffentlich
# - 8558 → nicht öffentlich exponiert; mTLS intern

Manche Produktivsysteme exponieren Management hinter einem Side-Car-Proxy, der Auth handhabt (Envoy + JWT, Linkerd + mTLS). Alternativ hängst du die eingebaute auth- / ipAllowlist- Middleware über die Settings an (siehe HTTP-Endpunkte).

managementRoutes gibt schlichte Routen zurück, du brauchst also gar keinen eigenen Port — concat sie in die bestehenden HTTP-Routen deiner App:

import { concat } from 'actor-ts/http';
import { managementRoutes } from 'actor-ts/management';
const mgmt = managementRoutes(system, cluster);
await system.http(8080).bind(concat(appRoutes, mgmt));

Zwei Gründe, das statt eines separaten Ports zu tun:

  1. Du hast schon einen HTTP-Server und möchtest Management inline.
  2. Single-Node-App ohne Cluster — Health-Checks allein rechtfertigen den Extra-Port vielleicht nicht; verdrahte /health in deinen bestehenden Server.

(Management auf dem öffentlichen Port zu mounten exponiert internen Zustand erneut — gate es mit den auth- / ipAllowlist-Settings, wenn du das tust.)