Skip to content

Provisioning

Cloud-Infrastruktur per Code: Server, Netzwerke, Firewalls, DNS, Load Balancer, TLS-Zertifikate und Volumes. Single-Server oder Multi-Node-Cluster. Provider-unabhängig, ENV-gesteuert, mit State-Tracking.

Überblick

jardisops/provisioning automatisiert die komplette Cloud-Infrastruktur: vom einzelnen Server bis zum Multi-Node-Cluster mit Private Network, Load Balancer und automatischem DNS. Alles wird über .env-Dateien konfiguriert, der aktuelle Zustand in .provision-state.json persistiert.

GitHub: jardisOps/provisioning

EigenschaftWert
PHP≥ 8.2
ProviderHetzner Cloud, INWX DNS
ModiSingle-Server, Multi-Node-Cluster
VerschlüsselungAES-256-GCM, Sodium
State.provision-state.json

Installation

bash
composer require jardisops/provisioning

Initialisierung eines neuen Projekts:

bash
vendor/bin/provision init --project-root=.

Erzeugt .env-Template, Makefile und .gitignore.

Architektur

┌──────────────────────────────────────────────────────┐
│              CLI (vendor/bin/provision)               │
└─────────────────────────┬────────────────────────────┘

┌─────────────────────────▼────────────────────────────┐
│          Provisioner (Orchestrator)                   │
│       Provider-unabhängige Workflow-Koordination      │
└──┬────────┬─────────┬─────────┬─────────┬────────┬───┘
   │        │         │         │         │        │
 Server  Network  Firewall  LoadBal.   DNS    Volume
   │        │         │         │         │        │
   └────────┴─────────┴─────────┴─────────┴────────┘

              ┌───────────▼───────────┐
              │   Provider-Adapter    │
              │  Hetzner │ INWX │ ... │
              └───────────────────────┘

Der Provisioner kennt keine Provider-Details. Er arbeitet ausschließlich über Interfaces aus Support/Contract/.

Deployment-Modi

Single-Server

Ein Server mit externer Firewall, optionalem DNS und optionalem Volume.

ini
PROVISION_MODE=single
INFRA_PROVIDER=hetzner

SERVER_NAME=my-app
SERVER_TYPE=cpx31

Ablauf:

  1. SSH-Key registrieren
  2. Cloud-Init-Script generieren (Härtung)
  3. Server erstellen + warten bis Running
  4. Externe Firewall erstellen (22, 80, 443)
  5. DNS-Records erstellen (optional)
  6. Volume erstellen (optional)
  7. State speichern

Multi-Node-Cluster

Mehrere Server mit Private Network, interner Firewall, Load Balancer und TLS.

ini
PROVISION_MODE=cluster
INFRA_PROVIDER=hetzner
CLUSTER_NAME=jardis-prod
CLUSTER_NODE_COUNT=3

CLUSTER_NODE_1_ROLE=server
CLUSTER_NODE_1_TYPE=cpx31
CLUSTER_NODE_1_NAME=jardis-prod-server-1

CLUSTER_NODE_2_ROLE=agent
CLUSTER_NODE_2_TYPE=cpx31
CLUSTER_NODE_2_NAME=jardis-prod-agent-1

CLUSTER_NODE_3_ROLE=agent
CLUSTER_NODE_3_TYPE=cpx31
CLUSTER_NODE_3_NAME=jardis-prod-agent-2

# Private Network
PRIVATE_NETWORK_NAME=jardis-prod-net
PRIVATE_NETWORK_SUBNET=10.0.1.0/24
PRIVATE_NETWORK_ZONE=eu-central

# Load Balancer
LOADBALANCER_ENABLED=true
LOADBALANCER_NAME=jardis-prod-lb
LOADBALANCER_TYPE=lb11
LOADBALANCER_ALGORITHM=round_robin
LOADBALANCER_HEALTH_CHECK_PATH=/health

