Files
AFC-Demo/terraform/README.md
T
cbazzaandClaude Opus 4.5 fddc78618e
Build and Deploy to Synology NAS / test (push) Failing after 15m0s
Build and Deploy to Synology NAS / build (push) Has been cancelled
Build and Deploy to Synology NAS / deploy (push) Has been cancelled
Build and Deploy to Synology NAS / notify (push) Has been cancelled
feat: add Azure AKS deployment infrastructure with Terraform
- Add Terraform configuration for AKS cluster deployment
- Add Kubernetes manifests for Laravel app (deployment, services, secrets)
- Add PostgreSQL on Kubernetes with multi-schema support
- Add Nginx Ingress Controller configuration
- Add GitHub Actions workflow for Azure deployment
- Add HTTP Basic Authentication for production
- Add database restore functionality via Kubernetes jobs
- Update Dockerfile and nginx config for production
- Update database.php for multi-schema connections
- Add deployment documentation and quickstart guides

Deployed version: 1.0.7 at http://72.144.113.194/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:43:08 +01:00

23 KiB

Laravel Application Deployment auf Azure Kubernetes Service (AKS)

Diese Terraform-Konfiguration stellt deine Laravel-Anwendung auf Azure Kubernetes Service (AKS) bereit und erstellt eine Azure PostgreSQL Datenbank.

📋 Inhaltsverzeichnis

Voraussetzungen

Folgende Tools müssen installiert sein:

Architektur-Übersicht

┌─────────────────────────────────────────────────────────────┐
│                      Azure Cloud                            │
│                                                             │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Resource Group: trusted_ai_demo_rg                    │ │
│  │                                                        │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │  AKS Cluster: trai_k8s_cluster                   │  │ │
│  │  │                                                  │  │ │
│  │  │  ┌────────────────────────────────────────────┐  │  │ │
│  │  │  │  Namespace: laravel-app                    │  │  │ │
│  │  │  │                                            │  │  │ │
│  │  │  │  • Deployment (2+ Pods)                    │  │  │ │
│  │  │  │  • Service (ClusterIP)                     │  │  │ │
│  │  │  │  • ConfigMaps & Secrets                    │  │  │ │
│  │  │  │  • Horizontal Pod Autoscaler               │  │  │ │
│  │  │  └────────────────────────────────────────────┘  │  │ │
│  │  │                                                  │  │ │
│  │  │  ┌────────────────────────────────────────────┐  │  │ │
│  │  │  │  Namespace: ingress-nginx                  │  │  │ │
│  │  │  │                                            │  │  │ │
│  │  │  │  • Nginx Ingress Controller                │  │  │ │
│  │  │  │  • LoadBalancer Service (Public IP)        │  │  │ │
│  │  │  └────────────────────────────────────────────┘  │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  │                                                        │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │  Azure PostgreSQL Flexible Server                │  │ │
│  │  │                                                  │  │ │
│  │  │  • PostgreSQL 16                                 │  │ │
│  │  │  • 32 GB Storage                                 │  │ │
│  │  │  • Automated Backups (7 days)                    │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Komponenten:

  1. AKS Cluster: Bestehender Kubernetes-Cluster
  2. Laravel Application: Containerisierte Laravel-App mit Nginx + PHP-FPM
  3. PostgreSQL Database: Azure Database for PostgreSQL Flexible Server
  4. Nginx Ingress Controller: Load Balancer für externen Zugriff
  5. Secrets Management: Kubernetes Secrets für sensible Daten

Schnellstart

1. Azure CLI Login

az login
az account set --subscription "77677a80-2dea-493d-9867-f1c961b80fb3"

2. Docker Image erstellen und pushen

Erstelle zuerst eine Azure Container Registry (falls noch nicht vorhanden):

# Container Registry erstellen
az acr create \
  --resource-group trusted_ai_demo_rg \
  --name mylaravelregistry \
  --sku Basic \
  --location germanywestcentral

# In Registry einloggen
az acr login --name mylaravelregistry

