Zum Inhalt springen

pbx-agent

pbx-agent ist das Programm auf jedem Server von PaaSbox Clusters, das den Cluster in dem Zustand hält, den das Portal für ihn vorsieht. Diese Seite listet seine Befehle, Dateien, sein Protokoll, seine Operationen und sein Verhalten bei Fehlern, für den Fall, dass du selbst auf einen Node schaust oder genau wissen willst, was das Portal von ihm verlangen kann.

pbx-agent ist ein statisches Go-Programm, das systemd auf jedem k3s-Server eines Clusters von PaaSbox Clusters ausführt. Es ist kein KI-Agent. Es läuft als root, weil eine Wiederherstellung k3s anhalten und wieder starten muss, während die Kubernetes-API nicht erreichbar ist. Es lauscht auf keinem Port: Es ruft das Portal an, bringt den Node auf den Sollzustand, den es bekommt, und führt eine Operation nach der anderen aus einer festen Liste aus.

BefehlWas er tut
pbx-agent runDer Dienst: sich einmal registrieren, k3s starten, sich mit dem Portal abgleichen, den Sollzustand anwenden, Operationen ausführen. Das führt die systemd-Unit aus.
pbx-agent statusGibt den Zustand von pbx-agent als JSON aus, ohne jedes Geheimnis.
pbx-agent uninstallZeigt, was er entfernen würde, und ändert nichts. Mit --yes entfernt er den Agenten (unten).
pbx-agent versionGibt die Version und die IDs der eingebauten Release-Schlüssel aus.
pbx-agent simulateSimulierte Agenten, um das Portal zu testen, bis zu einem Lasttest mit 1.000; ändert nichts an der Maschine, auf der er läuft. Wird auf einem Node nicht benutzt.
PfadModusWas es ist
/etc/pbx-agent/config.yaml0600Die Adresse des Portals, die ID des Clusters, der Name des Nodes und das Registrierungs-Token, bis es benutzt ist. Von cloud-init geschrieben.
/etc/systemd/system/pbx-agent.serviceDie Unit. Von cloud-init geschrieben.
/var/lib/pbx-agent/0700Das Zustandsverzeichnis von pbx-agent.
/var/lib/pbx-agent/bin/pbx-agentDas Programm, daneben pbx-agent.prev (die vorige Version) und pbx-agent.new (während eines Updates).
/var/lib/pbx-agent/identity.json0600Die ID von pbx-agent und seine privaten Schlüssel: ein Ed25519-Schlüssel zum Signieren, ein X25519-Schlüssel, um versiegelte Geheimnisse zu empfangen; während eines Wechsels auch die vorigen Schlüssel.
/var/lib/pbx-agent/state.json0600Der zuletzt angewandte Sollzustand, die laufende Operation und ihr Schritt, und die IDs abgeschlossener Operationen (30 Tage aufbewahrt).
/var/lib/pbx-agent/bootstrap.json0600Die Antwort auf die Registrierung. Geheimnisse darin bleiben auf der Platte versiegelt.
/var/lib/pbx-agent/ops/<id>.logEin Log pro Operation. Die letzten 200 Zeilen gehen in einen Fehlerbericht.
/etc/rancher/k3s/config.yaml0600Die Konfiguration von k3s, einmal bei der Registrierung geschrieben.
/etc/rancher/k3s/config.yaml.d/50-pbx-*.yamlDie Drop-ins von pbx-agent: der Snapshot-Zeitplan und der Ingress-Modus.
/var/lib/rancher/k3s/server/manifests/pbx-*.yamlDie Manifeste, die k3s bei seinem ersten Start anwendet, etwa das des Cloud Controllers. Sobald pbx-agent dieses Add-on über die API verwaltet, schreibt er pbx-<name>.yaml.skip daneben, damit k3s die erste Fassung nicht mehr anwendet.

Das Programm liegt unter /var, weil /usr auf dem Node-Image nur lesbar ist; /var und das Overlay auf /etc überstehen Image-Updates.

Die Unit:

[Unit]
Description=pbx-agent
Wants=network-online.target
After=network-online.target
[Service]
Type=exec
ExecStart=/var/lib/pbx-agent/bin/pbx-agent run
Restart=always
RestartSec=5
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target

Die Logs: journalctl -u pbx-agent.

pbx-agent öffnet jede Verbindung, zu https://agents.<Domain des Portals>/agent/v1. JSON über HTTPS, Bodies von höchstens 256 KiB.

