syslet in diesem Repo¶
Diese Seite beschreibt, wie die Dateien unter syslet/ aufgeteilt sind und welche Konventionen wir beim Einsatz von syslet einhalten.
Wie syslet allgemein funktioniert, steht in der syslet-Doku; wie eine einzelne Stack-Datei aufgebaut ist, in Eine Stack-Datei lesen.
Aufbau von syslet/¶
| Datei | Inhalt |
|---|---|
syslet/syslet.cue |
gilt für alle Hosts: bindet syslet und seine Addons ein und erzeugt, was an den Host geht |
syslet/syslet_tool.cue |
die Befehle cue cmd plan, cue cmd apply und einige zum Nachsehen |
weitere Dateien direkt in syslet/ |
Gemeinsames für alle Hosts, etwa die Mail-Einstellungen in mailjet.cue oder die Backup-Skripte |
syslet/<host>/host.cue |
Name des Hosts (fqdn), Laden der Secrets, Speicherlimits aller Container |
syslet/<host>/infra-<name>.cue |
Dienste, die alle Apps des Hosts nutzen: Caddy und Backup |
syslet/<host>/stack-<app>.cue |
eine App mit allen ihren Containern, Volumes und Netzwerken |
syslet/<host>/creds-<name>.enc.yaml |
verschlüsselte Secrets |
Auf containerhost liegen Caddy und das Monitoring noch in stack-caddy.cue und stack-prom.cue.
Die Secrets lädt jeder Host in seiner eigenen host.cue, mit der Zeile secretFiles: _ @embed(…); in syslet.cue steht nur der Platzhalter secretFiles: _.
@embed liest relativ zum Ordner der Datei, also nur die creds-*.enc.yaml dieses Hosts.
Ein neuer Host braucht diese Zeile deshalb in seiner host.cue, sonst bekommt er keine Secrets.
Jede App hat eine eigene Datei.
Was zu einer App gehört, steht in einer Datei; eine App hinzuzufügen heißt, eine Datei anzulegen.
Nur die Speicherlimits stehen gesammelt in host.cue, damit man an einer Stelle sieht, wie viel Arbeitsspeicher alle Container eines Hosts zusammen belegen dürfen.
Ausrollen¶
Ausgerollt wird je Host aus seinem Ordner, mit cue cmd plan und cue cmd apply; wie, steht in Änderung ausrollen.
Ein Befehl wirkt immer nur auf einen Host
cue cmd plan und cue cmd apply arbeiten nur mit dem Host, in dessen Ordner man sie ausführt.
Betrifft eine Änderung beide Hosts, auch über eine gemeinsame Datei direkt in syslet/, muss man sie in beiden Ordnern nacheinander ausrollen.
Sonst bleibt der andere Host auf dem alten Stand, und das nächste plan dort zeigt die Änderung unerwartet an.
Im Ordner syslet/ selbst funktionieren die Befehle nicht, weil dort kein fqdn gesetzt ist.
CUE bricht dann mit reference "fqdn" not found ab, bevor es einen Host anspricht; man ist nur im falschen Ordner.
Jeder Host sieht nur seine Secrets und wird für sich ausgerollt.
Weil jeder Host seine Secrets in seiner eigenen host.cue lädt, muss nirgends eine Liste von Hosts gepflegt werden.
syslet läuft auf dem Host und kennt nur dessen Konfiguration; einen zentralen Dienst, der alle Hosts gemeinsam ausrollt, haben wir bewusst nicht (siehe Git-Workflow).
Konventionen¶
Dateien, Secrets und Labels heißen überall nach demselben Muster. So sieht eine Stack-Datei aus wie die andere. Eine neue App entsteht meist durch Kopieren einer ähnlichen, und wer eine Stack-Datei lesen kann, kann alle lesen.
Addons¶
Der Kern von sysdef kennt nur, was syslet selbst auf dem Host einrichtet: Container, Volumes, Netzwerke, Builds und Secrets.
Ein Addon ergänzt diesen Kern um ein Feld, in dem eine Stack-Datei allgemein beschreibt, was sie zusätzlich braucht.
Umgesetzt wird es von einer konkreten Software in einem eigenen Container, die die Einträge aller Stacks des Hosts ausliest.
Wir nutzen zwei Addons:
- Ingress:
ingress: <container>: { host, tls, containerPort }macht einen Container unter einem Hostnamen per HTTPS erreichbar (mittls: falsenur per HTTP). Umgesetzt von Caddy ininfra-caddy.cue; mehr in Ingress mit Caddy. - Backup:
backup: <app>: <volume>: [<pfade>]legt fest, was von einer App gesichert wird. Umgesetzt von restic ininfra-backup.cue; mehr in Backup.
Stack-Dateien müssen Caddy und restic nicht kennen.
Über die Addons trägt eine App nur Hostname und zu sichernde Volumes ein.
Wie Caddy und restic eingerichtet sind, steht einmal je Host in den infra--Dateien; dort sieht man auch, dass eine Änderung alle Apps des Hosts betrifft.
Ingress mit Caddy¶
Auf beiden Hosts läuft Caddy als Container und nimmt alle Anfragen auf den Ports 80 und 443 entgegen:
| Host | Datei | Netzwerk zu den Apps |
|---|---|---|
| werner | syslet/werner/infra-caddy.cue |
caddy; jede App, die von außen erreichbar sein soll, hängt ihren Container zusätzlich an dieses Netzwerk |
| containerhost | syslet/containerhost/stack-caddy.cue |
internal, an dem alle Container des Hosts hängen |
Eine App trägt in ihrer Stack-Datei einen Ingress-Eintrag ein, zum Beispiel am Ende von syslet/werner/stack-hedgedoc.cue:
| Text Only | |
|---|---|
Das heißt: Anfragen an md.garage-lab.de gehen per HTTPS an den Container hedgedoc-server, Port 3000.
Mit tls: false wäre die App nur per HTTP erreichbar.
Caddy liest die Einträge nicht selbst.
CUE erzeugt beim Ausrollen aus den Ingress-Einträgen aller Stacks des Hosts die Konfigurationsdatei von Caddy, das Caddyfile, über die Vorlage _caddyTemplate in der Caddy-Datei des Hosts.
Ändert sich die Datei, lässt syslet Caddy sie neu einlesen; der Container muss dafür nicht neu starten.
Für Sonderfälle kann ein Eintrag zusätzliche Caddy-Einstellungen mitgeben, etwa die Nextcloud für große Uploads (reverseProxyConfig, extraConfig in syslet/werner/stack-nextcloud-aio.cue).
Caddy reicht die Anfragen per HTTP an den Container weiter, lässt den Header Host unverändert und hängt X-Forwarded-For (die Adresse der Besucher) und X-Forwarded-Proto (https) an.
Ohne passende Einstellung sieht eine App als Absender nur Caddy und hält die Verbindung für unverschlüsselt; was eine App dafür braucht, steht auf ihrer Seite unter „Besonderheiten“.
Welche Hostnamen ein Host bedient, zeigt cue cmd ingress im Ordner des Hosts (definiert in syslet/syslet_tool.cue).
Damit der Hostname überhaupt beim richtigen Host ankommt, braucht er außerdem einen DNS-Eintrag (siehe DNS).
flowchart LR
stack["Stack-Datei<br>ingress: hedgedoc-server"]
cue["CUE<br>_caddyTemplate"]
caddyfile["Caddyfile<br>auf dem Host"]
caddy["Caddy"]
app["Container<br>hedgedoc-server"]
stack --> cue -->|cue cmd apply| caddyfile --> caddy
caddy -->|md.garage-lab.de| app
CUE erzeugt das Caddyfile. So gibt es keine Datei, die jemand von Hand pflegen muss und die mit den Stacks auseinanderlaufen kann. Eine App, die aus dem Repo verschwindet, verschwindet beim nächsten apply auch aus Caddy.
Labels¶
Jeder Container auf werner bekommt über #Labels aus syslet/werner/host.cue drei Container-Labels: zu welcher App er gehört (partOf), welche Rolle er darin hat (component) und welche Software darin läuft (name).
Das Monitoring gruppiert die Container danach; mehr in Monitoring.
Netzwerke und Locks¶
Am Ende jeder Stack-Datei stehen zwei Blöcke mit Hilfsdefinitionen aus syslet:
tools.#SysdefAssignNetwork hängt die Container an ihre Netzwerke, sodass alle Netzwerke eines Stacks an einer Stelle stehen.
tools.#SysdefLock sperrt jedes Volume mit Daten und die Container und Netzwerke dazu, damit syslet sie nicht löscht (Lock); wie man einen gesperrten Stack entfernt, steht in App entfernen.
Secret-Namen¶
Aus jedem Schlüssel in creds-<name>.enc.yaml wird ein Podman Secret <name>-<schlüssel>.
Wir benennen so:
- Die Datei heißt wie der Container, der die Secrets nutzt, etwa
creds-hedgedoc-server.enc.yaml; Secrets für mehrere Container nach dem Dienst, etwacreds-mailjet.enc.yaml. - Schlüssel klein und ohne Trennzeichen, für die Anmeldung über Authentik immer
oidcclientidundoidcclientsecret.
Aus oidcclientid in creds-hedgedoc-server.enc.yaml wird so hedgedoc-server-oidcclientid.
Wie die Secrets in die Container kommen, steht in Podman Secrets.
Weiterlesen¶
- Eine Stack-Datei lesen: HedgeDoc Block für Block
- CUE lesen
- Änderung ausrollen
- Spec types in der syslet-Doku: woraus syslet die Quadlets erzeugt
- How an apply works in der syslet-Doku
- Manage several hosts in der syslet-Doku