Azure IoT Operations auf Arc-enabled Kubernetes - Troubleshooting Guide
Einleitung
Du hast Azure IoT Operations auf einem Azure Arc-enabled Kubernetes Cluster deployed - und auf einmal läuft etwas nicht so, wie es soll. Pods crashen, der MQTT Broker antwortet nicht, die Verbindung zu Arc ist unterbrochen, oder die OPC UA Assets senden keine Daten mehr.
Willkommen in der Realität von Edge-Deployments.
Troubleshooting in einer verteilten IoT-Umgebung ist komplex, weil viele Schichten zusammenwirken: Kubernetes, Azure Arc Agents, das IoT Operations Control Plane, der MQTT Broker, Zertifikate, Netzwerk-Policies und die Cloud-seitigen Azure-Services. Ein Problem auf einer Ebene kann sich als Symptom auf einer ganz anderen Ebene zeigen.
In diesem Post zeige ich dir:
- Die richtigen Diagnose-Tools für Azure IoT Operations (nicht nur
kubectl logs) - Die häufigsten Fehlerkategorien und wie du sie erkennst
- Konkrete kubectl- und az-cli-Befehle für die Fehleranalyse
- Observability mit Azure Monitor, Prometheus und Grafana aufbauen
- Best Practices, damit viele Fehler erst gar nicht auftreten
Das wichtigste Tool zuerst: az iot ops check
Bevor du anfängst, manuell Logs zu durchsuchen, solltest du diesen Befehl kennen. Er ist der schnellste Einstieg in die Diagnose:
az iot ops check
az iot ops check wertet deinen Azure IoT Operations Deployment auf Health, Konfiguration und Nutzbarkeit aus. Er prüft alle AIO-Komponenten systematisch und gibt dir eine strukturierte Übersicht über gefundene Probleme.
Für ein detaillierteres Ergebnis:
az iot ops check --as-object # JSON-Output für Scripting
az iot ops check --context <dein-kubectl-context> # bei mehreren Clustern
Support-Bundle erstellen
Wenn das Problem tiefer liegt oder du Microsoft Support einbeziehen möchtest, erstellt dieser Befehl ein vollständiges Diagnose-Paket:
az iot ops support create-bundle
Das Bundle ist ein ZIP-Archiv mit Logs, Events, Custom Resource Status und Konfigurationen aller AIO-Komponenten. Ideal für die Kommunikation mit dem Support oder für eine gründliche Offline-Analyse.
💡 Voraussetzung: Azure CLI ab Version 2.53.0 und die
azure-iot-opsCLI-Extension müssen installiert sein:az extension add --upgrade --name azure-iot-ops
Kategorie 1: Azure Arc Agent Probleme
Symptome
- Der Cluster taucht nicht im Azure Portal auf
az connectedk8s connectschlägt fehl oder hängt- Arc-Agents crashen oder starten nicht
Diagnose
Alle Azure Arc Agents laufen als Pods im Namespace azure-arc. Prüfe deren Status:
kubectl get deployments,pods -n azure-arc
Die Ausgabe sollte ungefähr so aussehen - alle Pods mit Running und vollständiger READY-Anzahl:
NAME READY STATUS RESTARTS AGE
pod/cluster-metadata-operator-... 2/2 Running 0 3d
pod/clusterconnect-agent-... 3/3 Running 0 3d
pod/clusteridentityoperator-... 2/2 Running 0 3d
pod/config-agent-... 1/2 Running 0 3d
pod/controller-manager-... 2/2 Running 0 3d
pod/extension-manager-... 3/3 Running 0 3d
pod/kube-aad-proxy-... 2/2 Running 0 3d
pod/metrics-agent-... 2/2 Running 0 3d
pod/resource-sync-agent-... 2/2 Running 0 3d
Pods im Status CrashLoopBackOff oder Pending - das sind die Kandidaten:
kubectl describe pod <pod-name> -n azure-arc
kubectl logs <pod-name> -n azure-arc --previous # Logs des letzten Crashes
Häufige Ursachen und Lösungen
Problem: clusterconnect-agent oder config-agent im CrashLoopBackOff
Prüfe, ob das MSI-Zertifikat vorhanden ist:
kubectl get secret -n azure-arc -o yaml | grep name:
Du solltest azure-identity-certificate in der Liste sehen. Fehlt es, ist die System-Assigned Managed Identity nicht korrekt eingerichtet. Lösung: Arc-Deployment löschen und neu verbinden:
az connectedk8s delete --name <cluster-name> --resource-group <rg>
az connectedk8s connect --name <cluster-name> -l <region> --resource-group <rg> \
--enable-oidc-issuer --enable-workload-identity
Problem: kube-aad-proxy Pod fehlt oder startet nicht
Prüfe, ob das kube-aad-proxy-certificate Secret vorhanden ist:
kubectl get secret -n azure-arc -o yaml | grep kube-aad-proxy
Fehlt es: Arc-Deployment löschen und mit einem anderen Cluster-Namen neu verbinden.
Problem: Outbound Connectivity - Arc kann Azure nicht erreichen
Arc Agents benötigen ausgehende Verbindungen zu einer Reihe von Endpunkten. Prüfe, ob folgende Domains aus dem Cluster erreichbar sind:
# Von einem Pod im Cluster testen:
kubectl run curl-test --image=curlimages/curl --restart=Never --rm -it -- \
curl -v https://management.azure.com
Pflicht-Endpunkte für Azure Arc:
management.azure.comlogin.microsoftonline.commcr.microsoft.com*.servicebus.windows.net(für Cluster Connect)<region>.obo.arc.azure.com:8084
Wenn ein Proxy im Einsatz ist, muss er beim az connectedk8s connect angegeben werden:
az connectedk8s connect --name <cluster-name> --resource-group <rg> \
--proxy-http http://proxy:port \
--proxy-https http://proxy:port \
--proxy-skip-range 169.254.169.254,10.0.0.0/8
Problem: UnauthorizedNamespaceError beim AIO-Deployment
Microsoft.ExtendedLocation resource provider does not have the required
permissions to create a namespace on the cluster.
Das Custom Locations Feature ist nicht korrekt aktiviert. Lösung:
export OBJECT_ID=$(az ad sp show --id bc313c14-388c-4e7d-a58e-70017303ee3b --query id -o tsv)
az connectedk8s enable-features -n <cluster-name> -g <rg> \
--custom-locations-oid $OBJECT_ID \
--features cluster-connect custom-locations
Kategorie 2: Azure IoT Operations Deployment schlägt fehl
Diagnose: Der AIO check-Befehl zuerst
az iot ops check
Danach, für spezifische Services:
az iot ops check --svc broker # Nur MQTT Broker prüfen
az iot ops check --svc dataflow # Nur Data Flows prüfen
az iot ops check --svc opcua # Nur OPC UA Connector prüfen
Häufige Ursachen und Lösungen
Problem: LinkedAuthorizationFailed
The client has permission to perform action ... however, it does not have
permission to perform action(s) Microsoft.Authorization/roleAssignments/write
Der deploying Principal hat keine ausreichenden Berechtigungen. Für das AIO-Deployment wird die Rolle Azure IoT Operations Onboarding benötigt, die Microsoft.Authorization/roleAssignments/write beinhaltet.
az role assignment create \
--assignee <principal-id> \
--role "Azure IoT Operations Onboarding" \
--scope /subscriptions/<sub-id>/resourceGroups/<rg>
Problem: MQTT Broker Deployment schlägt wegen Ressourcenmangel fehl
kubectl describe pod -l app=aio-broker -n azure-iot-operations
# Ausgabe prüfen auf: Insufficient memory / Insufficient cpu
Der Broker benötigt je nach Cardinality-Konfiguration erhebliche Ressourcen. Mindestanforderung für AIO: 4 vCPUs, 10 GB RAM. Prüfe den tatsächlichen Verbrauch:
kubectl top nodes
kubectl top pods -n azure-iot-operations
Problem: Namespace bleibt beim Löschen in Terminating hängen
Nie direkt den Namespace löschen! AIO Custom Resources haben Finalizers, die das blockieren. Immer den offiziellen Weg gehen:
az iot ops delete --name <instance-name> --resource-group <rg>
Kategorie 3: MQTT Broker Probleme
Diagnose
# Status aller Broker-Pods
kubectl get pods -n azure-iot-operations -l app=aio-broker
# Listener-Status anzeigen
kubectl get brokerlistener -n azure-iot-operations
# Details zu einem spezifischen Listener
kubectl describe brokerlistener <listener-name> -n azure-iot-operations
# Broker-Logs (Frontend)
kubectl logs -l app=aio-broker-frontend -n azure-iot-operations --tail=100
# Health Manager Logs (wichtig für TLS/Zertifikat-Probleme)
kubectl logs -l app=health-manager -n azure-iot-operations --tail=100
Häufige Ursachen und Lösungen
Problem: AllBrokersDown Fehler in Data Flow Logs
Global error: AllBrokersDown
Der Data Flow konnte 4-5 Minuten lang keine Nachrichten verarbeiten. Prüfe:
- Sind die richtigen Topic-Namen konfiguriert?
- Laufen alle Broker-Pods?
- Ist der BrokerListener korrekt konfiguriert?
kubectl get pods -n azure-iot-operations -l app=aio-broker
kubectl get brokerlistener -n azure-iot-operations -o yaml
Problem: TLS-Verbindung schlägt fehl - server certificate not found
kubectl logs -l app=health-manager -n azure-iot-operations | grep -i certificate
Typische Meldung: Server certificate server-cert-secret not found. Awaiting creation of secret.
Das referenzierte Kubernetes Secret für das TLS-Zertifikat existiert nicht. Prüfe:
kubectl get secret -n azure-iot-operations | grep tls
Fehlende Secrets entweder manuell erstellen (manuelles TLS) oder cert-manager konfigurieren (automatisches TLS).
Problem: MQTT-Verbindung von extern wird abgelehnt
Checkliste in dieser Reihenfolge prüfen:
# 1. Externe IP vorhanden?
kubectl get service -n azure-iot-operations
# 2. TCP-Verbindung erreichbar?
nc -zv <external-ip> 8883
# 3. TLS-Zertifikat prüfen
openssl s_client -connect <external-ip>:8883 -CAfile ca.crt
# 4. Listener-Konfiguration korrekt?
kubectl describe brokerlistener -n azure-iot-operations
# 5. BrokerAuthentication verknüpft?
kubectl get brokerauthentication -n azure-iot-operations -o yaml
Problem: Clients werden nach einiger Zeit getrennt
Azure IoT Operations trennt Clients automatisch, wenn deren Credentials ablaufen:
- SAT-Clients (Kubernetes Service Account Token): Token läuft ab
- X.509-Clients: Client-Zertifikat abgelaufen
- Custom Auth-Clients: Ablaufzeit vom Custom Auth Server bestimmt
MQTT v5 Clients können sich mit einem neuen Credential re-authentifizieren, ohne die Verbindung zu trennen:
# Neues SAT-Token für Tests generieren
kubectl create token <service-account> -n azure-iot-operations --audience <audience>
Kategorie 4: OPC UA Connector Probleme
Diagnose
# OPC UA Connector Pods
kubectl get pods -n azure-iot-operations -l app.kubernetes.io/component=akri-agent
# Logs des OPC UA Connectors
kubectl logs -l app.kubernetes.io/component=aio-opc -n azure-iot-operations --tail=100
# Asset-Status in der Operations Experience prüfen
# https://iotoperations.azure.com
Häufige Ursachen und Lösungen
Problem: BadSecurityModeRejected - OPC UA Server Verbindung schlägt fehl
Der Connector versucht, sich mit einem OPC UA Server zu verbinden, der nur unsichere Endpoints ohne Security-Policy anbietet. Zwei Optionen:
Option A - Security explizit auf None setzen (nur für Tests!):
Im Device-Konfiguration in der Operations Experience oder per YAML:
additionalConfiguration:
securityMode: none
securityPolicy: "http://opcfoundation.org/UA/SecurityPolicy#None"
Option B - OPC UA Server um einen sicheren Endpoint erweitern und Certificate Trust konfigurieren. Das ist der empfohlene Weg für Produktionsumgebungen.
Problem: OPC PLC Simulator sendet keine Daten nach Device-Erstellung
Bekanntes Issue: Der Simulator erfordert, dass nicht vertrauenswürdige Server-Zertifikate automatisch akzeptiert werden. In der Operations Experience beim Device Endpoint die Option "Automatically accept untrusted certificates" aktivieren.
⚠️ Diese Einstellung nur in Entwicklungsumgebungen verwenden!
Problem: Resource Sync funktioniert nicht - Akri entdeckt keine Geräte
az iot ops enable-rsync -n <instance-name> -g <resource-group>
Wenn der CLI-User keine Berechtigung hat, die OID des K8 Bridge Service Principals abzufragen:
# OID manuell ermitteln
az ad sp list --display-name "K8 Bridge" --query "[0].appId" -o tsv
# Dann mit expliziter OID
az iot ops enable-rsync --k8-bridge-sp-oid <oid> -n <instance-name> -g <rg>
Kategorie 5: Azure Key Vault und Secret Management
Diagnose
# Secret Provider Class Status
kubectl get secretproviderclass -n azure-iot-operations
# Fehler beim Secret-Mount
kubectl describe pod <pod-name> -n azure-iot-operations | grep -A 10 Events
Problem: SecretNotFound in Key Vault
rpc error: ... GET https://<vault>.vault.azure.net/secrets/<name>/...
RESPONSE 404: SecretNotFound
Das Secret, das AIO synchronisieren soll, existiert nicht in Azure Key Vault. Das Secret muss vor der AIO-Konfiguration in Key Vault angelegt werden.
Problem: Key Vault Secrets Officer Berechtigungen fehlen
Wenn in der Operations Experience Secrets oder Zertifikate nicht hinzugefügt werden können:
az role assignment create \
--assignee <entra-id-user-or-sp> \
--role "Key Vault Secrets Officer" \
--scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault-name>
Kategorie 6: Netzwerk und Firewall
Pflicht-Ports für Azure IoT Operations
Folgende Ports müssen ausgehend aus dem Cluster erreichbar sein:
| Protokoll | Port | Zweck |
|---|---|---|
| HTTPS | 443 | Azure Management, MCR, ACR |
| AMQP | 5671 | Azure Service Bus / Event Hubs |
| MQTT+TLS | 8883 | External MQTT Clients (Inbound) |
| HTTPS | 8084 | <region>.obo.arc.azure.com (Arc Cluster Connect) |
Für die ausgehenden Endpunkte von IoT Operations gelten zusätzlich die Arc-enabled Kubernetes Network Requirements.
Netzwerk-Debugging
# DNS-Auflösung im Cluster testen
kubectl run dns-test --image=busybox --restart=Never --rm -it -- \
nslookup management.azure.com
# Ausgehende Verbindungen prüfen
kubectl run curl-test --image=curlimages/curl --restart=Never --rm -it -- \
curl -v https://management.azure.com
# Netzwerk-Policy prüfen
kubectl get networkpolicy -n azure-iot-operations
kubectl get networkpolicy -n azure-arc
Observability aufbauen: Azure Monitor + Prometheus + Grafana
Das beste Troubleshooting beginnt, bevor Fehler auftreten. Azure IoT Operations unterstützt eine vollständige Observability-Stack aus Prometheus-Metriken, Container Insights Logs und Grafana-Dashboards.
Setup in 3 Schritten
Schritt 1: Azure-Ressourcen erstellen
# Azure Monitor Workspace für Metriken
az monitor account create \
--name <workspace-name> \
--resource-group <rg> \
--location <region>
# Azure Managed Grafana
az grafana create \
--name <grafana-name> \
--resource-group <rg>
# Log Analytics Workspace für Container Insights
az monitor log-analytics workspace create \
-g <rg> \
-n <logs-workspace-name>
Schritt 2: Metrics Collection am Arc-Cluster aktivieren
# Prometheus-Metriken aktivieren
az k8s-extension create \
--name azuremonitor-metrics \
--cluster-name <cluster-name> \
--resource-group <rg> \
--cluster-type connectedClusters \
--extension-type Microsoft.AzureMonitor.Containers.Metrics \
--configuration-settings \
azure-monitor-workspace-resource-id=<monitor-workspace-id> \
grafana-resource-id=<grafana-id>
# Container Insights Logs aktivieren
az k8s-extension create \
--name azuremonitor-containers \
--cluster-name <cluster-name> \
--resource-group <rg> \
--cluster-type connectedClusters \
--extension-type Microsoft.AzureMonitor.Containers \
--configuration-settings \
logAnalyticsWorkspaceResourceID=<log-analytics-id>
Schritt 3: OpenTelemetry Collector deployen
AIO exportiert Metriken über OpenTelemetry. Installiere den Collector mit Helm:
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update
helm upgrade --install aio-observability open-telemetry/opentelemetry-collector \
-f otel-collector-values.yaml \
--namespace azure-iot-operations
Nach dem Setup: Im AIO GitHub Repository gibt es fertige Grafana Dashboard-JSON-Dateien für AIO, die du direkt importieren kannst.
Nützliche Log-Queries in Azure Log Analytics
// AIO Fehler der letzten Stunde
ContainerLog
| where TimeGenerated > ago(1h)
| where Namespace == "azure-iot-operations"
| where LogEntry contains "error" or LogEntry contains "Error"
| project TimeGenerated, ContainerName, LogEntry
| order by TimeGenerated desc
// MQTT Broker Verbindungsfehler
ContainerLog
| where TimeGenerated > ago(1h)
| where ContainerName contains "aio-broker"
| where LogEntry contains "connection" or LogEntry contains "auth"
| project TimeGenerated, ContainerName, LogEntry
| order by TimeGenerated desc
// Arc Agent Events
KubeEvents
| where TimeGenerated > ago(1h)
| where Namespace == "azure-arc"
| where Reason != "Pulled" and Reason != "Started"
| project TimeGenerated, Name, Reason, Message
| order by TimeGenerated desc
Best Practices: Fehler von vornherein vermeiden
✅ 1. AIO immer mit az iot ops delete deinstallieren
Niemals den azure-iot-operations Namespace direkt löschen. Die Custom Resources haben Finalizers, die den Namespace in einem dauerhaften Terminating-Zustand hinterlassen können:
# Richtig:
az iot ops delete --name <instance-name> --resource-group <rg>
# Falsch:
kubectl delete namespace azure-iot-operations # ❌
✅ 2. Default-BrokerListener niemals anfassen
Der Default-Listener (ClusterIP, Port 18883) ist für die interne Kommunikation zwischen AIO-Komponenten reserviert. Für externe Verbindungen immer einen neuen Listener erstellen.
✅ 3. az iot ops check in CI/CD integrieren
Nach jedem Deployment oder Update ausführen, um Probleme früh zu erkennen:
az iot ops check --as-object | jq '.status'
✅ 4. Netzwerk-Anforderungen vor dem Deployment prüfen
Azure Arc und AIO benötigen ausgehende Verbindungen zu einer Reihe von Azure-Endpunkten. Führe vor dem Deployment einen Connectivity-Check durch:
az connectedk8s troubleshoot --name <cluster-name> --resource-group <rg>
✅ 5. Ressourcen-Anforderungen realistisch planen
Mindestanforderungen für AIO auf einem Produktionscluster:
- RAM: 16 GB (10 GB für AIO)
- CPU: 4 vCPUs
- Für Multi-Node mit Fault Tolerance: 32 GB RAM, 8 vCPUs empfohlen
✅ 6. Observability von Anfang an aktivieren
Nicht erst aktivieren, wenn es brennt. Der Observability-Stack aus Azure Monitor, Prometheus und Grafana sollte Teil jedes AIO-Deployments sein.
✅ 7. Auto-Upgrade deaktivieren
Beim initialen Arc-Connect --disable-auto-upgrade setzen und Updates kontrolliert manuell durchführen:
az connectedk8s connect --name <cluster> --resource-group <rg> \
--disable-auto-upgrade
Schnell-Referenz: Die wichtigsten Debugging-Befehle
# ═══ AIO Gesamt-Health ═══
az iot ops check
# ═══ Support Bundle erstellen ═══
az iot ops support create-bundle
# ═══ Arc Agents ═══
kubectl get pods -n azure-arc
kubectl logs <pod> -n azure-arc
# ═══ AIO Pods ═══
kubectl get pods -n azure-iot-operations
kubectl top pods -n azure-iot-operations
# ═══ MQTT Broker ═══
kubectl get brokerlistener -n azure-iot-operations
kubectl logs -l app=aio-broker-frontend -n azure-iot-operations --tail=100
kubectl logs -l app=health-manager -n azure-iot-operations --tail=100
# ═══ Kubernetes Events (sehr nützlich!) ═══
kubectl get events -n azure-iot-operations --sort-by='.lastTimestamp'
kubectl get events -n azure-arc --sort-by='.lastTimestamp'
# ═══ Custom Resource Status ═══
kubectl get instance -n azure-iot-operations -o yaml
kubectl get broker -n azure-iot-operations -o yaml
kubectl get brokerlistener -n azure-iot-operations -o yaml
# ═══ Zertifikate ═══
kubectl get certificate -n azure-iot-operations
kubectl get secret -n azure-iot-operations | grep tls
Fazit
Troubleshooting in Azure IoT Operations folgt einer klaren Logik: von oben nach unten. Beginne immer mit az iot ops check für einen schnellen Überblick, dann arbeite dich durch die Schichten - Arc Agents, AIO Control Plane, MQTT Broker, Konnektoren, Netzwerk.
Die häufigsten Fehlerquellen in der Praxis:
- Berechtigungen: RBAC-Rollen fehlen bei Deployment oder Secret-Zugriff
- Netzwerk: Ausgehende Verbindungen zu Azure-Endpunkten sind geblockt
- Zertifikate: TLS-Zertifikate fehlen, sind abgelaufen oder enthalten nicht die richtige SAN
- Ressourcen: Zu wenig RAM/CPU für den MQTT Broker
Und das Wichtigste: Observability nicht als Nachgedanken behandeln. Azure Monitor, Prometheus und Grafana sind keine Add-ons - sie sind die Grundlage dafür, dass du Probleme erkennst, bevor sie zum Ausfall werden.
Weiterführende Links
- Troubleshoot Azure IoT Operations - Microsoft Docs
- Known Issues - Azure IoT Operations
- Troubleshoot Azure Arc-enabled Kubernetes - Microsoft Docs
- Arc-enabled Kubernetes Diagnose Connection Issues
- Observability mit Azure Monitor und Grafana - Microsoft Docs
- az iot ops CLI Reference
- Azure IoT Operations Network Requirements