EndpunktZweckAuthentisiert durch
POST /enrollDas Registrierungs-Token gegen eine Identität und die Konfiguration des Nodes tauschenDas Registrierungs-Token
POST /syncDen Zustand des Nodes melden; den Sollzustand und höchstens eine Operation bekommenDie Signatur von pbx-agent
POST /operations/{id}/eventsFortschritt und Ergebnis einer Operation meldenDie Signatur von pbx-agent
GET /releases/{version}/manifestEin signiertes Release-Manifest holenDie Signatur von pbx-agent
POST /rotate-keyNeue öffentliche Schlüssel eintragen, signiert mit dem alten SchlüsselDie Signatur von pbx-agent

Signieren. Jede Anfrage nach der Registrierung trägt die ID von pbx-agent, einen Zeitstempel und eine Ed25519-Signatur über Methode, Pfad, Zeitstempel und einen SHA-256 des Bodys. Das Portal lehnt eine Zeitabweichung von mehr als 60 Sekunden ab und eine Signatur, die es in den letzten 120 Sekunden schon gesehen hat.

Versiegeln. Jedes Geheimnis, das das Portal schickt (k3s-Tokens, S3-Schlüssel, Hetzner-Tokens, Geheimnisse von Add-ons), ist mit einer libsodium Sealed Box an den X25519-Schlüssel von pbx-agent verschlüsselt. Kommt ein Geheimnis im Klartext an, lehnt pbx-agent das ganze Dokument ab (unsealed_secret).

Wie pbx-agent auf die Statuscodes des Portals reagiert

Abschnitt betitelt „Wie pbx-agent auf die Statuscodes des Portals reagiert“
Antwortpbx-agent
200wendet sie an
400protokolliert sie und wartet; schickt dieselbe Anfrage nie öfter als dreimal. Eine Antwort replayed (ein neu gestarteter pbx-agent hat dieselbe Anfrage in derselben Sekunde signiert) signiert er einmal neu mit der nächsten Sekunde.
401behandelt seine Identität als widerrufen: hört auf, sich abzugleichen, lässt den Cluster in Ruhe, läuft untätig weiter
409 clock_skewkorrigiert seine Zeitabweichung anhand der Zeit des Portals und versucht es erneut
426 protocol_too_oldaktualisiert sich auf den pbx-agent des Releases, das das Portal nennt, egal, was der Sollzustand sagt
429wartet so lange, wie das Portal sagt
5xx, kein Netzwartet exponentiell länger, von 5 Sekunden bis 5 Minuten, mit Zufallsanteil
  1. Beim ersten Start erzeugt pbx-agent seine Schlüssel und speichert sie, bevor er sie benutzt.
  2. Er liest die ID des Servers aus dem Metadatendienst von Hetzner.
  3. Er schickt das Registrierungs-Token, seine öffentlichen Schlüssel und den Hash des Boot-Images, das der Node tatsächlich gestartet hat. Das Portal prüft das Token (unbenutzt, nicht abgelaufen, an diesen Cluster und diesen Node-Namen gebunden), prüft über die Hetzner-API, dass der Server das Label des Clusters und den Namen des Nodes trägt, und vergleicht den Hash des Boot-Images mit dem Release.
  4. Er speichert die Antwort und löscht das Token aus seiner Konfiguration.
  5. Er schreibt die Konfiguration von k3s, startet k3s als Server, wartet auf die API und schreibt die Secrets kube-system/hcloud und kube-system/pbx-etcd-s3.
Das Portal antwortetBedeutungpbx-agent
200Identität und Konfigurationmacht weiter
401 invalid_token, token_used, token_expired, server_mismatchdas Token wird abgelehntversucht es höchstens dreimal, dann wartet er untätig; ein neues Token heißt ein neuer Server
409 image_mismatchder Node hat ein anderes Image gestartet als das seines Releaseswartet untätig; der Node braucht einen neuen Server aus dem richtigen Image
409 conflictdie Konfiguration kann noch nicht gebaut werdenversucht es mit wachsender Wartezeit erneut
503 internaldas Portal erreicht die Hetzner-API nichtversucht es mit wachsender Wartezeit erneut
429zu viele Anfragenwartet so lange, wie das Portal sagt

Dasselbe Token mit denselben Schlüsseln vom selben Server bekommt wieder dieselbe Antwort; eine Antwort, die unterwegs verloren geht, kann pbx-agent also gefahrlos erneut anfragen.

Etwa alle 30 Sekunden (± 5) schickt pbx-agent seinen Bericht und bekommt den Sollzustand. In jedem Durchgang gleicht er in dieser Reihenfolge an: sein eigenes Update, die Konfiguration des Hosts (Drop-ins für k3s), die Konfiguration des Clusters (Secrets, Add-ons), dann die Operation. Die Konfiguration des Clusters wendet er alle 10 Minuten neu an, auch ohne Änderung; eine Änderung von Hand an einem verwalteten Objekt wird also überschrieben.

