51d1caa509
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
486 lines
10 KiB
Markdown
486 lines
10 KiB
Markdown
# Kestra Scripts
|
||
|
||
Dieses Repository enthält Kestra-Flows und Hilfsskripte für Homelab-Automatisierung.
|
||
|
||
Aktuell enthalten:
|
||
|
||
* `docker_stack_inventory_scan.yaml`
|
||
* `build_select_options.py`
|
||
* `linux_apt-upgrade.yaml`
|
||
* `hetzner-vm-provision.yaml`
|
||
* `hetzner-server-type-location-update.yaml`
|
||
* `hetzner-server-available-list.yaml`
|
||
* `hetzner-vm-destroy.yaml`
|
||
* `.env.example`
|
||
|
||
Der erste Flow scannt mehrere Docker-Hosts per SSH, sucht nach Docker-Compose-Stacks und schreibt daraus eine Dropdown-Liste in den Kestra KV-Store.
|
||
|
||
---
|
||
|
||
## Zweck
|
||
|
||
Dieses Repository trennt bewusst:
|
||
|
||
* **Kestra-Flow**: Ablaufsteuerung und Orchestrierung
|
||
* **Python-Script**: Verarbeitung der Scan-Ergebnisse
|
||
* **Secrets / Zugangsdaten**: außerhalb des Repositories über `.env` bzw. Kestra Secrets
|
||
|
||
Damit bleibt der Flow übersichtlich, wartbar und sicherer.
|
||
|
||
---
|
||
|
||
## Dateien
|
||
|
||
### `docker_stack_inventory_scan.yaml`
|
||
|
||
Kestra-Flow zum Scannen mehrerer Docker-Hosts.
|
||
|
||
Der Flow:
|
||
|
||
1. verbindet sich per SSH mit definierten Docker-Hosts
|
||
2. durchsucht dort ein Basisverzeichnis nach Compose-Dateien
|
||
3. sammelt gefundene Docker-Stacks ein
|
||
4. übergibt die Ergebnisse an ein Python-Script
|
||
5. schreibt die fertige Dropdown-Liste in den Kestra KV-Store
|
||
|
||
Gesucht werden unter anderem:
|
||
|
||
```text
|
||
compose.yml
|
||
compose.yaml
|
||
docker-compose.yml
|
||
docker-compose.yaml
|
||
```
|
||
|
||
---
|
||
|
||
### `build_select_options.py`
|
||
|
||
Python-Script zum Zusammenführen der Scan-Ergebnisse.
|
||
|
||
Das Script liest die Umgebungsvariable:
|
||
|
||
```text
|
||
OPTIONS_B64_JSON
|
||
```
|
||
|
||
Darin erwartet es eine JSON-Liste mit Base64-codierten Host-Ergebnissen.
|
||
|
||
Ausgabe:
|
||
|
||
```text
|
||
select_options.json
|
||
```
|
||
|
||
Diese Datei wird anschließend vom Kestra-Flow in den KV-Store geschrieben.
|
||
|
||
---
|
||
|
||
### `linux_apt-upgrade.yaml`
|
||
|
||
Kestra-Flow zum Ausführen von `apt update && apt upgrade` auf einem Linux-Server per SSH.
|
||
|
||
Der Flow:
|
||
|
||
1. verbindet sich per SSH mit dem Zielserver
|
||
2. erkennt automatisch ob der Benutzer root ist oder sudo benötigt
|
||
3. führt `apt-get update` und `apt-get upgrade` aus
|
||
4. meldet ob ein Reboot erforderlich ist
|
||
|
||
Der Flow wird manuell gestartet und erwartet folgende Eingaben:
|
||
|
||
| Input | Beschreibung |
|
||
|---|---|
|
||
| `host` | Server IP oder Hostname |
|
||
| `user` | SSH-Benutzer |
|
||
| `sudo_password` | Sudo-Passwort (Kestra Secret) |
|
||
|
||
Benötigtes Kestra Secret:
|
||
|
||
```text
|
||
SSH_PRIVATE_KEY
|
||
```
|
||
|
||