Ablauf:

  1. SSH-Key registrieren + Cloud-Init generieren
  2. Private Network erstellen
  3. Server-Node erstellen (10.0.1.2)
  4. Agent-Nodes erstellen (10.0.1.3, 10.0.1.4, ...)
  5. Externe Firewall (22, 80, 443) + interne Firewall (K3S-Ports)
  6. TLS-Zertifikat erstellen (Let's Encrypt)
  7. Load Balancer erstellen + Targets zuweisen
  8. DNS-Records auf LB-IP
  9. Volumes erstellen (optional)
  10. State speichern

Interne Firewall-Regeln (K3S):

PortProtokollDienst
6443TCPKubernetes API
8472UDPFlannel/WireGuard
10250TCPKubelet
2379TCPetcd
2380TCPetcd Peer

Konfiguration

Globale Variablen

VariableBeschreibung
PROVISION_MODEsingle oder cluster
INFRA_PROVIDERInfrastructure-Provider (hetzner)
DNS_PROVIDERDNS-Provider (hetzner, inwx) — optional
SSH_KEY_PATHPfad zum SSH Public Key

Hetzner Cloud

VariableBeschreibung
HETZNER_API_TOKENAPI-Token (unterstützt Verschlüsselung)
HETZNER_DNS_TOKENDNS-Token (optional, fällt auf API-Token zurück)
HETZNER_REGIONRechenzentrum (fsn1, nbg1, hel1, ash, sin)
HETZNER_IMAGEServer-Image (ubuntu-24.04)
HETZNER_BACKUP_ENABLEDAutomatische Backups (true/false)

INWX DNS

VariableBeschreibung
INWX_USERINWX Benutzername
INWX_PASSWORDPasswort (unterstützt Verschlüsselung)
DNS_ZONEDNS-Zone (example.com)
DNS_RECORDSRecords (api:A,portal:A,monitoring:A)
DNS_TTLTime-to-Live (Default: 300)

Sicherheit / Cloud-Init

VariableDefaultBeschreibung
SECURITY_DEPLOY_USERdeployNicht-Root Deploy-User
SECURITY_SSH_PORT22SSH-Port
SECURITY_DISABLE_ROOTtrueRoot-Login deaktivieren
SECURITY_DISABLE_PASSWORD_AUTHtrueNur SSH-Key-Auth
SECURITY_AUTO_UPDATEStrueAutomatische Updates
SECURITY_FAIL2BANtrueFail2Ban aktivieren

Load Balancer

VariableDefaultBeschreibung
LOADBALANCER_ENABLEDLoad Balancer aktivieren
LOADBALANCER_NAMEName
LOADBALANCER_TYPElb11Typ (lb11, lb21)
LOADBALANCER_ALGORITHMround_robinAlgorithmus
LOADBALANCER_HEALTH_CHECK_PROTOCOLhttpProtokoll
LOADBALANCER_HEALTH_CHECK_PORT80Port
LOADBALANCER_HEALTH_CHECK_PATH/healthPfad
LOADBALANCER_HEALTH_CHECK_INTERVAL15Intervall (Sek.)
LOADBALANCER_HEALTH_CHECK_TIMEOUT10Timeout (Sek.)
LOADBALANCER_HEALTH_CHECK_RETRIES3Wiederholungen

CLI-Commands

bash
vendor/bin/provision <command> [optionen]
CommandBeschreibung
initProjekt bootstrappen (ENV-Template, Makefile)
provisionInfrastruktur aufbauen
provision --dry-runVorschau ohne Änderungen
deprovision --forceAlles abbauen
statusAktuellen Zustand anzeigen
status --jsonZustand als JSON
node:addNode zum Cluster hinzufügen
node:removeNode aus Cluster entfernen
secret:generate-keyVerschlüsselungs-Key generieren
secret:encryptWert verschlüsseln (AES-256-GCM)
secret:encrypt-sodiumWert verschlüsseln (Sodium)

Node-Management

Node hinzufügen

bash
vendor/bin/provision node:add \
  --name=jardis-prod-agent-3 \
  --role=agent \
  --type=cpx31 \
  --volume=50

Erstellt Server, hängt ihn ins Private Network, wendet Firewalls an, fügt ihn zum Load Balancer hinzu.

Node entfernen

bash
vendor/bin/provision node:remove \
  --name=jardis-prod-agent-3 \
  --delete-volume

Entfernt Node aus LB, löst Volumes, entfernt Firewalls, löscht Server.

Secret-Management

API-Tokens und Passwörter können verschlüsselt in .env gespeichert werden:

bash
# Key generieren
vendor/bin/provision secret:generate-key

# Wert verschlüsseln
vendor/bin/provision secret:encrypt --value="hcloud-Xyz..."
# → secret(aes:k9Xp2mV8nQ3wR6yT...)

In .env eintragen:

ini
HETZNER_API_TOKEN=secret(aes:k9Xp2mV8nQ3wR6yT...)
INWX_PASSWORD=secret(sodium:A7bQ9c...)

Die Entschlüsselung erfolgt automatisch beim Laden der Konfiguration via jardissupport/dotenv + jardissupport/secret.

State-Tracking

Der aktuelle Infrastruktur-Zustand wird in .provision-state.json persistiert:

json
{
  "version": 1,
  "mode": "cluster",
  "cluster_name": "jardis-prod",
  "provider": "hetzner",
  "region": "fsn1",
  "created_at": "2024-01-15T10:30:00+00:00",
  "resources": {
    "ssh_key": { "id": 123, "name": "jardis-prod" },
    "nodes": [
      { "name": "server-1", "role": "server", "public_ip": "49.12.xx.xx", "private_ip": "10.0.1.2" }
    ],
    "firewalls": [...],
    "network": { "name": "jardis-prod-net", "subnet": "10.0.1.0/24" },
    "load_balancer": { "name": "jardis-prod-lb", "ip": "49.12.xx.xx" },
    "dns_records": [...]
  }
}

Idempotent: Mehrfaches Ausführen von provision erstellt keine Duplikate: der State verhindert doppelte Ressourcen.

Provider erweitern

Neuen Provider hinzufügen:

  1. Verzeichnis src/Provider/<Name>/ erstellen
  2. 6–7 Interfaces implementieren (ServerProviderInterface, NetworkProviderInterface, etc.)
  3. Handler-Klasse erstellen (<Name>InfraHandler)
  4. In ProvisionerFactory registrieren
  5. .env.example im Provider-Verzeichnis anlegen

Der Provisioner, StateManager und die CLI funktionieren automatisch: keine Änderungen nötig.

Makefile

TargetBeschreibung
make provisionInfrastruktur aufbauen
make provision-dryDry-Run
make deprovisionAlles abbauen
make cluster-statusStatus anzeigen
make cluster-status-jsonStatus als JSON
make node-addNode hinzufügen
make node-removeNode entfernen
make generate-key-fileVerschlüsselungs-Key generieren
make encryptWert verschlüsseln (AES)
make encrypt-sodiumWert verschlüsseln (Sodium)

Abhängigkeiten

PackageZweck
jardissupport/dotenvENV-Laden mit Typ-Casting
jardissupport/secretSecret-Verschlüsselung/-Entschlüsselung
ext-jsonJSON-Verarbeitung
ext-curlHTTP-Requests
ext-xmlrpcINWX XML-RPC API