Restructure project: Move AKS cluster to beispiel-k8s-cluster directory
Major improvements: - Import existing Azure AKS cluster with aztfexport - Optimize VM size from Standard_D4d_v4 to Standard_D2as_v6 (50% cost reduction) - Configure availability zones to [1, 2] - Add comprehensive monitoring setup: * New Log Analytics Workspace * OMS Agent integration * Data Collection Rule for Container Insights * Email alerts for CPU and Memory - Refactor configuration: * Extract all values to variables.tf * Rename resources with meaningful names * Add detailed outputs.tf - Add project documentation: * Comprehensive README.md * cluster-status-commands.md with useful Azure CLI commands * terraform.tfvars.example template * .gitignore for sensitive files Infrastructure changes: - Resource Group: trusted_ai_demo_rg (Germany West Central) - AKS Cluster: trai_k8s_cluster (Kubernetes 1.33) - Node Pool: 2-3 nodes with auto-scaling - Network: VNet 10.0.0.0/16, Subnet 10.0.0.0/24 - Monitoring: Full Container Insights with alerts Cost optimization: ~€75/month (down from ~€140/month) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,128 +0,0 @@
|
||||
# Trusted AI Demo - OpenTofu Infrastructure
|
||||
|
||||
This project contains OpenTofu/Terraform configuration for the Trusted AI Demo infrastructure on Azure.
|
||||
|
||||
## Infrastructure Components
|
||||
|
||||
This configuration creates:
|
||||
|
||||
- **Resource Group**: Container for all Azure resources
|
||||
- **Virtual Network**: 10.0.0.0/16 address space
|
||||
- **Subnet**: 10.0.1.0/24 for VM placement
|
||||
- **Network Security Group**: With RDP (port 3389) rule for remote access
|
||||
- **Public IP**: Static public IP for VM access
|
||||
- **Network Interface**: Connects VM to the virtual network
|
||||
- **Windows Server 2022 VM**: Standard_B2s (2 vCPUs, 4 GB RAM)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [OpenTofu](https://opentofu.org/) >= 1.0 or [Terraform](https://www.terraform.io/) >= 1.0
|
||||
- Azure CLI configured with appropriate credentials
|
||||
- Azure subscription with necessary permissions
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Authenticate with Azure
|
||||
|
||||
```bash
|
||||
az login
|
||||
az account set --subscription "<your-subscription-id>"
|
||||
```
|
||||
|
||||
### 2. Initialize OpenTofu
|
||||
|
||||
```bash
|
||||
tofu init
|
||||
```
|
||||
|
||||
Or if using Terraform:
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
```
|
||||
|
||||
### 3. Review the Plan
|
||||
|
||||
```bash
|
||||
tofu plan
|
||||
```
|
||||
|
||||
### 4. Apply the Configuration
|
||||
|
||||
```bash
|
||||
tofu apply
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `main.tf` - Main infrastructure configuration
|
||||
- `variables.tf` - Input variable definitions
|
||||
- `outputs.tf` - Output value definitions
|
||||
- `terraform.tfvars.example` - Example variable values (copy to `terraform.tfvars`)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Configuration
|
||||
|
||||
1. Copy the example variables file:
|
||||
```bash
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
```
|
||||
|
||||
2. Edit `terraform.tfvars` and set your admin password:
|
||||
```hcl
|
||||
admin_password = "YourSecurePassword123!"
|
||||
```
|
||||
|
||||
**Important**: The password must be at least 12 characters long and contain uppercase, lowercase, and numbers.
|
||||
|
||||
3. **Security Recommendation**: Change `allowed_rdp_source` to your public IP address instead of `"*"`:
|
||||
```hcl
|
||||
allowed_rdp_source = "YOUR_PUBLIC_IP/32"
|
||||
```
|
||||
|
||||
You can find your public IP with:
|
||||
```bash
|
||||
curl ifconfig.me
|
||||
```
|
||||
|
||||
### Optional Customization
|
||||
|
||||
You can also customize:
|
||||
- `resource_group_name`: Name of the resource group
|
||||
- `location`: Azure region (default: westeurope)
|
||||
- `vm_name`: Name of the virtual machine
|
||||
- `vm_size`: VM size (default: Standard_B2s)
|
||||
- `vnet_address_space`: Virtual network address space
|
||||
- `subnet_address_prefix`: Subnet address prefix
|
||||
|
||||
## Connecting to the VM
|
||||
|
||||
After the infrastructure is created, you can connect to the Windows VM via RDP:
|
||||
|
||||
1. Get the public IP address:
|
||||
```bash
|
||||
tofu output vm_public_ip
|
||||
```
|
||||
|
||||
2. Connect using Remote Desktop:
|
||||
- **Windows**: Use the connection string from output:
|
||||
```bash
|
||||
tofu output rdp_connection_string
|
||||
```
|
||||
- **macOS**: Use Microsoft Remote Desktop app
|
||||
- **Linux**: Use Remmina or similar RDP client
|
||||
|
||||
3. Login credentials:
|
||||
- Username: The value you set for `admin_username` (default: azureadmin)
|
||||
- Password: The password you set in `terraform.tfvars`
|
||||
|
||||
## Cleanup
|
||||
|
||||
To destroy all resources:
|
||||
|
||||
```bash
|
||||
tofu destroy
|
||||
```
|
||||
|
||||
**Warning**: This will permanently delete all resources created by this configuration.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Exclude all .tfvars files, which are likely to contain sensitive data
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Ignore override files as they are usually used to override resources locally
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Include override files you do wish to add to version control using negation pattern
|
||||
# !example_override.tf
|
||||
|
||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||
*tfplan*
|
||||
|
||||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
|
||||
# Ignore aztfexport generated files (optional, keep if you want version history)
|
||||
aztfexportResourceMapping.json
|
||||
aztfexportSkippedResources.txt
|
||||
|
||||
# Ignore Mac OS files
|
||||
.DS_Store
|
||||
|
||||
# Ignore editor/IDE files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Ignore kubeconfig
|
||||
kubeconfig
|
||||
*.kubeconfig
|
||||
@@ -0,0 +1,22 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/azurerm" {
|
||||
version = "4.33.0"
|
||||
constraints = "4.33.0"
|
||||
hashes = [
|
||||
"h1:3N8/4SkUbJcy+s4W74sx0KCM75T8U0ytUfSv/rCj3ok=",
|
||||
"zh:1f61ce7671de78f09a8e7532bfe1366eff6e6af47050de0a06217162638b11a0",
|
||||
"zh:20f103ad60399090c219685ef71d29713f46aba32499c02cc640508f8821b067",
|
||||
"zh:22ce8ad46b32be74d7bd13c982f30e5ffc0749a42191de468309d4ca1ee427f2",
|
||||
"zh:23ec8730b2f22701dbef4fd72459b95800bd4f87dfd517898064e291b807af20",
|
||||
"zh:273202db879542def36a057072ef1b87aa0f1ccced81029c8ede55508d16080e",
|
||||
"zh:2c5bc87083e7ddf55e49e3159a4836353a24a01288f78a846399453d33375938",
|
||||
"zh:5dcae547287b377bc4c8e472e313d2178821264ac00cbf4fc6469dffb27a79cd",
|
||||
"zh:6601669c92bea9b7c6fc7e1e20a957389e5d7c02d06cd2dcda44c6ef62f3d7df",
|
||||
"zh:8b91e6153a586be514680c90b0d1a4aee7556a39376100e73dde8e9452537671",
|
||||
"zh:9b6742b8b4a7bc4efa62794bd3425e39166dd3ac53fbdd8efb3214d79f36ffab",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
"zh:f664e54e87c9466d54adc1f0dff41d8cca8d623aca317ff38aab29522b0d2508",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
# AKS Cluster Terraform Configuration
|
||||
|
||||
Dieses Projekt verwaltet einen Azure Kubernetes Service (AKS) Cluster mit vollständigem Monitoring und Alerting über Terraform.
|
||||
|
||||
## Projektübersicht
|
||||
|
||||
Der AKS Cluster wurde ursprünglich in Azure erstellt und anschließend mit `aztfexport` in Terraform importiert. Die Konfiguration wurde optimiert und um zusätzliche Monitoring-Komponenten erweitert.
|
||||
|
||||
## Infrastruktur-Komponenten
|
||||
|
||||
### Netzwerk
|
||||
- **Resource Group**: `trusted_ai_demo_rg` (Germany West Central)
|
||||
- **Virtual Network**: `trusted_ai_demo_vn` (10.0.0.0/16)
|
||||
- **Subnet**: `default` (10.0.0.0/24)
|
||||
|
||||
### AKS Cluster
|
||||
- **Name**: `trai_k8s_cluster`
|
||||
- **Kubernetes Version**: 1.33
|
||||
- **VM Size**: `Standard_D2as_v6` (2 vCPUs, 8 GB RAM)
|
||||
- **Node Count**: 2-3 (Auto-Scaling)
|
||||
- **Availability Zones**: 1, 2
|
||||
- **Features**:
|
||||
- OIDC Issuer enabled
|
||||
- Workload Identity enabled
|
||||
- Image Cleaner enabled (wöchentlich)
|
||||
- Automatische Updates (Sonntags)
|
||||
- Azure CNI Overlay Networking
|
||||
|
||||
### Monitoring & Logging
|
||||
- **Log Analytics Workspace**: `aksloganalyticstraik8scluster`
|
||||
- SKU: PerGB2018
|
||||
- Retention: 30 Tage
|
||||
- **Data Collection Rule**: Container Insights mit:
|
||||
- Container Logs V2
|
||||
- Kubernetes Events
|
||||
- Pod Inventory
|
||||
- **OMS Agent**: Automatisch auf allen Nodes deployed
|
||||
|
||||
### Alerting
|
||||
- **Action Group**: Email-Benachrichtigungen
|
||||
- **Metric Alerts**:
|
||||
- CPU Usage > 95%
|
||||
- Memory Working Set > 100%
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
.
|
||||
├── README.md # Diese Datei
|
||||
├── main.tf # Haupt-Ressourcendefinitionen
|
||||
├── variables.tf # Variablendefinitionen
|
||||
├── terraform.tfvars # Aktuelle Variablenwerte
|
||||
├── outputs.tf # Output-Definitionen
|
||||
├── provider.tf # Azure Provider-Konfiguration
|
||||
├── terraform.tf # Terraform-Einstellungen
|
||||
├── terraform.tfstate # State-Datei (lokal)
|
||||
├── aztfexportResourceMapping.json # Import-Mapping
|
||||
├── aztfexportSkippedResources.txt # Übersprungene Ressourcen
|
||||
└── cluster-status-commands.md # Nützliche Azure CLI Befehle
|
||||
|
||||
```
|
||||
|
||||
## Verwendung
|
||||
|
||||
### Voraussetzungen
|
||||
- Terraform >= 1.0
|
||||
- Azure CLI
|
||||
- kubectl
|
||||
- Authentifizierung bei Azure (`az login`)
|
||||
|
||||
### Initialisierung
|
||||
```bash
|
||||
terraform init
|
||||
```
|
||||
|
||||
### Änderungen anzeigen
|
||||
```bash
|
||||
terraform plan
|
||||
```
|
||||
|
||||
### Infrastruktur erstellen/aktualisieren
|
||||
```bash
|
||||
terraform apply
|
||||
```
|
||||
|
||||
### Infrastruktur löschen
|
||||
```bash
|
||||
terraform destroy
|
||||
```
|
||||
|
||||
### Cluster-Zugriff einrichten
|
||||
```bash
|
||||
az aks get-credentials --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --overwrite-existing
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
## Konfiguration
|
||||
|
||||
### Wichtige Variablen (terraform.tfvars)
|
||||
|
||||
```hcl
|
||||
location = "germanywestcentral"
|
||||
resource_group_name = "trusted_ai_demo_rg"
|
||||
aks_cluster_name = "trai_k8s_cluster"
|
||||
aks_node_vm_size = "Standard_D2as_v6"
|
||||
aks_node_zones = ["1", "2"]
|
||||
alert_email_address = "your-email@example.com"
|
||||
```
|
||||
|
||||
### Anpassbare Parameter
|
||||
|
||||
| Variable | Beschreibung | Default |
|
||||
|----------|--------------|---------|
|
||||
| `aks_node_pool_min_count` | Minimale Anzahl Nodes | 2 |
|
||||
| `aks_node_pool_max_count` | Maximale Anzahl Nodes | 3 |
|
||||
| `aks_node_vm_size` | VM-Größe für Nodes | Standard_D2as_v6 |
|
||||
| `aks_node_zones` | Availability Zones | ["1", "2"] |
|
||||
|
||||
## Outputs
|
||||
|
||||
Nach dem Apply werden folgende Informationen ausgegeben:
|
||||
|
||||
```bash
|
||||
terraform output
|
||||
```
|
||||
|
||||
- `aks_cluster_fqdn` - Cluster FQDN
|
||||
- `aks_cluster_id` - Cluster Resource ID
|
||||
- `aks_oidc_issuer_url` - OIDC Issuer URL
|
||||
- `log_analytics_workspace_id` - Log Analytics Workspace ID
|
||||
- Weitere...
|
||||
|
||||
## Kostenübersicht
|
||||
|
||||
**Monatliche Kosten (geschätzt)**:
|
||||
- 2x Standard_D2as_v6 Nodes: ~€70/Monat
|
||||
- Log Analytics Workspace: ~€2-5/Monat (bei geringer Nutzung)
|
||||
- **Gesamt**: ~€75-80/Monat
|
||||
|
||||
**Kostenoptimierung**:
|
||||
- Ursprünglich Standard_D4d_v4: ~€140/Monat
|
||||
- **Ersparnis**: ~€60-65/Monat (ca. 50%)
|
||||
|
||||
## Import-Historie
|
||||
|
||||
Das Projekt wurde mit `aztfexport` erstellt:
|
||||
|
||||
```bash
|
||||
aztfexport resource-group trusted_ai_demo_rg --non-interactive --plain-ui --continue
|
||||
```
|
||||
|
||||
**Importierte Ressourcen**: 9
|
||||
- Resource Group
|
||||
- Virtual Network + Subnet
|
||||
- AKS Cluster
|
||||
- Monitor Action Group
|
||||
- 2x Metric Alerts
|
||||
- Data Collection Rule (nachträglich hinzugefügt)
|
||||
- Log Analytics Workspace (nachträglich hinzugefügt)
|
||||
|
||||
**Übersprungene Ressourcen**: 2
|
||||
- Maintenance Configurations (automatisch verwaltet)
|
||||
|
||||
## Optimierungen
|
||||
|
||||
1. **VM-Größe**: Wechsel von Standard_D4d_v4 zu Standard_D2as_v6
|
||||
- 50% Kostenreduktion
|
||||
- Moderne AMD EPYC v6 Prozessoren
|
||||
- Ausreichend für die meisten Workloads
|
||||
|
||||
2. **Availability Zones**: Reduziert auf Zonen 1 und 2
|
||||
- Zone 3 war für das Abonnement nicht verfügbar
|
||||
|
||||
3. **Monitoring**: Komplett neu aufgesetzt
|
||||
- Eigener Log Analytics Workspace (statt shared)
|
||||
- Container Insights mit modernem V2 Format
|
||||
- Strukturierte Alerting-Regeln
|
||||
|
||||
4. **Variabilisierung**: Alle Werte in variables.tf ausgelagert
|
||||
- Einfache Anpassung
|
||||
- Wiederverwendbar
|
||||
|
||||
## Nützliche Befehle
|
||||
|
||||
Siehe [cluster-status-commands.md](./cluster-status-commands.md) für eine vollständige Liste nützlicher Azure CLI und kubectl Befehle.
|
||||
|
||||
## Sicherheitshinweise
|
||||
|
||||
- `terraform.tfvars` enthält sensitive Werte (Email-Adresse) und sollte nicht in Version Control eingecheckt werden
|
||||
- `.gitignore` ist konfiguriert, um State-Dateien und sensitive Daten auszuschließen
|
||||
- Verwenden Sie Azure Key Vault oder ähnliche Lösungen für Production-Secrets
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Quota-Fehler bei Node Pool Rotation
|
||||
Wenn Sie VM-Größen ändern und einen Quota-Fehler erhalten:
|
||||
```bash
|
||||
terraform destroy
|
||||
terraform apply
|
||||
```
|
||||
|
||||
### Log Analytics Workspace existiert nicht
|
||||
Falls der Workspace gelöscht wurde, erstellt Terraform automatisch einen neuen.
|
||||
|
||||
## Weiterführende Schritte
|
||||
|
||||
- [ ] State zu Azure Blob Storage migrieren (Remote State)
|
||||
- [ ] Azure Key Vault Integration für Secrets
|
||||
- [ ] CI/CD Pipeline einrichten
|
||||
- [ ] Weitere Monitoring Dashboards erstellen
|
||||
- [ ] Backup-Strategie implementieren
|
||||
|
||||
## Kontakt
|
||||
|
||||
Für Fragen oder Probleme, siehe die GitHub Issues.
|
||||
|
||||
## Lizenz
|
||||
|
||||
Projekt für Demo-Zwecke.
|
||||
@@ -0,0 +1,36 @@
|
||||
# AKS Cluster Status Befehle
|
||||
|
||||
Hier sind die Bash-Befehle, mit denen ich den Cluster-Status geprüft habe:
|
||||
|
||||
```bash
|
||||
# 1. Cluster-Status prüfen
|
||||
az aks show --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --query "{name:name, powerState:powerState.code, provisioningState:provisioningState, kubernetesVersion:kubernetesVersion, nodeResourceGroup:nodeResourceGroup}" -o table
|
||||
|
||||
# 2. Node Pool Status prüfen
|
||||
az aks nodepool list --resource-group trusted_ai_demo_rg --cluster-name trai_k8s_cluster --query "[].{name:name, count:count, vmSize:vmSize, provisioningState:provisioningState, powerState:powerState.code}" -o table
|
||||
|
||||
# 3. Kubeconfig herunterladen (für kubectl Zugriff)
|
||||
az aks get-credentials --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --overwrite-existing
|
||||
|
||||
# 4. Kubernetes Nodes anzeigen
|
||||
kubectl get nodes
|
||||
|
||||
# 5. Alle Pods in allen Namespaces anzeigen
|
||||
kubectl get pods -A
|
||||
```
|
||||
|
||||
## Zusätzliche nützliche Befehle
|
||||
|
||||
```bash
|
||||
# Detaillierte Cluster-Informationen
|
||||
az aks show --resource-group trusted_ai_demo_rg --name trai_k8s_cluster -o json
|
||||
|
||||
# Cluster-Ressourcen anzeigen
|
||||
kubectl top nodes
|
||||
|
||||
# Spezifische Namespace-Pods anzeigen
|
||||
kubectl get pods -n kube-system
|
||||
|
||||
# Cluster-Events anzeigen
|
||||
kubectl get events -A --sort-by='.lastTimestamp'
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
resource "azurerm_resource_group" "main" {
|
||||
location = var.location
|
||||
name = var.resource_group_name
|
||||
}
|
||||
|
||||
resource "azurerm_virtual_network" "main" {
|
||||
address_space = var.vnet_address_space
|
||||
location = var.location
|
||||
name = var.vnet_name
|
||||
resource_group_name = var.resource_group_name
|
||||
depends_on = [
|
||||
azurerm_resource_group.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_subnet" "default" {
|
||||
address_prefixes = var.subnet_address_prefixes
|
||||
name = var.subnet_name
|
||||
resource_group_name = var.resource_group_name
|
||||
virtual_network_name = var.vnet_name
|
||||
depends_on = [
|
||||
azurerm_virtual_network.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_log_analytics_workspace" "main" {
|
||||
name = "aksloganalytics${replace(var.aks_cluster_name, "_", "")}"
|
||||
location = var.location
|
||||
resource_group_name = var.resource_group_name
|
||||
sku = "PerGB2018"
|
||||
retention_in_days = 30
|
||||
depends_on = [
|
||||
azurerm_resource_group.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_kubernetes_cluster" "main" {
|
||||
automatic_upgrade_channel = "patch"
|
||||
dns_prefix = var.aks_dns_prefix
|
||||
image_cleaner_enabled = true
|
||||
image_cleaner_interval_hours = 168
|
||||
location = var.location
|
||||
name = var.aks_cluster_name
|
||||
oidc_issuer_enabled = true
|
||||
resource_group_name = var.resource_group_name
|
||||
workload_identity_enabled = true
|
||||
|
||||
default_node_pool {
|
||||
auto_scaling_enabled = true
|
||||
max_count = var.aks_node_pool_max_count
|
||||
min_count = var.aks_node_pool_min_count
|
||||
name = "agentpool"
|
||||
vm_size = var.aks_node_vm_size
|
||||
zones = var.aks_node_zones
|
||||
temporary_name_for_rotation = "temppool"
|
||||
upgrade_settings {
|
||||
max_surge = "10%"
|
||||
}
|
||||
}
|
||||
|
||||
identity {
|
||||
type = "SystemAssigned"
|
||||
}
|
||||
|
||||
maintenance_window_auto_upgrade {
|
||||
day_of_week = "Sunday"
|
||||
duration = 8
|
||||
frequency = "Weekly"
|
||||
interval = 1
|
||||
start_time = "00:00"
|
||||
utc_offset = "+00:00"
|
||||
}
|
||||
|
||||
maintenance_window_node_os {
|
||||
day_of_week = "Sunday"
|
||||
duration = 8
|
||||
frequency = "Weekly"
|
||||
interval = 1
|
||||
start_time = "00:00"
|
||||
utc_offset = "+00:00"
|
||||
}
|
||||
|
||||
oms_agent {
|
||||
log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id
|
||||
msi_auth_for_monitoring_enabled = true
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
azurerm_resource_group.main,
|
||||
azurerm_log_analytics_workspace.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_monitor_data_collection_rule" "aks_monitoring" {
|
||||
kind = "Linux"
|
||||
location = var.location
|
||||
name = "MSCI-${var.location}-${var.aks_cluster_name}"
|
||||
resource_group_name = var.resource_group_name
|
||||
|
||||
data_flow {
|
||||
destinations = ["ciworkspace"]
|
||||
streams = ["Microsoft-ContainerLog", "Microsoft-ContainerLogV2", "Microsoft-KubeEvents", "Microsoft-KubePodInventory"]
|
||||
}
|
||||
|
||||
data_sources {
|
||||
extension {
|
||||
extension_json = jsonencode({
|
||||
dataCollectionSettings = {
|
||||
enableContainerLogV2 = true
|
||||
interval = "1m"
|
||||
namespaceFilteringMode = "Off"
|
||||
}
|
||||
})
|
||||
extension_name = "ContainerInsights"
|
||||
name = "ContainerInsightsExtension"
|
||||
streams = ["Microsoft-ContainerLog", "Microsoft-ContainerLogV2", "Microsoft-KubeEvents", "Microsoft-KubePodInventory"]
|
||||
}
|
||||
}
|
||||
|
||||
destinations {
|
||||
log_analytics {
|
||||
name = "ciworkspace"
|
||||
workspace_resource_id = azurerm_log_analytics_workspace.main.id
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
azurerm_resource_group.main,
|
||||
azurerm_log_analytics_workspace.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_monitor_action_group" "alerts" {
|
||||
name = "RecommendedAlertRules-AG-c92012"
|
||||
resource_group_name = var.resource_group_name
|
||||
short_name = "alertc92012"
|
||||
|
||||
email_receiver {
|
||||
email_address = var.alert_email_address
|
||||
name = "Email_-EmailAction-"
|
||||
use_common_alert_schema = true
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
azurerm_resource_group.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_monitor_metric_alert" "cpu_alert" {
|
||||
auto_mitigate = false
|
||||
frequency = "PT5M"
|
||||
name = "CPU Usage Percentage - ${var.aks_cluster_name}"
|
||||
resource_group_name = var.resource_group_name
|
||||
scopes = [azurerm_kubernetes_cluster.main.id]
|
||||
|
||||
action {
|
||||
action_group_id = azurerm_monitor_action_group.alerts.id
|
||||
}
|
||||
|
||||
criteria {
|
||||
aggregation = "Average"
|
||||
metric_name = "node_cpu_usage_percentage"
|
||||
metric_namespace = "Microsoft.ContainerService/managedClusters"
|
||||
operator = "GreaterThan"
|
||||
threshold = 95
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
azurerm_resource_group.main
|
||||
]
|
||||
}
|
||||
|
||||
resource "azurerm_monitor_metric_alert" "memory_alert" {
|
||||
auto_mitigate = false
|
||||
frequency = "PT5M"
|
||||
name = "Memory Working Set Percentage - ${var.aks_cluster_name}"
|
||||
resource_group_name = var.resource_group_name
|
||||
scopes = [azurerm_kubernetes_cluster.main.id]
|
||||
|
||||
action {
|
||||
action_group_id = azurerm_monitor_action_group.alerts.id
|
||||
}
|
||||
|
||||
criteria {
|
||||
aggregation = "Average"
|
||||
metric_name = "node_memory_working_set_percentage"
|
||||
metric_namespace = "Microsoft.ContainerService/managedClusters"
|
||||
operator = "GreaterThan"
|
||||
threshold = 100
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
azurerm_resource_group.main
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
output "resource_group_name" {
|
||||
description = "Name of the resource group"
|
||||
value = azurerm_resource_group.main.name
|
||||
}
|
||||
|
||||
output "aks_cluster_name" {
|
||||
description = "Name of the AKS cluster"
|
||||
value = azurerm_kubernetes_cluster.main.name
|
||||
}
|
||||
|
||||
output "aks_cluster_id" {
|
||||
description = "ID of the AKS cluster"
|
||||
value = azurerm_kubernetes_cluster.main.id
|
||||
}
|
||||
|
||||
output "aks_cluster_fqdn" {
|
||||
description = "FQDN of the AKS cluster"
|
||||
value = azurerm_kubernetes_cluster.main.fqdn
|
||||
}
|
||||
|
||||
output "aks_kube_config" {
|
||||
description = "Kubeconfig for the AKS cluster"
|
||||
value = azurerm_kubernetes_cluster.main.kube_config_raw
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "aks_oidc_issuer_url" {
|
||||
description = "OIDC issuer URL of the AKS cluster"
|
||||
value = azurerm_kubernetes_cluster.main.oidc_issuer_url
|
||||
}
|
||||
|
||||
output "vnet_id" {
|
||||
description = "ID of the virtual network"
|
||||
value = azurerm_virtual_network.main.id
|
||||
}
|
||||
|
||||
output "subnet_id" {
|
||||
description = "ID of the subnet"
|
||||
value = azurerm_subnet.default.id
|
||||
}
|
||||
|
||||
output "log_analytics_workspace_id" {
|
||||
description = "ID of the Log Analytics workspace"
|
||||
value = azurerm_log_analytics_workspace.main.id
|
||||
}
|
||||
|
||||
output "log_analytics_workspace_name" {
|
||||
description = "Name of the Log Analytics workspace"
|
||||
value = azurerm_log_analytics_workspace.main.name
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
provider "azurerm" {
|
||||
features {
|
||||
}
|
||||
subscription_id = var.subscription_id
|
||||
environment = "public"
|
||||
use_msi = false
|
||||
use_cli = true
|
||||
use_oidc = false
|
||||
resource_provider_registrations = "none"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
terraform {
|
||||
backend "local" {}
|
||||
|
||||
required_providers {
|
||||
azurerm = {
|
||||
source = "hashicorp/azurerm"
|
||||
version = "4.33.0"
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Azure Region
|
||||
location = "germanywestcentral"
|
||||
|
||||
# Resource Group
|
||||
resource_group_name = "trusted_ai_demo_rg"
|
||||
|
||||
# Virtual Network
|
||||
vnet_name = "trusted_ai_demo_vn"
|
||||
subnet_name = "default"
|
||||
|
||||
# AKS Cluster Configuration
|
||||
aks_cluster_name = "trai_k8s_cluster"
|
||||
aks_dns_prefix = "traik8scluster"
|
||||
|
||||
# AKS Node Pool Configuration
|
||||
aks_node_vm_size = "Standard_D2as_v6"
|
||||
aks_node_zones = ["1", "2"]
|
||||
|
||||
# Auto-Scaling Configuration
|
||||
aks_node_pool_min_count = 2
|
||||
aks_node_pool_max_count = 3
|
||||
|
||||
# Alert Configuration
|
||||
# WICHTIG: Ersetzen Sie diese Email-Adresse mit Ihrer eigenen
|
||||
alert_email_address = "your-email@example.com"
|
||||
|
||||
# Azure Subscription ID (optional, falls abweichend vom Default)
|
||||
# subscription_id = "your-subscription-id"
|
||||
@@ -0,0 +1,83 @@
|
||||
variable "location" {
|
||||
description = "Azure region for resources"
|
||||
type = string
|
||||
default = "germanywestcentral"
|
||||
}
|
||||
|
||||
variable "resource_group_name" {
|
||||
description = "Name of the resource group"
|
||||
type = string
|
||||
default = "trusted_ai_demo_rg"
|
||||
}
|
||||
|
||||
variable "vnet_name" {
|
||||
description = "Name of the virtual network"
|
||||
type = string
|
||||
default = "trusted_ai_demo_vn"
|
||||
}
|
||||
|
||||
variable "vnet_address_space" {
|
||||
description = "Address space for the virtual network"
|
||||
type = list(string)
|
||||
default = ["10.0.0.0/16"]
|
||||
}
|
||||
|
||||
variable "subnet_name" {
|
||||
description = "Name of the subnet"
|
||||
type = string
|
||||
default = "default"
|
||||
}
|
||||
|
||||
variable "subnet_address_prefixes" {
|
||||
description = "Address prefixes for the subnet"
|
||||
type = list(string)
|
||||
default = ["10.0.0.0/24"]
|
||||
}
|
||||
|
||||
variable "aks_cluster_name" {
|
||||
description = "Name of the AKS cluster"
|
||||
type = string
|
||||
default = "trai_k8s_cluster"
|
||||
}
|
||||
|
||||
variable "aks_dns_prefix" {
|
||||
description = "DNS prefix for the AKS cluster"
|
||||
type = string
|
||||
default = "traik8scluster"
|
||||
}
|
||||
|
||||
variable "aks_node_pool_min_count" {
|
||||
description = "Minimum number of nodes in the AKS node pool"
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "aks_node_pool_max_count" {
|
||||
description = "Maximum number of nodes in the AKS node pool"
|
||||
type = number
|
||||
default = 3
|
||||
}
|
||||
|
||||
variable "aks_node_vm_size" {
|
||||
description = "VM size for AKS node pool"
|
||||
type = string
|
||||
default = "Standard_D2as_v6"
|
||||
}
|
||||
|
||||
variable "aks_node_zones" {
|
||||
description = "Availability zones for AKS nodes"
|
||||
type = list(string)
|
||||
default = ["1", "2"]
|
||||
}
|
||||
|
||||
variable "alert_email_address" {
|
||||
description = "Email address for alert notifications"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "subscription_id" {
|
||||
description = "Azure subscription ID"
|
||||
type = string
|
||||
default = "77677a80-2dea-493d-9867-f1c961b80fb3"
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
azurerm = {
|
||||
source = "hashicorp/azurerm"
|
||||
version = "~> 3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "azurerm" {
|
||||
features {}
|
||||
}
|
||||
|
||||
# Resource Group
|
||||
resource "azurerm_resource_group" "main" {
|
||||
name = var.resource_group_name
|
||||
location = var.location
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Virtual Network
|
||||
resource "azurerm_virtual_network" "main" {
|
||||
name = "${var.resource_group_name}-vnet"
|
||||
address_space = [var.vnet_address_space]
|
||||
location = azurerm_resource_group.main.location
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Subnet
|
||||
resource "azurerm_subnet" "main" {
|
||||
name = "default"
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
virtual_network_name = azurerm_virtual_network.main.name
|
||||
address_prefixes = [var.subnet_address_prefix]
|
||||
}
|
||||
|
||||
# Network Security Group
|
||||
resource "azurerm_network_security_group" "main" {
|
||||
name = "${var.vm_name}-nsg"
|
||||
location = azurerm_resource_group.main.location
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
|
||||
security_rule {
|
||||
name = "SSH"
|
||||
priority = 1001
|
||||
direction = "Inbound"
|
||||
access = "Allow"
|
||||
protocol = "Tcp"
|
||||
source_port_range = "*"
|
||||
destination_port_range = "22"
|
||||
source_address_prefix = var.allowed_ssh_source
|
||||
destination_address_prefix = "*"
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Public IP
|
||||
resource "azurerm_public_ip" "main" {
|
||||
name = "${var.vm_name}-pip"
|
||||
location = azurerm_resource_group.main.location
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
allocation_method = "Static"
|
||||
sku = "Standard"
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Network Interface
|
||||
resource "azurerm_network_interface" "main" {
|
||||
name = "${var.vm_name}-nic"
|
||||
location = azurerm_resource_group.main.location
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
|
||||
ip_configuration {
|
||||
name = "internal"
|
||||
subnet_id = azurerm_subnet.main.id
|
||||
private_ip_address_allocation = "Dynamic"
|
||||
public_ip_address_id = azurerm_public_ip.main.id
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Associate NSG with Network Interface
|
||||
resource "azurerm_network_interface_security_group_association" "main" {
|
||||
network_interface_id = azurerm_network_interface.main.id
|
||||
network_security_group_id = azurerm_network_security_group.main.id
|
||||
}
|
||||
|
||||
# Linux Virtual Machine
|
||||
resource "azurerm_linux_virtual_machine" "main" {
|
||||
name = var.vm_name
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
location = azurerm_resource_group.main.location
|
||||
size = var.vm_size
|
||||
admin_username = var.admin_username
|
||||
admin_password = var.admin_password
|
||||
disable_password_authentication = false
|
||||
|
||||
network_interface_ids = [
|
||||
azurerm_network_interface.main.id,
|
||||
]
|
||||
|
||||
os_disk {
|
||||
caching = "ReadWrite"
|
||||
storage_account_type = "Standard_LRS"
|
||||
}
|
||||
|
||||
source_image_reference {
|
||||
publisher = "Canonical"
|
||||
offer = "0001-com-ubuntu-server-jammy"
|
||||
sku = "22_04-lts-gen2"
|
||||
version = "latest"
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
output "resource_group_name" {
|
||||
description = "Name of the created resource group"
|
||||
value = azurerm_resource_group.main.name
|
||||
}
|
||||
|
||||
output "resource_group_id" {
|
||||
description = "ID of the created resource group"
|
||||
value = azurerm_resource_group.main.id
|
||||
}
|
||||
|
||||
output "location" {
|
||||
description = "Location of the resource group"
|
||||
value = azurerm_resource_group.main.location
|
||||
}
|
||||
|
||||
# Network Outputs
|
||||
output "vnet_name" {
|
||||
description = "Name of the virtual network"
|
||||
value = azurerm_virtual_network.main.name
|
||||
}
|
||||
|
||||
output "vnet_id" {
|
||||
description = "ID of the virtual network"
|
||||
value = azurerm_virtual_network.main.id
|
||||
}
|
||||
|
||||
output "subnet_id" {
|
||||
description = "ID of the subnet"
|
||||
value = azurerm_subnet.main.id
|
||||
}
|
||||
|
||||
# VM Outputs
|
||||
output "vm_name" {
|
||||
description = "Name of the virtual machine"
|
||||
value = azurerm_linux_virtual_machine.main.name
|
||||
}
|
||||
|
||||
output "vm_id" {
|
||||
description = "ID of the virtual machine"
|
||||
value = azurerm_linux_virtual_machine.main.id
|
||||
}
|
||||
|
||||
output "vm_private_ip" {
|
||||
description = "Private IP address of the VM"
|
||||
value = azurerm_network_interface.main.private_ip_address
|
||||
}
|
||||
|
||||
output "vm_public_ip" {
|
||||
description = "Public IP address of the VM"
|
||||
value = azurerm_public_ip.main.ip_address
|
||||
}
|
||||
|
||||
output "ssh_connection_string" {
|
||||
description = "SSH connection string for the VM"
|
||||
value = "ssh ${azurerm_linux_virtual_machine.main.admin_username}@${azurerm_public_ip.main.ip_address}"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":4,"terraform_version":"1.11.1","serial":11,"lineage":"cad35d7f-13a9-933b-a7ef-af99f16a5d08","outputs":{},"resources":[],"check_results":null}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,23 +0,0 @@
|
||||
# Copy this file to terraform.tfvars and customize as needed
|
||||
|
||||
# Resource Group Configuration
|
||||
resource_group_name = "rg-trusted-ai-demo"
|
||||
location = "austriaeast"
|
||||
|
||||
# Network Configuration
|
||||
vnet_address_space = "10.0.0.0/16"
|
||||
subnet_address_prefix = "10.0.1.0/24"
|
||||
allowed_ssh_source = "*" # Change to your public IP for better security, e.g., "1.2.3.4/32"
|
||||
|
||||
# Virtual Machine Configuration
|
||||
vm_name = "vm-trusted-ai"
|
||||
vm_size = "Standard_B2ats_v2"
|
||||
admin_username = "azureadmin"
|
||||
admin_password = "Hab2009Keins!"
|
||||
|
||||
# Tags
|
||||
tags = {
|
||||
Environment = "dev"
|
||||
Project = "trusted-ai-demo"
|
||||
ManagedBy = "OpenTofu"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
# Copy this file to terraform.tfvars and customize as needed
|
||||
|
||||
# Resource Group Configuration
|
||||
resource_group_name = "rg-trusted-ai-demo"
|
||||
location = "westus"
|
||||
|
||||
# Network Configuration
|
||||
vnet_address_space = "10.0.0.0/16"
|
||||
subnet_address_prefix = "10.0.1.0/24"
|
||||
allowed_rdp_source = "*" # Change to your public IP for better security, e.g., "1.2.3.4/32"
|
||||
|
||||
# Virtual Machine Configuration
|
||||
vm_name = "vm-trusted-ai"
|
||||
vm_size = "Standard_B2s"
|
||||
admin_username = "azureadmin"
|
||||
admin_password = "YourSecurePassword123!" # IMPORTANT: Change this! Min 12 characters, must include upper, lower, number
|
||||
|
||||
# Tags
|
||||
tags = {
|
||||
Environment = "dev"
|
||||
Project = "trusted-ai-demo"
|
||||
ManagedBy = "OpenTofu"
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
variable "resource_group_name" {
|
||||
description = "Name of the resource group"
|
||||
type = string
|
||||
default = "rg-trusted-ai-demo"
|
||||
}
|
||||
|
||||
variable "location" {
|
||||
description = "Azure region for resources"
|
||||
type = string
|
||||
default = "austriaeast"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Tags to apply to all resources"
|
||||
type = map(string)
|
||||
default = {
|
||||
Environment = "dev"
|
||||
Project = "trusted-ai-demo"
|
||||
ManagedBy = "OpenTofu"
|
||||
}
|
||||
}
|
||||
|
||||
# Network Configuration
|
||||
variable "vnet_address_space" {
|
||||
description = "Address space for the virtual network"
|
||||
type = string
|
||||
default = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
variable "subnet_address_prefix" {
|
||||
description = "Address prefix for the subnet"
|
||||
type = string
|
||||
default = "10.0.1.0/24"
|
||||
}
|
||||
|
||||
variable "allowed_ssh_source" {
|
||||
description = "Source IP address or range allowed to SSH to the VM (use your public IP or '*' for any - not recommended)"
|
||||
type = string
|
||||
default = "*"
|
||||
}
|
||||
|
||||
# Virtual Machine Configuration
|
||||
variable "vm_name" {
|
||||
description = "Name of the virtual machine"
|
||||
type = string
|
||||
default = "vm-trusted-ai"
|
||||
}
|
||||
|
||||
variable "vm_size" {
|
||||
description = "Size of the virtual machine"
|
||||
type = string
|
||||
default = "Standard_B2s"
|
||||
}
|
||||
|
||||
variable "admin_username" {
|
||||
description = "Admin username for the virtual machine"
|
||||
type = string
|
||||
default = "azureadmin"
|
||||
}
|
||||
|
||||
variable "admin_password" {
|
||||
description = "Admin password for the virtual machine (use strong password, min 12 characters)"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
Reference in New Issue
Block a user