|
||
|
||
---
|
||
|
||
### `hetzner-vm-provision.yaml`
|
||
|
||
Kestra-Flow zum Provisionieren einer Hetzner Cloud VM via Terraform — mit KI-gestützter Plan-Analyse und manuellem Approval-Gate.
|
||
|
||
**Namespace:** `hetzner`
|
||
|
||
Der Flow läuft in vier Phasen:
|
||
|
||
1. **Terraform Plan** — erstellt einen Plan für die neue VM (Ubuntu 24.04) im Hetzner-Datacenter; Terraform State wird im S3-Backend (Hetzner Object Storage) gespeichert
|
||
2. **LLM-Analyse** — GPT-4o-mini fasst den Plan auf Deutsch zusammen und bewertet ob er sicher aussieht
|
||
3. **Approval-Gate** — Kestra pausiert und wartet auf manuelle Freigabe
|
||
4. **Terraform Apply / Abbruch** — bei Freigabe wird die VM erstellt und die IPv4-Adresse ausgegeben; bei Ablehnung wird die Execution abgebrochen
|
||
|
||
Der Flow erwartet folgende Eingaben:
|
||
|
||
| Input | Typ | Beschreibung |
|
||
|---|---|---|
|
||
| `vm_name` | STRING | Eindeutiger VM-Name, z.B. `dev-server-01` |
|
||
| `server_type` | SELECT | `cx23` (2 vCPU / 4 GB) · `cx33` · `cx43` · `cx53` |
|
||
| `location` | SELECT | `nbg1` · `fsn1` · `hel1` |
|
||
| `team` | STRING | Label für die VM |
|
||
|
||
Benötigte Kestra Secrets:
|
||
|
||
```text
|
||
HCLOUD_TOKEN
|
||
SSH_KEY_NAME
|
||
AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY
|
||
TF_BACKEND_BUCKET
|
||
TF_BACKEND_ENDPOINT
|
||
OPENAI_API_KEY
|
||
```
|
||
|
||