Dann baue und pushe das Docker Image:

# Zurück zum Projekt-Root
cd /Users/sebastianfrohlich/Herd/frontend

# Docker Image bauen
docker build -t mylaravelregistry.azurecr.io/laravel-app:v1.0.0 .

# Image pushen
docker push mylaravelregistry.azurecr.io/laravel-app:v1.0.0

3. Terraform konfigurieren

cd terraform

# Kopiere die Beispiel-Konfiguration
cp terraform.tfvars.example terraform.tfvars

# Bearbeite terraform.tfvars
nano terraform.tfvars

Wichtige Werte in terraform.tfvars:

docker_image = "mylaravelregistry.azurecr.io/laravel-app:v1.0.0"
app_key      = "base64:YOUR_GENERATED_KEY"  # Generiere mit: php artisan key:generate --show
postgresql_admin_password = "YourSecurePassword123!"
alert_email_address = "your-email@example.com"

4. Deployment ausführen

# Automatisches Deployment mit Script
./scripts/deploy.sh

Oder manuell:

# Terraform initialisieren
terraform init

# Plan überprüfen
terraform plan

# Deployment ausführen
terraform apply

5. Datenbank wiederherstellen

# Interaktives Restore-Script
./scripts/restore-db.sh

Oder manuell:

# Setze db_restore_enabled = true in terraform.tfvars
terraform apply

Detaillierte Anleitung

Schritt 1: Azure Container Registry (ACR) Setup

Die Laravel-Anwendung muss als Docker Image bereitgestellt werden:

# ACR erstellen (wenn nicht vorhanden)
az acr create \
  --resource-group trusted_ai_demo_rg \
  --name mylaravelregistry \
  --sku Basic

# Admin-Zugriff aktivieren (optional, für einfachere Handhabung)
az acr update -n mylaravelregistry --admin-enabled true

# Login credentials abrufen
az acr credential show --name mylaravelregistry

# Docker login
az acr login --name mylaravelregistry

Schritt 2: Docker Image Build & Push

cd /Users/sebastianfrohlich/Herd/frontend

# Image mit Tag bauen
docker build -t mylaravelregistry.azurecr.io/laravel-app:latest .
docker build -t mylaravelregistry.azurecr.io/laravel-app:v1.0.0 .

# Image pushen
docker push mylaravelregistry.azurecr.io/laravel-app:latest
docker push mylaravelregistry.azurecr.io/laravel-app:v1.0.0

Schritt 3: AKS Pull-Berechtigung für ACR

# AKS Pull-Berechtigung für ACR erteilen
az aks update \
  --resource-group trusted_ai_demo_rg \
  --name trai_k8s_cluster \
  --attach-acr mylaravelregistry

Schritt 4: Laravel APP_KEY generieren

cd /Users/sebastianfrohlich/Herd/frontend
php artisan key:generate --show

Kopiere den Output (z.B. base64:xyz...) in deine terraform.tfvars.

Schritt 5: Terraform Konfiguration

Erstelle terraform/terraform.tfvars:

# Azure Configuration
subscription_id      = "77677a80-2dea-493d-9867-f1c961b80fb3"
resource_group_name  = "trusted_ai_demo_rg"
location             = "germanywestcentral"
aks_cluster_name     = "trai_k8s_cluster"

# Application Configuration
app_name      = "laravel-app"
app_namespace = "laravel-app"
app_env       = "production"
app_debug     = false
app_replicas  = 2

# Docker Image
docker_image = "mylaravelregistry.azurecr.io/laravel-app:v1.0.0"

# Laravel APP_KEY (generiert mit: php artisan key:generate --show)
app_key = "base64:YOUR_ACTUAL_KEY_HERE"

# PostgreSQL Configuration
postgresql_admin_username       = "pgadmin"
postgresql_admin_password       = "YourVerySecurePassword123!"
postgresql_sku_name             = "B_Standard_B1ms"
postgresql_storage_mb           = 32768
postgresql_version              = "16"
postgresql_backup_retention_days = 7