Ein Sollzustand wird als Ganzes angewandt. Sein Release-Manifest wird zuerst geholt und geprüft; ein Manifest, das kein eingebauter Schlüssel bestätigt, ändert nichts (manifest_rejected).

Ein Drop-in, das einen Neustart von k3s braucht, wird sofort geschrieben; der Neustart folgt im nächsten Moment innerhalb des Wartungsfensters, nie während einer Operation. In Arbeit Das ist auf einem echten Node noch nicht gelaufen.

In einem Cluster mit mehr als einem Server führt ein pbx-agent: der Inhaber des Lease pbx-system/pbx-agent-leader. Auf einem einzelnen Node führt sein pbx-agent, solange die Kubernetes-API läuft.

pbx-agent wendet jedes Add-on aus der Vorlage im signierten Release an, mit den Optionen aus dem Sollzustand.

WasWie
Objekte, die er anlegen darfHelmChart- und HelmChartConfig-Objekte, Secrets namens pbx-addon-* in kube-system und für die PaaSbox Platform eine clusterweite Platform, benannt nach dem Cluster
Labelspbx.io/managed=true an jedem verwalteten Objekt, pbx.io/addon=<name> an den Objekten eines Add-ons
Geheime OptionenNur in einem Secret pbx-addon-<name>, das das Chart liest, nie in einem HelmChart: k3s verschlüsselt Secrets im Ruhezustand, Custom Resources nicht
AbgeschaltetSeine Objekte werden gelöscht; Daten, Volumes und CRDs bleiben. Die Secrets hcloud und pbx-etcd-s3 werden nie gelöscht.
Eine Vorlage oder ein Anwenden, das fehlschlägtDas Add-on meldet failed und behält die Objekte, die es hat: Eine fehlgeschlagene Vorlage deinstalliert nie ein laufendes Chart

Jedes Add-on meldet einen Zustand: applied, pending, failed oder removed.

FallZustand
Ein Add-on, das es braucht, ist ausfailed: braucht das Add-on <r>, das aus ist
Ein Add-on, mit dem es sich nicht verträgt, ist an und installiertfailed: verträgt sich nicht mit dem Add-on <c>; schalte das zuerst ab
Ein solches Add-on ist aus, seine Objekte gibt es nochpending, bis sie weg sind
Ein Add-on, das es braucht, ist noch nicht appliedpending
Angewandt, seine Gesundheitsprüfung besteht noch nichtpending; pbx-agent wendet die Konfiguration des Clusters in jedem Durchgang an, bis sie besteht
Angewandt, seine Gesundheitsprüfung besteht, oder es hat keineapplied
Abgeschaltet, während ein Add-on an ist, das es brauchtfailed: wird noch gebraucht

Gebaut im Labor: Das Add-on PaaSbox Platform wird in zwei Schritten abgeschaltet. Solange es eine SaaSApplication gibt, ändert Abschalten nichts: Das Add-on meldet failed mit den Namen der Anwendungen. Lösche sie zuerst. Dann wendet pbx-agent eine Platform an, die nichts installiert, und wartet, bis Flux entfernt hat, was die Plattform installiert hat. Eine Platform, die das Entfernen ablehnt (eine Datenbank, oder eine Anwendung, die noch einen Teil von ihr braucht), behält alles und meldet das Add-on mit ihrer Nachricht als failed.

Pro Cluster läuft eine Operation zur Zeit. Jede ist eine Liste benannter Schritte, die sich gefahrlos wiederholen lassen; pbx-agent hält den Schritt fest, bevor er ihn beginnt, und setzt nach einem Absturz oder Neustart dort fort. Ein fehlgeschlagener Schritt meldet seinen Namen und die letzten 200 Zeilen seines Logs. Zerstörende Schritte wiederholt pbx-agent nie von sich aus.

OperationSchritteWas sie tut
snapshot.savesave, confirm_s3, reportMacht einen etcd-Snapshot und bestätigt, dass er im Bucket angekommen ist
cluster.restorestop_k3s, reset_restore, start_k3s, wait_api, forget_stale_nodesSetzt den Zustand des Clusters auf einen Snapshot zurück; siehe Snapshots machen und wiederherstellen
cluster.upgradepreflight, pre_snapshot, fetch_image, stage_slot, reboot, health_gate, commitAktualisiert das Node-Image an Ort und Stelle; siehe Einen Cluster upgraden
access.issueensure_sa, token, sealStellt eine Kubeconfig aus, versiegelt an den Schlüssel dessen, der gefragt hat: deinen Browser oder den eigenen Schlüssel eines Agenten
access.revokedelete_saLöscht die ServiceAccounts einer Person oder die aller
agent.rotate_keygenerate, register, confirmErsetzt die eigenen Schlüssel von pbx-agent; das Portal verlangt das, wenn sie 90 Tage alt sind
s3.verifylist_bucketListet den Bucket mit neuen Schlüsseln, bevor sie benutzt werden
diag.collectcollectVersionen, Zustände der Units und die letzten Zeilen der Logs von k3s und pbx-agent, nur mit deiner Zustimmung für genau diese Anfrage; nie Secrets, Tokens oder Umgebungsdateien
server.rejoin, node.drain, node.forgetFür Cluster mit mehr als einem Server; auf einem einzelnen Node nicht benutzt