|
||
|
||
---
|
||
|
||
### `hetzner-server-type-location-update.yaml`
|
||
|
||
Kestra-Flow zum automatischen Aktualisieren der verfügbaren Hetzner Server-Typen und Standorte.
|
||
|
||
**Namespace:** `hetzner`
|
||
**Trigger:** Alle 15 Minuten, täglich 07:00–21:00 Uhr (Europe/Berlin)
|
||
|
||
Der Flow:
|
||
|
||
1. **Hetzner API abfragen** — ruft die aktuellen Server-Typen (`cx23`, `cx33`, `cpx42`) und deren verfügbare Standorte (`nbg1`, `fsn1`, `hel1`) ab
|
||
2. **Dropdown-Matrix bauen** — erzeugt eine kombinierte Server-Type/Location-Liste im Format `cx23|nbg1`
|
||
3. **MinIO/S3 Upload** — schreibt beide JSON-Dateien ins S3-Backend unter `inventory/`
|
||
4. **KV-Store setzen** — speichert die Dropdown-Optionen unter dem Key `hetzner_server_type_location_options`
|
||
|
||
Ausgaben:
|
||
|
||
| Ziel | Pfad / Key |
|
||
|---|---|
|
||
| S3 | `inventory/hetzner-server-types.json` |
|
||
| S3 | `inventory/hetzner-server-type-location-options.json` |
|
||
| KV-Store | `hetzner_server_type_location_options` |
|
||
|
||
Benötigte Kestra Secrets:
|
||
|
||
```text
|
||
HCLOUD_TOKEN
|
||
AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY
|
||
TF_BACKEND_BUCKET
|
||
TF_BACKEND_ENDPOINT
|
||
```
|
||
|
||
---
|
||
|
||
### `hetzner-server-available-list.yaml`
|
||
|
||
Kestra-Flow zum automatischen Abrufen aller laufenden Hetzner Cloud Server.
|
||
|
||
**Namespace:** `hetzner`
|
||
**Trigger:** Alle 15 Minuten, täglich 07:00–21:00 Uhr (Europe/Berlin)
|
||
|
||
Der Flow:
|
||
|
||
1. **Hetzner API abfragen** — ruft alle vorhandenen Server ab (Name, Status, IPv4, Server-Typ, Standort, Labels, Erstelldatum)
|
||
2. **Servernamen extrahieren** — erzeugt eine separate JSON-Liste mit nur den Namen für Kestra-Dropdowns
|
||
3. **MinIO/S3 Upload** — schreibt beide JSON-Dateien ins S3-Backend unter `inventory/`
|
||
4. **KV-Store setzen** — speichert die Servernamen unter dem Key `hetzner_server_names`
|
||
|
||
Ausgaben:
|
||
|
||
| Ziel | Pfad / Key |
|
||
|---|---|
|
||
| S3 | `inventory/hetzner-server-available.json` (vollständige Serverdaten) |
|
||
| S3 | `inventory/hetzner-server-names.json` (nur Namen) |
|
||
| KV-Store | `hetzner_server_names` |
|
||
|
||
Benötigte Kestra Secrets:
|
||
|
||
```text
|
||
HCLOUD_TOKEN
|
||
AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY
|
||
TF_BACKEND_BUCKET
|
||
TF_BACKEND_ENDPOINT
|
||
```
|
||
|
||
---
|
||
|
||
### `hetzner-vm-destroy.yaml`
|
||
|
||
Kestra-Flow zum sicheren Löschen einer Hetzner Cloud VM via Terraform — mit Destroy-Plan, manuellem Approval-Gate und automatischer Inventar-Aktualisierung.
|
||
|
||
**Namespace:** `hetzner`
|
||
**Trigger:** Manuell (kein Schedule)
|
||
|
||
Der Flow läuft in vier Phasen:
|
||
|
||
1. **Terraform Destroy Plan** — erstellt einen Destroy-Plan für die gewählte VM; lädt den Terraform State aus dem S3-Backend
|
||
2. **Plan-Ausgabe loggen** — zeigt den vollständigen Destroy-Plan im Kestra-Log zur manuellen Prüfung
|
||
3. **Approval-Gate** — Kestra pausiert und wartet auf manuelle Freigabe
|
||
4. **Destroy / Abbruch** — bei Freigabe wird die VM gelöscht und anschließend automatisch der Subflow `hetzner-server-available-list` ausgeführt, um Inventar und KV-Store zu aktualisieren; bei Ablehnung wird abgebrochen
|
||
|
||
Die VM wird per dynamischem Dropdown aus dem KV-Key `hetzner_server_names` ausgewählt (befüllt durch `hetzner-server-available-list`).
|
||
|
||
Benötigte Kestra Secrets:
|
||
|
||
```text
|
||
HCLOUD_TOKEN
|
||
SSH_KEY_NAME
|
||
AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY
|
||
TF_BACKEND_BUCKET
|
||
TF_BACKEND_ENDPOINT
|
||
```
|
||
|
||
---
|
||
|
||
### `.env.example`
|
||
|
||
Beispiel-Datei für benötigte Umgebungsvariablen und Secrets.
|
||
|
||
Die Datei enthält bewusst nur Platzhalter.
|
||
|
||
Die echte `.env` darf nicht ins Git-Repository committed werden.
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
Repository klonen:
|
||
|
||
```bash
|
||
git clone https://git.unixweb.net/joachim/kestra-scripts.git
|
||
cd kestra-scripts
|
||
```
|
||
|
||
Beispiel-Umgebung kopieren:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
Danach die Werte in `.env` anpassen.
|
||
|
||
---
|
||
|
||
## Kestra Secrets
|
||
|
||
Der Flow verwendet Kestra Secrets, zum Beispiel:
|
||
|
||
```yaml
|
||
privateKey: "{{ secret('SSH_PRIVATE_KEY') }}"
|
||
```
|
||
|
||
Bei Kestra OSS müssen `SECRET_*` Werte in der `.env` base64-codiert hinterlegt werden.
|
||
|
||
Beispiel Linux:
|
||
|
||
```bash
|
||
echo -n "mein-geheimer-wert" | base64 -w 0
|
||
```
|
||
|
||
Beispiel macOS:
|
||
|
||
```bash
|
||
echo -n "mein-geheimer-wert" | base64
|
||
```
|
||
|
||
Beispiel für einen SSH Private Key:
|
||
|
||
```bash
|
||
base64 -w 0 ~/.ssh/id_ed25519
|
||
```
|
||
|
||
Dann in `.env` eintragen:
|
||
|
||
```env
|
||
SECRET_SSH_PRIVATE_KEY=base64_encoded_private_ssh_key
|
||
```
|
||
|
||
---
|
||
|
||
## Docker Stack Inventory Scan
|
||
|
||
Der Flow befindet sich in:
|
||
|
||
```text
|
||
docker_stack_inventory_scan.yaml
|
||
```
|
||
|
||
Wichtige Variablen im Flow:
|
||
|
||
```yaml
|
||
variables:
|
||
ssh_user: meinuser
|
||
base_dir: /home/meinuser/docker
|
||
kv_select_options_key: docker_stack_select_options
|
||
```
|
||
|
||
Die Docker-Hosts werden im Flow als Liste definiert:
|
||
|
||
```yaml
|
||
docker_hosts:
|
||
- docker1;192.168.100.10
|
||
- docker2;192.168.100.11
|
||
```
|
||
|
||
Format:
|
||
|
||
```text
|
||
hostname;ip-adresse
|
||
```
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
docker1;192.168.100.10
|
||
```
|
||
|
||
---
|
||
|
||
## KV-Store Ergebnis
|
||
|
||
Der Flow schreibt die Dropdown-Liste in diesen Kestra KV-Key:
|
||
|
||
```text
|
||
docker_stack_select_options
|
||
```
|
||
|
||
Die Werte haben dieses Format:
|
||
|
||
```text
|
||
hostname;ip-adresse;ssh-user;compose-verzeichnis
|
||
```
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
docker1;192.168.100.10;meinuser;/home/meinuser/docker/nextcloud
|
||
```
|
||
|
||
---
|
||
|
||
## Sicherheit
|
||
|
||
Dieses Repository darf keine echten Zugangsdaten enthalten.
|
||
|
||
Nicht committen:
|
||
|
||
```text
|
||
.env
|
||
SSH Private Keys
|
||
API Tokens
|
||
Passwörter
|
||
Terraform State Dateien
|
||
S3 Zugangsdaten
|
||
OpenAI API Keys
|
||
SMTP Passwörter
|
||
```
|
||
|
||
Empfohlene `.gitignore`:
|
||
|
||
```gitignore
|
||
.env
|
||
.env.*
|
||
!.env.example
|
||
|
||
*.tfstate
|
||
*.tfstate.*
|
||
.terraform/
|
||
|
||
*.pem
|
||
*.key
|
||
id_rsa
|
||
id_ed25519
|
||
|
||
__pycache__/
|
||
*.pyc
|
||
```
|
||
|
||
Wichtig: Wenn ein Secret einmal versehentlich committed oder öffentlich geteilt wurde, sollte es ausgetauscht werden.
|
||
|
||
---
|
||
|
||
## Test des Python-Scripts
|
||
|
||
Das Python-Script kann lokal getestet werden.
|
||
|
||
Beispiel:
|
||
|
||
```bash
|
||
export OPTIONS_B64_JSON='["WyJkb2NrZXIxOzE5Mi4xNjguMTAwLjEwO21laW51c2VyOy9ob21lL21laW51c2VyL2RvY2tlci9uZXh0Y2xvdWQiXQ=="]'
|
||
python3 build_select_options.py
|
||
cat select_options.json
|
||
```
|
||
|
||
Erwartete Ausgabe:
|
||
|
||
```json
|
||
[
|
||
"docker1;192.168.100.10;meinuser;/home/meinuser/docker/nextcloud"
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
## Typische Fehler
|
||
|
||
### Python-Script wird nicht gefunden
|
||
|
||
Fehler:
|
||
|
||
```text
|
||
python3: can't open file ... build_select_options.py
|
||
```
|
||
|
||
Ursache:
|
||
|
||
Das Script liegt nicht an der erwarteten Stelle im geklonten Repository.
|
||
|
||
Lösung:
|
||
|
||
Im Kestra-Log prüfen, welche Dateien nach dem Git-Clone vorhanden sind. Der aktuelle Flow sucht `build_select_options.py` automatisch.
|
||
|
||
---
|
||
|
||
### SSH-Verbindung schlägt fehl
|
||
|
||
Mögliche Ursachen:
|
||
|
||
* falscher SSH-Benutzer
|
||
* falscher Host
|
||
* SSH-Key fehlt in Kestra
|
||
* Public Key ist auf dem Zielhost nicht in `authorized_keys`
|
||
* Firewall blockiert Port 22
|
||
|
||
---
|
||
|
||
### Keine Stacks gefunden
|
||
|
||
Mögliche Ursachen:
|
||
|
||
* falsches `base_dir`
|
||
* Compose-Dateien liegen tiefer als `maxdepth 2`
|
||
* Compose-Dateien heißen anders
|
||
* Benutzer hat keine Leserechte
|
||
|
||
---
|
||
|
||
## Grundsatz
|
||
|
||
Die klassische Aufteilung bleibt:
|
||
|
||
```text
|
||
Kestra = Ablaufsteuerung
|
||
Git = versionierte Logik
|
||
Secrets = außerhalb des Repositories
|
||
KV-Store = Laufzeitdaten für Dropdowns und Auswahlfelder
|
||
```
|
||
|