# Ingress Configuration
ingress_enabled = true
ingress_host    = ""  # Leer lassen für IP-basierten Zugriff

# SSL/TLS Configuration (optional, später aktivieren)
ssl_enabled      = false
ssl_issuer_email = ""

# Database Restore Configuration
db_restore_enabled   = true
db_backup_file_path  = "../backups/backup_backend_20251203_101741.dump"

# Alert Configuration
alert_email_address = "your-email@example.com"

Schritt 6: Terraform Deployment

cd /Users/sebastianfrohlich/Herd/frontend/terraform

# Terraform initialisieren
terraform init

# Validierung
terraform validate

# Plan erstellen und überprüfen
terraform plan -out=tfplan

# Deployment ausführen
terraform apply tfplan

# Outputs anzeigen
terraform output
terraform output deployment_instructions

Schritt 7: kubectl konfigurieren

# kubectl Credentials abrufen
az aks get-credentials \
  --resource-group trusted_ai_demo_rg \
  --name trai_k8s_cluster \
  --overwrite-existing

# Cluster-Zugriff testen
kubectl get nodes

# Pods prüfen
kubectl get pods -n laravel-app

# Services prüfen
kubectl get svc -n laravel-app
kubectl get svc -n ingress-nginx

Schritt 8: Anwendung testen

# LoadBalancer IP abrufen
kubectl get svc ingress-nginx-controller -n ingress-nginx

# External IP sollte angezeigt werden, z.B.:
# NAME                       TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)
# ingress-nginx-controller   LoadBalancer   10.0.45.123   20.79.123.456   80:31234/TCP,443:31567/TCP

# Anwendung im Browser öffnen:
# http://<EXTERNAL-IP>

HTTP Basic Authentication

