1036 lines
22 KiB
Markdown
1036 lines
22 KiB
Markdown
# Deployment-Guide: Risk Intelligence Platform
|
|||
|
|
|
||
|
|
## 📋 Inhaltsverzeichnis
|
||
|
|
|
||
|
|
1. [Übersicht](#übersicht)
|
||
|
|
2. [Voraussetzungen](#voraussetzungen)
|
||
|
|
3. [Docker Deployment](#docker-deployment)
|
||
|
|
4. [Kubernetes Deployment](#kubernetes-deployment)
|
||
|
|
5. [Production Checklist](#production-checklist)
|
||
|
|
6. [Environment Configuration](#environment-configuration)
|
||
|
|
7. [Database Migration](#database-migration)
|
||
|
|
8. [Monitoring & Logging](#monitoring--logging)
|
||
|
|
9. [Backup & Recovery](#backup--recovery)
|
||
|
|
10. [Rollback-Strategie](#rollback-strategie)
|
||
|
|
11. [Troubleshooting](#troubleshooting)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Übersicht
|
||
|
|
|
||
|
|
Die Risk Intelligence Platform kann auf verschiedene Arten deployed werden:
|
||
|
|
|
||
|
|
- **Docker** - Standalone Container oder Docker Compose
|
||
|
|
- **Kubernetes** - Production-ready mit CronJobs für Scheduled Tasks
|
||
|
|
- **Traditional** - Apache/Nginx + PHP-FPM auf Linux-Server
|
||
|
|
|
||
|
|
### Deployment-Architektur
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────┐
|
||
|
|
│ Production Environment │
|
||
|
|
├─────────────────────────────────────────────────────────────┤
|
||
|
|
│ │
|
||
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
|
|
│ │ Nginx │ │ PHP-FPM │ │ Supervisor │ │
|
||
|
|
│ │ (Port 80) │ │ (Laravel) │ │ (Queue) │ │
|
||
|
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||
|
|
│ │ │ │ │
|
||
|
|
│ └─────────────────┴─────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌────────────────────────────────┐ │
|
||
|
|
│ │ PostgreSQL Database │ │
|
||
|
|
│ │ (Public + Backend Schema) │ │
|
||
|
|
│ └────────────────────────────────┘ │
|
||
|
|
│ │
|
||
|
|
│ ┌────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ Kubernetes CronJob (Laravel Scheduler) │ │
|
||
|
|
│ │ - SyncBackendDataPool (every 6h) │ │
|
||
|
|
│ │ - TransformDataPool (every 6h at :30) │ │
|
||
|
|
│ └────────────────────────────────────────────────────┘ │
|
||
|
|
│ │
|
||
|
|
└─────────────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Voraussetzungen
|
||
|
|
|
||
|
|
### System Requirements
|
||
|
|
|
||
|
|
| Komponente | Minimum | Empfohlen |
|
||
|
|
|------------|---------|-----------|
|
||
|
|
| **CPU** | 2 Cores | 4 Cores |
|
||
|
|
| **RAM** | 2 GB | 4 GB |
|
||
|
|
| **Disk** | 20 GB | 50 GB SSD |
|
||
|
|
| **OS** | Linux (Ubuntu 22.04+) | Alpine Linux 3.22 |
|
||
|
|
|
||
|
|
### Software Requirements
|
||
|
|
|
||
|
|
| Software | Version | Zweck |
|
||
|
|
|----------|---------|-------|
|
||
|
|
| **PHP** | 8.2+ | Runtime |
|
||
|
|
| **Composer** | 2.0+ | Dependencies |
|
||
|
|
| **Node.js** | 18+ | Asset Building |
|
||
|
|
| **PostgreSQL** | 14+ | Database |
|
||
|
|
| **Nginx** | 1.24+ | Web Server |
|
||
|
|
| **Supervisor** | 4.0+ | Process Management |
|
||
|
|
| **Docker** | 24.0+ | Containerization (optional) |
|
||
|
|
| **Kubernetes** | 1.28+ | Orchestration (optional) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Docker Deployment
|
||
|
|
|
||
|
|
### Multi-Stage Dockerfile
|
||
|
|
|
||
|
|
Die Applikation nutzt einen **Multi-Stage Build** für optimale Image-Größe.
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Stage 1: Composer Dependencies
|
||
|
|
FROM composer:2 AS vendor
|
||
|
|
WORKDIR /app
|
||
|
|
COPY composer.json composer.lock ./
|
||
|
|
RUN composer install --no-dev --optimize-autoloader
|
||
|
|
|
||
|
|
# Stage 2: Runtime
|
||
|
|
FROM alpine:3.22
|
||
|
|
# Install PHP 8.2, Nginx, Supervisor, PostgreSQL Client
|
||
|
|
RUN apk add --no-cache \
|
||
|
|
nginx supervisor php82 php82-fpm \
|
||
|
|
php82-pgsql php82-pdo_pgsql \
|
||
|
|
nodejs npm
|
||
|
|
|
||
|
|
# Copy vendor from build stage
|
||
|
|
COPY --from=vendor /app/vendor ./vendor
|
||
|
|
COPY . ./
|
||
|
|
|
||
|
|
# Build frontend assets
|
||
|
|
RUN npm ci && npm run build
|
||
|
|
|
||
|
|
# Optimize Laravel
|
||
|
|
RUN php artisan config:cache && \
|
||
|
|
php artisan route:cache && \
|
||
|
|
php artisan view:cache
|
||
|
|
|
||
|
|
EXPOSE 80
|
||
|
|
CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Build & Run
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Build Image
|
||
|
|
docker build -t risk-platform:latest .
|
||
|
|
|
||
|
|
# Run Container
|
||
|
|
docker run -d \
|
||
|
|
--name risk-platform \
|
||
|
|
-p 8080:80 \
|
||
|
|
-v $(pwd)/.env:/var/www/html/.env \
|
||
|
|
-v $(pwd)/storage:/var/www/html/storage \
|
||
|
|
risk-platform:latest
|
||
|
|
```
|
||
|
|
|
||
|
|
### Docker Compose
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# docker-compose.yml
|
||
|
|
version: "3.9"
|
||
|
|
|
||
|
|
services:
|
||
|
|
app:
|
||
|
|
build:
|
||
|
|
context: .
|
||
|
|
dockerfile: Dockerfile
|
||
|
|
container_name: risk-platform
|
||
|
|
restart: unless-stopped
|
||
|
|
ports:
|
||
|
|
- "8080:80"
|
||
|
|
volumes:
|
||
|
|
- .env:/var/www/html/.env
|
||
|
|
- ./storage:/var/www/html/storage
|
||
|
|
depends_on:
|
||
|
|
- postgres
|
||
|
|
networks:
|
||
|
|
- risk-net
|
||
|
|
|
||
|
|
postgres:
|
||
|
|
image: postgres:16-alpine
|
||
|
|
container_name: risk-postgres
|
||
|
|
restart: unless-stopped
|
||
|
|
environment:
|
||
|
|
POSTGRES_DB: risk_platform_db
|
||
|
|
POSTGRES_USER: risk_user
|
||
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||
|
|
volumes:
|
||
|
|
- postgres-data:/var/lib/postgresql/data
|
||
|
|
ports:
|
||
|
|
- "5432:5432"
|
||
|
|
networks:
|
||
|
|
- risk-net
|
||
|
|
|
||
|
|
scheduler:
|
||
|
|
build:
|
||
|
|
context: .
|
||
|
|
dockerfile: Dockerfile
|
||
|
|
container_name: risk-scheduler
|
||
|
|
restart: unless-stopped
|
||
|
|
command: ["php", "artisan", "schedule:work"]
|
||
|
|
volumes:
|
||
|
|
- .env:/var/www/html/.env
|
||
|
|
depends_on:
|
||
|
|
- postgres
|
||
|
|
networks:
|
||
|
|
- risk-net
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
postgres-data:
|
||
|
|
|
||
|
|
networks:
|
||
|
|
risk-net:
|
||
|
|
driver: bridge
|
||
|
|
```
|
||
|
|
|
||
|
|
**Starten:**
|
||
|
|
```bash
|
||
|
|
docker-compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Kubernetes Deployment
|
||
|
|
|
||
|
|
### Namespace erstellen
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# namespace.yaml
|
||
|
|
apiVersion: v1
|
||
|
|
kind: Namespace
|
||
|
|
metadata:
|
||
|
|
name: risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
kubectl apply -f namespace.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### ConfigMap für Environment
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# configmap.yaml
|
||
|
|
apiVersion: v1
|
||
|
|
kind: ConfigMap
|
||
|
|
metadata:
|
||
|
|
name: risk-platform-config
|
||
|
|
namespace: risk-platform
|
||
|
|
data:
|
||
|
|
env: |
|
||
|
|
APP_NAME="Risk Intelligence Platform"
|
||
|
|
APP_ENV=production
|
||
|
|
APP_KEY=base64:xxx
|
||
|
|
APP_DEBUG=false
|
||
|
|
APP_URL=https://risk.example.com
|
||
|
|
|
||
|
|
DB_CONNECTION2=pgsql
|
||
|
|
DB_HOST2=postgres-service
|
||
|
|
DB_PORT2=5432
|
||
|
|
DB_DATABASE2=risk_platform_db
|
||
|
|
DB_USERNAME2=risk_user
|
||
|
|
DB_PASSWORD2=xxx
|
||
|
|
|
||
|
|
CACHE_STORE=redis
|
||
|
|
SESSION_DRIVER=redis
|
||
|
|
QUEUE_CONNECTION=redis
|
||
|
|
|
||
|
|
REDIS_HOST=redis-service
|
||
|
|
REDIS_PORT=6379
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
kubectl apply -f configmap.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Deployment
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# deployment.yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: risk-platform
|
||
|
|
namespace: risk-platform
|
||
|
|
labels:
|
||
|
|
app: risk-platform
|
||
|
|
spec:
|
||
|
|
replicas: 2
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: risk-platform
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: risk-platform
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: app
|
||
|
|
image: registry.example.com/risk-platform:latest
|
||
|
|
imagePullPolicy: Always
|
||
|
|
ports:
|
||
|
|
- containerPort: 80
|
||
|
|
name: http
|
||
|
|
env:
|
||
|
|
- name: APP_ENV
|
||
|
|
value: "production"
|
||
|
|
volumeMounts:
|
||
|
|
- name: config
|
||
|
|
mountPath: /var/www/html/.env
|
||
|
|
subPath: env
|
||
|
|
- name: storage
|
||
|
|
mountPath: /var/www/html/storage
|
||
|
|
resources:
|
||
|
|
requests:
|
||
|
|
memory: "512Mi"
|
||
|
|
cpu: "250m"
|
||
|
|
limits:
|
||
|
|
memory: "1Gi"
|
||
|
|
cpu: "500m"
|
||
|
|
livenessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /
|
||
|
|
port: 80
|
||
|
|
initialDelaySeconds: 30
|
||
|
|
periodSeconds: 10
|
||
|
|
readinessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /
|
||
|
|
port: 80
|
||
|
|
initialDelaySeconds: 10
|
||
|
|
periodSeconds: 5
|
||
|
|
volumes:
|
||
|
|
- name: config
|
||
|
|
configMap:
|
||
|
|
name: risk-platform-config
|
||
|
|
- name: storage
|
||
|
|
persistentVolumeClaim:
|
||
|
|
claimName: risk-platform-storage
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
kubectl apply -f deployment.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Service
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# service.yaml
|
||
|
|
apiVersion: v1
|
||
|
|
kind: Service
|
||
|
|
metadata:
|
||
|
|
name: risk-platform-service
|
||
|
|
namespace: risk-platform
|
||
|
|
spec:
|
||
|
|
selector:
|
||
|
|
app: risk-platform
|
||
|
|
ports:
|
||
|
|
- protocol: TCP
|
||
|
|
port: 80
|
||
|
|
targetPort: 80
|
||
|
|
type: ClusterIP
|
||
|
|
```
|
||
|
|
|
||
|
|
### Ingress (Optional)
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# ingress.yaml
|
||
|
|
apiVersion: networking.k8s.io/v1
|
||
|
|
kind: Ingress
|
||
|
|
metadata:
|
||
|
|
name: risk-platform-ingress
|
||
|
|
namespace: risk-platform
|
||
|
|
annotations:
|
||
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||
|
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||
|
|
spec:
|
||
|
|
ingressClassName: nginx
|
||
|
|
tls:
|
||
|
|
- hosts:
|
||
|
|
- risk.example.com
|
||
|
|
secretName: risk-platform-tls
|
||
|
|
rules:
|
||
|
|
- host: risk.example.com
|
||
|
|
http:
|
||
|
|
paths:
|
||
|
|
- path: /
|
||
|
|
pathType: Prefix
|
||
|
|
backend:
|
||
|
|
service:
|
||
|
|
name: risk-platform-service
|
||
|
|
port:
|
||
|
|
number: 80
|
||
|
|
```
|
||
|
|
|
||
|
|
### CronJob für Laravel Scheduler
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# cronjob.yaml
|
||
|
|
apiVersion: batch/v1
|
||
|
|
kind: CronJob
|
||
|
|
metadata:
|
||
|
|
name: sync-backend-data-pool
|
||
|
|
namespace: risk-platform
|
||
|
|
spec:
|
||
|
|
schedule: "0 */6 * * *" # Every 6 hours
|
||
|
|
successfulJobsHistoryLimit: 3
|
||
|
|
failedJobsHistoryLimit: 3
|
||
|
|
concurrencyPolicy: Forbid
|
||
|
|
jobTemplate:
|
||
|
|
spec:
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: sync-backend-data-pool
|
||
|
|
spec:
|
||
|
|
restartPolicy: OnFailure
|
||
|
|
containers:
|
||
|
|
- name: sync
|
||
|
|
image: registry.example.com/risk-platform:latest
|
||
|
|
command: ["php", "artisan", "schedule:run"]
|
||
|
|
volumeMounts:
|
||
|
|
- name: config
|
||
|
|
mountPath: /var/www/html/.env
|
||
|
|
subPath: env
|
||
|
|
volumes:
|
||
|
|
- name: config
|
||
|
|
configMap:
|
||
|
|
name: risk-platform-config
|
||
|
|
```
|
||
|
|
|
||
|
|
```bash
|
||
|
|
kubectl apply -f cronjob.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Alle Ressourcen deployen
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Complete Deployment
|
||
|
|
kubectl apply -f namespace.yaml
|
||
|
|
kubectl apply -f configmap.yaml
|
||
|
|
kubectl apply -f deployment.yaml
|
||
|
|
kubectl apply -f service.yaml
|
||
|
|
kubectl apply -f ingress.yaml
|
||
|
|
kubectl apply -f cronjob.yaml
|
||
|
|
|
||
|
|
# Status prüfen
|
||
|
|
kubectl get all -n risk-platform
|
||
|
|
|
||
|
|
# Logs anschauen
|
||
|
|
kubectl logs -f deployment/risk-platform -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Production Checklist
|
||
|
|
|
||
|
|
### Pre-Deployment
|
||
|
|
|
||
|
|
- [ ] **Environment Configuration**
|
||
|
|
- [ ] `.env` auf `production` gesetzt
|
||
|
|
- [ ] `APP_DEBUG=false`
|
||
|
|
- [ ] `APP_KEY` generiert
|
||
|
|
- [ ] Sichere Passwörter für DB
|
||
|
|
|
||
|
|
- [ ] **Database**
|
||
|
|
- [ ] PostgreSQL läuft
|
||
|
|
- [ ] Schemas erstellt (public, backend)
|
||
|
|
- [ ] User-Rechte vergeben
|
||
|
|
- [ ] Backup-Strategie definiert
|
||
|
|
|
||
|
|
- [ ] **Dependencies**
|
||
|
|
- [ ] `composer install --no-dev --optimize-autoloader`
|
||
|
|
- [ ] `npm ci && npm run build`
|
||
|
|
|
||
|
|
- [ ] **Laravel Optimization**
|
||
|
|
- [ ] `php artisan config:cache`
|
||
|
|
- [ ] `php artisan route:cache`
|
||
|
|
- [ ] `php artisan view:cache`
|
||
|
|
- [ ] `php artisan event:cache`
|
||
|
|
|
||
|
|
- [ ] **Security**
|
||
|
|
- [ ] HTTPS aktiviert (SSL/TLS)
|
||
|
|
- [ ] Firewall konfiguriert
|
||
|
|
- [ ] `.env` nicht im Git
|
||
|
|
- [ ] Secrets in Vault/ConfigMap
|
||
|
|
|
||
|
|
### Post-Deployment
|
||
|
|
|
||
|
|
- [ ] **Migrations**
|
||
|
|
- [ ] `php artisan migrate --force`
|
||
|
|
- [ ] Backup vor Migration
|
||
|
|
|
||
|
|
- [ ] **Tests**
|
||
|
|
- [ ] Health Check (`/`)
|
||
|
|
- [ ] Login funktioniert
|
||
|
|
- [ ] Database Connection
|
||
|
|
- [ ] Scheduled Jobs
|
||
|
|
|
||
|
|
- [ ] **Monitoring**
|
||
|
|
- [ ] Logs werden geschrieben
|
||
|
|
- [ ] Metrics werden gesammelt
|
||
|
|
- [ ] Alerts konfiguriert
|
||
|
|
|
||
|
|
- [ ] **Performance**
|
||
|
|
- [ ] OPcache aktiviert
|
||
|
|
- [ ] Redis für Cache/Session
|
||
|
|
- [ ] Database Indizes
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Environment Configuration
|
||
|
|
|
||
|
|
### Production .env
|
||
|
|
|
||
|
|
```ini
|
||
|
|
# Application
|
||
|
|
APP_NAME="Risk Intelligence Platform"
|
||
|
|
APP_ENV=production
|
||
|
|
APP_KEY=base64:xxx # Generate with: php artisan key:generate
|
||
|
|
APP_DEBUG=false
|
||
|
|
APP_URL=https://risk.example.com
|
||
|
|
|
||
|
|
# Locale
|
||
|
|
APP_LOCALE=de
|
||
|
|
APP_FALLBACK_LOCALE=en
|
||
|
|
|
||
|
|
# Database (PostgreSQL)
|
||
|
|
DB_CONNECTION2=pgsql
|
||
|
|
DB_HOST2=postgres-host
|
||
|
|
DB_PORT2=5432
|
||
|
|
DB_DATABASE2=risk_platform_db
|
||
|
|
DB_USERNAME2=risk_user
|
||
|
|
DB_PASSWORD2=xxx # Use strong password!
|
||
|
|
|
||
|
|
# Cache & Session (Redis)
|
||
|
|
CACHE_STORE=redis
|
||
|
|
SESSION_DRIVER=redis
|
||
|
|
SESSION_LIFETIME=120
|
||
|
|
|
||
|
|
# Queue
|
||
|
|
QUEUE_CONNECTION=redis
|
||
|
|
|
||
|
|
# Redis
|
||
|
|
REDIS_HOST=redis-host
|
||
|
|
REDIS_PASSWORD=null
|
||
|
|
REDIS_PORT=6379
|
||
|
|
|
||
|
|
# Mail
|
||
|
|
MAIL_MAILER=smtp
|
||
|
|
MAIL_HOST=smtp.example.com
|
||
|
|
MAIL_PORT=587
|
||
|
|
MAIL_USERNAME=noreply@example.com
|
||
|
|
MAIL_PASSWORD=xxx
|
||
|
|
MAIL_ENCRYPTION=tls
|
||
|
|
MAIL_FROM_ADDRESS=noreply@example.com
|
||
|
|
MAIL_FROM_NAME="${APP_NAME}"
|
||
|
|
|
||
|
|
# Logging
|
||
|
|
LOG_CHANNEL=stack
|
||
|
|
LOG_LEVEL=error # Production: error, nicht debug!
|
||
|
|
|
||
|
|
# Security
|
||
|
|
SESSION_SECURE_COOKIE=true
|
||
|
|
SESSION_SAME_SITE=strict
|
||
|
|
```
|
||
|
|
|
||
|
|
### Secrets Management
|
||
|
|
|
||
|
|
**Kubernetes Secrets:**
|
||
|
|
```bash
|
||
|
|
# Create Secret
|
||
|
|
kubectl create secret generic risk-platform-secrets \
|
||
|
|
--from-literal=APP_KEY=base64:xxx \
|
||
|
|
--from-literal=DB_PASSWORD=xxx \
|
||
|
|
--from-literal=REDIS_PASSWORD=xxx \
|
||
|
|
-n risk-platform
|
||
|
|
|
||
|
|
# Use in Deployment
|
||
|
|
env:
|
||
|
|
- name: APP_KEY
|
||
|
|
valueFrom:
|
||
|
|
secretKeyRef:
|
||
|
|
name: risk-platform-secrets
|
||
|
|
key: APP_KEY
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Database Migration
|
||
|
|
|
||
|
|
### Pre-Migration Backup
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# PostgreSQL Backup
|
||
|
|
pg_dump -h localhost -U risk_user -d risk_platform_db > backup_$(date +%Y%m%d_%H%M%S).sql
|
||
|
|
|
||
|
|
# Verify Backup
|
||
|
|
psql -h localhost -U risk_user -d risk_platform_db_test < backup_xxx.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
### Run Migrations
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Production Migration
|
||
|
|
php artisan migrate --force
|
||
|
|
|
||
|
|
# With Output
|
||
|
|
php artisan migrate --force --verbose
|
||
|
|
|
||
|
|
# Rollback (if needed)
|
||
|
|
php artisan migrate:rollback --force
|
||
|
|
```
|
||
|
|
|
||
|
|
### Zero-Downtime Migration
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Maintenance Mode
|
||
|
|
php artisan down --message="Updating..." --retry=60
|
||
|
|
|
||
|
|
# 2. Pull latest code
|
||
|
|
git pull origin main
|
||
|
|
|
||
|
|
# 3. Update dependencies
|
||
|
|
composer install --no-dev --optimize-autoloader
|
||
|
|
|
||
|
|
# 4. Run migrations
|
||
|
|
php artisan migrate --force
|
||
|
|
|
||
|
|
# 5. Clear & cache
|
||
|
|
php artisan optimize:clear
|
||
|
|
php artisan config:cache
|
||
|
|
php artisan route:cache
|
||
|
|
php artisan view:cache
|
||
|
|
|
||
|
|
# 6. Restart services
|
||
|
|
sudo supervisorctl restart all
|
||
|
|
|
||
|
|
# 7. Exit maintenance mode
|
||
|
|
php artisan up
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Monitoring & Logging
|
||
|
|
|
||
|
|
### Application Logs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Laravel Logs
|
||
|
|
tail -f storage/logs/laravel.log
|
||
|
|
|
||
|
|
# Nur Errors
|
||
|
|
tail -f storage/logs/laravel.log | grep ERROR
|
||
|
|
|
||
|
|
# Mit Laravel Pail
|
||
|
|
php artisan pail --filter=error
|
||
|
|
```
|
||
|
|
|
||
|
|
### Nginx Logs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Access Log
|
||
|
|
tail -f /var/log/nginx/access.log
|
||
|
|
|
||
|
|
# Error Log
|
||
|
|
tail -f /var/log/nginx/error.log
|
||
|
|
```
|
||
|
|
|
||
|
|
### Kubernetes Logs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Pod Logs
|
||
|
|
kubectl logs -f deployment/risk-platform -n risk-platform
|
||
|
|
|
||
|
|
# Alle Pods
|
||
|
|
kubectl logs -f -l app=risk-platform -n risk-platform
|
||
|
|
|
||
|
|
# CronJob Logs
|
||
|
|
kubectl logs -f cronjob/sync-backend-data-pool -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
### Health Checks
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Application Health
|
||
|
|
curl https://risk.example.com/
|
||
|
|
|
||
|
|
# Database Connection
|
||
|
|
php artisan tinker
|
||
|
|
>>> DB::connection()->getPdo()
|
||
|
|
|
||
|
|
# Queue Status
|
||
|
|
php artisan queue:monitor
|
||
|
|
|
||
|
|
# Scheduler Status
|
||
|
|
php artisan schedule:list
|
||
|
|
```
|
||
|
|
|
||
|
|
### Monitoring-Tools (Optional)
|
||
|
|
|
||
|
|
**Laravel Telescope:**
|
||
|
|
```bash
|
||
|
|
composer require laravel/telescope --dev
|
||
|
|
php artisan telescope:install
|
||
|
|
php artisan migrate
|
||
|
|
```
|
||
|
|
|
||
|
|
**Prometheus + Grafana:**
|
||
|
|
- Metrics-Export via Laravel Package
|
||
|
|
- Custom Dashboards für Transactions, Companies
|
||
|
|
- Alerts bei hoher Error-Rate
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Backup & Recovery
|
||
|
|
|
||
|
|
### Automated Backup Script
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# backup.sh
|
||
|
|
|
||
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||
|
|
BACKUP_DIR="/backups"
|
||
|
|
DB_NAME="risk_platform_db"
|
||
|
|
|
||
|
|
# Database Backup
|
||
|
|
pg_dump -h localhost -U risk_user $DB_NAME > $BACKUP_DIR/db_$DATE.sql
|
||
|
|
|
||
|
|
# Storage Backup
|
||
|
|
tar -czf $BACKUP_DIR/storage_$DATE.tar.gz storage/
|
||
|
|
|
||
|
|
# Keep only last 7 days
|
||
|
|
find $BACKUP_DIR -type f -mtime +7 -delete
|
||
|
|
|
||
|
|
echo "Backup completed: $DATE"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Crontab:**
|
||
|
|
```bash
|
||
|
|
# Daily backup at 2 AM
|
||
|
|
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
|
||
|
|
```
|
||
|
|
|
||
|
|
### Kubernetes Backup
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# backup-cronjob.yaml
|
||
|
|
apiVersion: batch/v1
|
||
|
|
kind: CronJob
|
||
|
|
metadata:
|
||
|
|
name: database-backup
|
||
|
|
namespace: risk-platform
|
||
|
|
spec:
|
||
|
|
schedule: "0 2 * * *" # Daily at 2 AM
|
||
|
|
jobTemplate:
|
||
|
|
spec:
|
||
|
|
template:
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: backup
|
||
|
|
image: postgres:16-alpine
|
||
|
|
command:
|
||
|
|
- /bin/sh
|
||
|
|
- -c
|
||
|
|
- |
|
||
|
|
pg_dump -h postgres-service -U risk_user risk_platform_db > /backup/db_$(date +%Y%m%d).sql
|
||
|
|
volumeMounts:
|
||
|
|
- name: backup-storage
|
||
|
|
mountPath: /backup
|
||
|
|
volumes:
|
||
|
|
- name: backup-storage
|
||
|
|
persistentVolumeClaim:
|
||
|
|
claimName: backup-pvc
|
||
|
|
restartPolicy: OnFailure
|
||
|
|
```
|
||
|
|
|
||
|
|
### Recovery Procedure
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Stop Application
|
||
|
|
kubectl scale deployment risk-platform --replicas=0 -n risk-platform
|
||
|
|
|
||
|
|
# 2. Restore Database
|
||
|
|
psql -h localhost -U risk_user -d risk_platform_db < backup_xxx.sql
|
||
|
|
|
||
|
|
# 3. Verify Data
|
||
|
|
psql -h localhost -U risk_user -d risk_platform_db
|
||
|
|
\dt
|
||
|
|
SELECT COUNT(*) FROM companies;
|
||
|
|
|
||
|
|
# 4. Restart Application
|
||
|
|
kubectl scale deployment risk-platform --replicas=2 -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Rollback-Strategie
|
||
|
|
|
||
|
|
### Git-based Rollback
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Identify previous version
|
||
|
|
git log --oneline -10
|
||
|
|
|
||
|
|
# 2. Checkout previous version
|
||
|
|
git checkout <commit-hash>
|
||
|
|
|
||
|
|
# 3. Rebuild & Deploy
|
||
|
|
docker build -t risk-platform:rollback .
|
||
|
|
docker push registry.example.com/risk-platform:rollback
|
||
|
|
|
||
|
|
# 4. Update Kubernetes
|
||
|
|
kubectl set image deployment/risk-platform \
|
||
|
|
app=registry.example.com/risk-platform:rollback \
|
||
|
|
-n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database Rollback
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Rollback last migration
|
||
|
|
php artisan migrate:rollback --step=1 --force
|
||
|
|
|
||
|
|
# Rollback specific batch
|
||
|
|
php artisan migrate:rollback --batch=3 --force
|
||
|
|
|
||
|
|
# Full rollback to fresh state (CAUTION!)
|
||
|
|
php artisan migrate:fresh --force
|
||
|
|
```
|
||
|
|
|
||
|
|
### Blue-Green Deployment
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# deployment-blue.yaml (current)
|
||
|
|
metadata:
|
||
|
|
name: risk-platform-blue
|
||
|
|
labels:
|
||
|
|
app: risk-platform
|
||
|
|
version: blue
|
||
|
|
|
||
|
|
# deployment-green.yaml (new version)
|
||
|
|
metadata:
|
||
|
|
name: risk-platform-green
|
||
|
|
labels:
|
||
|
|
app: risk-platform
|
||
|
|
version: green
|
||
|
|
|
||
|
|
# Switch Traffic
|
||
|
|
# Change service selector from blue to green
|
||
|
|
kubectl patch service risk-platform-service \
|
||
|
|
-p '{"spec":{"selector":{"version":"green"}}}' \
|
||
|
|
-n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Problem: Container startet nicht
|
||
|
|
|
||
|
|
**Diagnose:**
|
||
|
|
```bash
|
||
|
|
docker logs risk-platform
|
||
|
|
kubectl logs deployment/risk-platform -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
**Häufige Ursachen:**
|
||
|
|
- `.env` fehlt oder ungültig
|
||
|
|
- Database Connection fehlgeschlagen
|
||
|
|
- Permissions auf `storage/` fehlen
|
||
|
|
|
||
|
|
**Lösung:**
|
||
|
|
```bash
|
||
|
|
# Check .env
|
||
|
|
docker exec -it risk-platform cat /var/www/html/.env
|
||
|
|
|
||
|
|
# Fix permissions
|
||
|
|
docker exec -it risk-platform chown -R nginx:nginx storage
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Problem: "500 Internal Server Error"
|
||
|
|
|
||
|
|
**Diagnose:**
|
||
|
|
```bash
|
||
|
|
# Laravel Logs
|
||
|
|
tail -f storage/logs/laravel.log
|
||
|
|
|
||
|
|
# Nginx Error Log
|
||
|
|
tail -f /var/log/nginx/error.log
|
||
|
|
```
|
||
|
|
|
||
|
|
**Häufige Ursachen:**
|
||
|
|
- `APP_KEY` nicht gesetzt
|
||
|
|
- Config Cache veraltet
|
||
|
|
- Database Connection Error
|
||
|
|
|
||
|
|
**Lösung:**
|
||
|
|
```bash
|
||
|
|
# Generate APP_KEY
|
||
|
|
php artisan key:generate --force
|
||
|
|
|
||
|
|
# Clear caches
|
||
|
|
php artisan optimize:clear
|
||
|
|
|
||
|
|
# Test DB connection
|
||
|
|
php artisan tinker
|
||
|
|
>>> DB::connection()->getPdo()
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Problem: Scheduled Jobs laufen nicht
|
||
|
|
|
||
|
|
**Diagnose:**
|
||
|
|
```bash
|
||
|
|
# Check CronJob Status
|
||
|
|
kubectl get cronjobs -n risk-platform
|
||
|
|
|
||
|
|
# Check Job History
|
||
|
|
kubectl get jobs -n risk-platform
|
||
|
|
|
||
|
|
# Check Logs
|
||
|
|
kubectl logs job/sync-backend-data-pool-xxx -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
**Lösung:**
|
||
|
|
```bash
|
||
|
|
# Test Schedule manually
|
||
|
|
php artisan schedule:run
|
||
|
|
|
||
|
|
# Test specific Job
|
||
|
|
php artisan backend:sync-data-pool --incremental
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Problem: High Memory Usage
|
||
|
|
|
||
|
|
**Diagnose:**
|
||
|
|
```bash
|
||
|
|
# Container Stats
|
||
|
|
docker stats risk-platform
|
||
|
|
|
||
|
|
# Pod Resource Usage
|
||
|
|
kubectl top pod -n risk-platform
|
||
|
|
```
|
||
|
|
|
||
|
|
**Lösung:**
|
||
|
|
- Reduce batch size in Jobs
|
||
|
|
- Increase memory limits
|
||
|
|
- Enable OPcache
|
||
|
|
- Use Redis for cache/session
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Performance Optimization
|
||
|
|
|
||
|
|
### OPcache Configuration
|
||
|
|
|
||
|
|
```ini
|
||
|
|
; /etc/php82/conf.d/opcache.ini
|
||
|
|
opcache.enable=1
|
||
|
|
opcache.memory_consumption=256
|
||
|
|
opcache.interned_strings_buffer=16
|
||
|
|
opcache.max_accelerated_files=10000
|
||
|
|
opcache.revalidate_freq=60
|
||
|
|
opcache.fast_shutdown=1
|
||
|
|
```
|
||
|
|
|
||
|
|
### Redis Configuration
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# redis.conf
|
||
|
|
maxmemory 512mb
|
||
|
|
maxmemory-policy allkeys-lru
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database Optimization
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Index on frequently queried columns
|
||
|
|
CREATE INDEX idx_transactions_status ON transactions(status);
|
||
|
|
CREATE INDEX idx_transactions_risk_score ON transactions(risk_score);
|
||
|
|
CREATE INDEX idx_companies_kyc_risk_level ON companies(kyc_risk_level);
|
||
|
|
|
||
|
|
-- Vacuum regularly
|
||
|
|
VACUUM ANALYZE companies;
|
||
|
|
VACUUM ANALYZE transactions;
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Security Best Practices
|
||
|
|
|
||
|
|
### SSL/TLS
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# ingress.yaml with TLS
|
||
|
|
spec:
|
||
|
|
tls:
|
||
|
|
- hosts:
|
||
|
|
- risk.example.com
|
||
|
|
secretName: risk-platform-tls
|
||
|
|
```
|
||
|
|
|
||
|
|
### Firewall Rules
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Allow HTTP/HTTPS only
|
||
|
|
ufw allow 80/tcp
|
||
|
|
ufw allow 443/tcp
|
||
|
|
ufw enable
|
||
|
|
```
|
||
|
|
|
||
|
|
### Security Headers
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
# nginx.conf
|
||
|
|
add_header X-Frame-Options "SAMEORIGIN";
|
||
|
|
add_header X-Content-Type-Options "nosniff";
|
||
|
|
add_header X-XSS-Protection "1; mode=block";
|
||
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Zusammenfassung
|
||
|
|
|
||
|
|
### Deployment-Optionen
|
||
|
|
|
||
|
|
| Option | Komplexität | Skalierbarkeit | Empfohlen für |
|
||
|
|
|--------|-------------|----------------|---------------|
|
||
|
|
| **Docker** | Niedrig | Mittel | Development, Small Production |
|
||
|
|
| **Kubernetes** | Hoch | Hoch | Production, Enterprise |
|
||
|
|
| **Traditional** | Mittel | Niedrig | Legacy Systems |
|
||
|
|
|
||
|
|
### Checkliste für Production
|
||
|
|
|
||
|
|
✅ Environment auf `production` gesetzt
|
||
|
|
✅ `APP_DEBUG=false`
|
||
|
|
✅ HTTPS aktiviert
|
||
|
|
✅ Database-Backup automatisiert
|
||
|
|
✅ Monitoring & Logging konfiguriert
|
||
|
|
✅ Scheduled Jobs laufen
|
||
|
|
✅ Health Checks aktiv
|
||
|
|
✅ Secrets sicher gespeichert
|
||
|
|
✅ Rollback-Strategie getestet
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Erstellt:** 2025-11-24
|
||
|
|
**Version:** 1.0
|
||
|
|
**Autor:** Risk Intelligence Platform Team
|