Wie die Schritte entscheiden, wo es darauf ankommt:

  • reset_restore legt den Snapshot selbst auf den Node, aus der lokalen Kopie von k3s oder mit dem eigenen S3-Client von pbx-agent aus dem Bucket geholt, entpackt ihn und startet k3s server --cluster-reset mit --etcd-s3=false. Die S3-Schlüssel landen nie auf einer Kommandozeile oder in der Umgebung von k3s.
  • forget_stale_nodes löscht einen anderen Node als den eigenen, dessen Kubelet sich nicht gemeldet hat, seit die wiederhergestellte API läuft, nach einer Frist von 2 Minuten.
  • cluster.upgrade macht den Snapshot pbx-pre-upgrade-<release>, legt das neue Image als Boot-Eintrag pbx-<release>-<arch>.efi an und behält zwei Einträge, den neuen und den, von dem es kam. Die Gesundheitsprüfung wartet auf die API, den Node Ready mit dem neuen k3s, den neuen Boot-Eintrag und jedes Deployment in kube-system verfügbar. Ein Node, der 20 Minuten nach dem Neustart nicht gesund ist, wird in den alten Eintrag neu gestartet. In Arbeit Diese Rückkehr hat auf einem echten Node noch nicht ausgelöst.
  • reset_restore und reboot sind die zerstörenden Schritte. Nach einem Absturz in einem davon prüft pbx-agent, was der Node zeigt: nicht begonnen, dann läuft er; abgeschlossen, dann geht es weiter; alles andere ist failed und läuft nie von sich aus erneut.

Eine unbekannte Operation wird als nicht unterstützt beantwortet. Es gibt keine Operation, die einen Befehl ausführt, den du oder jemand anderes eintippt.

Ist die Kubernetes-API nicht erreichbar, nimmt pbx-agent nur cluster.restore und diag.collect an.

Lagepbx-agent
Das Portal ist nicht erreichbarbehält den letzten Sollzustand und versucht es mit wachsender Wartezeit erneut; k3s macht weiter die geplanten Snapshots
Die Kubernetes-API ist nicht erreichbarmeldet das und nimmt nur Operationen auf Host-Ebene an: Wiederherstellung und Diagnose
Ein Schritt einer Operation schlägt fehlhält an, meldet den Schritt und die letzten 200 Log-Zeilen; wiederholt einen zerstörenden Schritt nie von sich aus
Die Signatur eines Release-Manifests ist ungültiglehnt es ab, meldet manifest_rejected, ändert nichts
Ein Geheimnis kommt im Klartext anlehnt das ganze Dokument ab, meldet unsealed_secret, ändert nichts
pbx-agent ist widerrufenhört auf, sich abzugleichen, und lässt den Cluster, wie er ist

Nennt der Sollzustand eine andere Version von pbx-agent, holt er das Release-Manifest, nimmt das Programm für seine Architektur, prüft dessen SHA-256, behält das laufende Programm als pbx-agent.prev, stellt einen Rückkehr-Timer auf 10 Minuten, tauscht die Programme und startet neu. Der erste erfolgreiche Abgleich mit dem Portal entschärft den Timer. Löst er aus, wird das vorige Programm zurückgelegt. Ein pbx-agent, der sich zurückgerollt findet, meldet das und versucht diese Version sechs Stunden lang nicht wieder.

pbx-agent vertraut nur Release-Manifesten, die mit einem der beiden eingebauten Release-Schlüssel signiert sind. Nichts zur Laufzeit kann diese Schlüssel ändern. Ein pbx-agent, der ohne sie gebaut wurde, lehnt jedes Manifest ab: Er aktualisiert sich nie und upgradet den Node nie. Releases und Kanäle beschreibt das Signieren.

Terminal-Fenster
pbx-agent uninstall --yes

Schaltet die Unit und den Rückkehr-Timer ab und entfernt sie, entfernt /var/lib/pbx-agent und /etc/pbx-agent. k3s, seine Konfiguration und jedes Kubernetes-Objekt bleiben. Ohne --yes zeigt er, was er tun würde, und ändert nichts. In Arbeit Auf einem echten Node noch nicht gelaufen. Einen Cluster abkoppeln oder löschen sagt, wann du ihn benutzt.