Die Anwendung ist mit HTTP Basic Auth geschützt:

  • Benutzer: afc-user
  • Passwort: vDZFrZ+*~4gW=3^?-,:8{ga=7M.o5k,G

Die Credentials sind in deploy/nginx/.htpasswd konfiguriert und werden während des Docker-Builds in das Image kopiert.

Aktueller Deployment-Status

Aktuell deployed: Version 1.0.7

Aktuelle Konfiguration:

  • URL: http://72.144.113.194/
  • Docker Image: laravelappreg.azurecr.io/laravel-app:1.0.7
  • Replicas: 2
  • Datenbank: laravel_app (PostgreSQL 16) mit 3 Schemas
  • HTTP Basic Auth: Aktiv

Letzte Änderungen (v1.0.7):

  • HTTP Basic Authentication hinzugefügt
  • Nginx Redirect für Livewire JavaScript (.min.js.js)
  • Alle 3 Datenbank-Schemas nach laravel_app migriert
  • Datenbankverbindungen in config/database.php aktualisiert
  • Session-Driver auf database umgestellt (Multi-Pod Support)

Konfiguration

Umgebungsvariablen

Die Laravel-Umgebungsvariablen werden über Kubernetes ConfigMaps und Secrets verwaltet:

ConfigMap (kubernetes_config_map.app_config):

  • APP_NAME, APP_ENV, APP_DEBUG, APP_URL
  • Session, Cache, Queue, Mail Konfiguration

Secrets (kubernetes_secret.app_secrets):

  • APP_KEY

Database Secrets (kubernetes_secret.db_credentials):

  • DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE
  • DB_USERNAME, DB_PASSWORD

Resource Limits

Standard-Einstellungen in variables.tf:

app_resources_requests_cpu    = "100m"
app_resources_requests_memory = "256Mi"
app_resources_limits_cpu      = "500m"
app_resources_limits_memory   = "512Mi"

Diese können in terraform.tfvars überschrieben werden.

Horizontal Pod Autoscaling

Die Anwendung skaliert automatisch basierend auf CPU und Memory:

  • Min Replicas: app_replicas (default: 2)
  • Max Replicas: app_replicas * 3 (default: 6)
  • CPU Threshold: 80%
  • Memory Threshold: 80%

Datenbank-Konfiguration

Datenbank-Struktur

Die Anwendung verwendet eine PostgreSQL-Datenbank (laravel_app) mit drei Schemas:

1. public Schema (12 Tabellen)

Standard Laravel-Tabellen und Application-Daten:

  • backend_data_pool, cache, cache_locks
  • companies, failed_jobs, job_batches, jobs
  • migrations, password_reset_tokens, sessions
  • transactions, users

Connection: DB::connection('pgsql_second') oder DB::connection('pgsql')

2. backend Schema (11 Tabellen)

Backend-spezifische Daten:

  • entity_corporate_context, evidence_registry
  • fallback_events, internal_context_blobs
  • prompt_results, prompt_runs, prompt_templates, prompt_token_metrics
  • sources, transaction_outputs, transactions

Connection: DB::connection('backend')

3. devbackend Schema (13 Tabellen)

Development/Testing Backend-Daten:

  • document_facts, entity_corporate_context
  • evidence_registry, fallback_events
  • internal_context_blobs, pdf_documents
  • prompt_results, prompt_runs, prompt_templates, prompt_token_metrics
  • sources, transaction_outputs, transactions

Connection: DB::connection('devbackend')

Verwendung in Laravel

// Public Schema (Standard)
$users = DB::connection('pgsql')->table('users')->get();
$users = DB::connection('pgsql_second')->table('users')->get();

// Backend Schema
$transactions = DB::connection('backend')->table('transactions')->get();

// DevBackend Schema
$documents = DB::connection('devbackend')->table('pdf_documents')->get();

Alle Connections sind in config/database.php konfiguriert und zeigen auf dieselbe Datenbank laravel_app mit unterschiedlichen search_path Einstellungen.

Datenbank-Wiederherstellung

Automatische Wiederherstellung während Deployment

Die Datenbank-Wiederherstellung importiert alle drei Schemas in die laravel_app Datenbank:

# Backups befinden sich in:
/Users/sebastianfrohlich/Herd/frontend/backups/
- backup_public_20251203_101723.dump      # Public Schema
- backup_backend_20251203_101741.dump     # Backend Schema
- backup_devbackend_20251203_103857.dump  # DevBackend Schema

Setze in terraform.tfvars:

db_restore_enabled  = true
db_backup_file_path = "../backups/backup_backend_20251203_101741.dump"

Das Backup wird als Kubernetes Job ausgeführt.

Manuelle Wiederherstellung

# Interaktives Script
./scripts/restore-db.sh

# Script fragt nach:
# - Welche Backup-Datei verwendet werden soll
# - Bestätigung zum Überschreiben der Datenbank
# - Zeigt Fortschritt und Logs an

Manuelles DB-Restore (kubectl)

# ConfigMap mit Backup erstellen
kubectl create configmap db-restore-backup \
  --from-file=backup.dump=/Users/sebastianfrohlich/Herd/frontend/backups/backup_backend_20251203_101741.dump \
  -n laravel-app

# Job aus db-restore.tf verwenden oder manuell erstellen
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: Job
metadata:
  name: db-restore-manual
  namespace: laravel-app
spec:
  template:
    spec:
      containers:
      - name: db-restore
        image: postgres:16-alpine
        command: ["/bin/sh", "-c"]
        args:
        - |
          set -e
          export PGPASSWORD="\$DB_PASSWORD"
          pg_restore -h \$DB_HOST -p \$DB_PORT -U \$DB_USERNAME -d \$DB_DATABASE \
            --verbose --clean --if-exists --no-owner --no-privileges /backup/backup.dump
        envFrom:
        - secretRef:
            name: laravel-app-db-credentials
        volumeMounts:
        - name: backup-volume
          mountPath: /backup
      volumes:
      - name: backup-volume
        configMap:
          name: db-restore-backup
      restartPolicy: OnFailure
EOF

# Job-Status prüfen
kubectl get jobs -n laravel-app

# Logs anzeigen
kubectl logs -n laravel-app -l job-name=db-restore-manual -f

Deployment

Neues Image deployen

# 1. Neues Image bauen
docker build -t mylaravelregistry.azurecr.io/laravel-app:v1.0.1 .
docker push mylaravelregistry.azurecr.io/laravel-app:v1.0.1

# 2. terraform.tfvars aktualisieren
# docker_image = "mylaravelregistry.azurecr.io/laravel-app:v1.0.1"

# 3. Terraform apply
terraform apply

# Oder direkt kubectl verwenden für schnelleres Update:
kubectl set image deployment/laravel-app \
  laravel-app=mylaravelregistry.azurecr.io/laravel-app:v1.0.1 \
  -n laravel-app

# Rollout Status prüfen
kubectl rollout status deployment/laravel-app -n laravel-app

Rollback

# Rollout Historie anzeigen
kubectl rollout history deployment/laravel-app -n laravel-app

# Zu vorheriger Version zurückkehren
kubectl rollout undo deployment/laravel-app -n laravel-app

# Zu spezifischer Revision zurückkehren
kubectl rollout undo deployment/laravel-app --to-revision=2 -n laravel-app

Replicas skalieren

# Über kubectl
kubectl scale deployment/laravel-app --replicas=3 -n laravel-app

# Über Terraform
# Ändere app_replicas in terraform.tfvars und führe aus:
terraform apply

Troubleshooting

Pods starten nicht

# Pod-Status prüfen
kubectl get pods -n laravel-app

# Detaillierte Pod-Informationen
kubectl describe pod <pod-name> -n laravel-app

# Pod-Logs anzeigen
kubectl logs <pod-name> -n laravel-app

# Vorherige Pod-Logs (bei CrashLoopBackOff)
kubectl logs <pod-name> -n laravel-app --previous

Datenbank-Verbindungsprobleme

# Secrets prüfen
kubectl get secret laravel-app-db-credentials -n laravel-app -o yaml

# PostgreSQL Server Firewall prüfen
az postgres flexible-server firewall-rule list \
  --resource-group trusted_ai_demo_rg \
  --name <postgresql-server-name>

# Verbindung vom Pod aus testen
kubectl run -it --rm debug --image=postgres:16-alpine -n laravel-app -- \
  psql "postgresql://user:pass@host:5432/database"

Ingress funktioniert nicht

# Ingress Status prüfen
kubectl get ingress -n laravel-app

# Ingress Controller Logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller

# LoadBalancer Service prüfen
kubectl get svc -n ingress-nginx

# Ingress Events prüfen
kubectl describe ingress laravel-app-ingress -n laravel-app

SSL/TLS Zertifikat-Probleme

# cert-manager Pods prüfen
kubectl get pods -n cert-manager

# Certificate Status prüfen
kubectl get certificate -n laravel-app

# Certificate Details
kubectl describe certificate laravel-app-tls -n laravel-app

# cert-manager Logs
kubectl logs -n cert-manager -l app=cert-manager

Performance-Probleme

# Resource Usage prüfen
kubectl top pods -n laravel-app
kubectl top nodes

# HPA Status prüfen
kubectl get hpa -n laravel-app

# Events prüfen
kubectl get events -n laravel-app --sort-by='.lastTimestamp'

Wartung

Backups

PostgreSQL Flexible Server erstellt automatische Backups:

# Backup-Konfiguration prüfen
az postgres flexible-server show \
  --resource-group trusted_ai_demo_rg \
  --name <postgresql-server-name> \
  --query "{backupRetentionDays:backup.backupRetentionDays,geoRedundantBackup:backup.geoRedundantBackup}"

# Manuelles Backup erstellen
az postgres flexible-server backup create \
  --resource-group trusted_ai_demo_rg \
  --name <postgresql-server-name> \
  --backup-name manual-backup-$(date +%Y%m%d)

Updates

Terraform Updates

# Terraform Zustand aktualisieren
terraform refresh

# Änderungen planen
terraform plan

# Änderungen anwenden
terraform apply

Laravel Updates

# Composer Dependencies aktualisieren
composer update

# NPM Dependencies aktualisieren
npm update

# Neues Image bauen und deployen
docker build -t mylaravelregistry.azurecr.io/laravel-app:v1.0.2 .
docker push mylaravelregistry.azurecr.io/laravel-app:v1.0.2

# Deployment aktualisieren
kubectl set image deployment/laravel-app \
  laravel-app=mylaravelregistry.azurecr.io/laravel-app:v1.0.2 \
  -n laravel-app

Monitoring

# Log Analytics Workspace
az monitor log-analytics workspace show \
  --resource-group trusted_ai_demo_rg \
  --workspace-name <workspace-name>

# Azure Monitor für Container
# Im Azure Portal: AKS Cluster > Monitoring > Insights

# Prometheus Metrics (wenn aktiviert)
kubectl port-forward -n ingress-nginx \
  svc/ingress-nginx-controller-metrics 10254:10254
# Dann: http://localhost:10254/metrics

Cleanup

# Einzelne Resources löschen
terraform destroy -target=kubernetes_deployment.app
terraform destroy -target=azurerm_postgresql_flexible_server.main

# Alles löschen
terraform destroy

# Namespace löschen (löscht alle Resources im Namespace)
kubectl delete namespace laravel-app

Kosten-Optimierung

Development/Staging

Für Dev/Staging Umgebungen kannst du Kosten sparen:

# terraform.tfvars für Staging
postgresql_sku_name = "B_Standard_B1ms"  # Burstable tier
postgresql_storage_mb = 32768             # 32 GB
app_replicas = 1                          # Weniger Replicas
aks_node_pool_min_count = 1               # Weniger Nodes

Production

Für Production empfohlen:

postgresql_sku_name = "GP_Standard_D2s_v3"  # General Purpose
postgresql_storage_mb = 131072                # 128 GB
postgresql_backup_retention_days = 35         # Längere Retention
app_replicas = 3                              # Mehr Replicas

Sicherheit

Best Practices

  1. Secrets Management:

    • Verwende Azure Key Vault für Production
    • Rotiere Passwörter regelmäßig
    • Verwende starke, generierte Passwörter
  2. Network Security:

    • Aktiviere VNet Integration für PostgreSQL
    • Verwende Private Endpoints
    • Beschränke Firewall-Regeln
  3. SSL/TLS:

    • Aktiviere SSL für Production:
      ssl_enabled = true
      ssl_issuer_email = "admin@yourdomain.com"
      ingress_host = "app.yourdomain.com"
      
  4. RBAC:

    • Verwende Kubernetes RBAC
    • Minimale Berechtigungen für Service Accounts

Support und Kontakt

Bei Fragen oder Problemen:

  1. Prüfe die Troubleshooting Sektion
  2. Prüfe Kubernetes Events: kubectl get events -n laravel-app
  3. Prüfe Logs: kubectl logs -n laravel-app -l app=laravel-app

Anhang

Nützliche Befehle

# Alle Resources in einem Namespace anzeigen
kubectl get all -n laravel-app

# Port-forward für lokalen Zugriff
kubectl port-forward -n laravel-app svc/laravel-app 8080:80

# Shell in einem Pod öffnen
kubectl exec -it -n laravel-app <pod-name> -- /bin/sh

# ConfigMap/Secret bearbeiten
kubectl edit configmap laravel-app-config -n laravel-app

# Resource Usage live monitoren
watch kubectl top pods -n laravel-app

# Cluster Info
kubectl cluster-info
kubectl get nodes -o wide

Terraform State Management

Für Team-Arbeit solltest du Remote State verwenden:

# backend.hcl
resource_group_name  = "trusted_ai_demo_rg"
storage_account_name = "tfstate<random>"
container_name       = "tfstate"
key                  = "laravel-app.terraform.tfstate"
# Backend initialisieren
terraform init -backend-config=backend.hcl