Troubleshooting-How-tos¶
Schritt-für-Schritt-Anleitungen für Probleme, auf die das Plattform-Team in den pipelines, auf den Build-Agents und in der lokalen Entwicklung stößt. Für einen ersten Blick auf einen Incident siehe Wo du zuerst nachschaust. Für bekannte Defekte siehe Bekannte Probleme.
| Problem | Weiter zu |
|---|---|
Ein plan oder apply schlägt fehl oder hängt ohne klaren Fehler |
Terraform-Logging einschalten |
| Build-Agents haben nach einem destroy ihre Route zu Azure DevOps verloren | Defekte Agent-Konnektivität wiederherstellen |
| Pipeline-Jobs warten auf Agents, oder Agents registrieren sich nie | Den agent pool mit den Smoke-Tests prüfen |
| Du erreichst von deinem Entwicklungsrechner keine privaten Ressourcen | Private Ressourcen aus einem Dev Container erreichen |
Terraform-Logging einschalten¶
Verwende das, wenn ein Terraform-plan- oder apply-Schritt ohne klaren Fehler fehlschlägt oder hängt, wenn du die API-Aufrufe sehen musst, die ein
Provider macht, oder wenn der support nach Terraform-Debug-Logs fragt.
Terraform hat zwei Log-Einstellungen, die du getrennt einschalten kannst:
| Einstellung | Umgebungsvariable | Was sie zeigt |
|---|---|---|
| Core-Log-Level | TF_LOG_CORE |
Terraforms eigenes Log: Graph-Aufbau, Orchestrierung von plan und apply |
| Provider-Log-Level | TF_LOG_PROVIDER |
Das Log der Provider-Plugins (zum Beispiel azurerm), einschließlich der Requests und Responses, die sie machen |
Die Werte sind TRACE, DEBUG, INFO, WARN und ERROR. Ein pipeline-Parameter mit dem Wert DEFAULT lässt die
Variable ungesetzt, sodass sich das Logging wie gewohnt verhält.
Beginne mit dem Core-Log auf DEBUG: Meist reicht es, um zu sehen, was Terraform tut. Verwende das Provider-Log nur kurz
und nur für ein bestimmtes Problem.
Provider-Logs können Secrets enthalten
TF_LOG_PROVIDER auf DEBUG oder TRACE kann unmaskierte Secrets aus den Request- und Response-Payloads der Provider ausgeben. Stelle
es wieder auf DEFAULT, sobald du hast, was du brauchst. Behandle die Logs dieses Laufs als sensibel: Beschränke den Zugriff und
lösche sie, wenn sie nicht mehr gebraucht werden.
Azure DevOps¶
Die älteren Environment-pipelines (pipelines/environment_canary.yaml und environment_prod.yaml) stellen zwei Lauf-Parameter bereit,
terraformLogCore und terraformLogProvider (Default DEFAULT):
- Öffne die pipeline und wähle Run pipeline.
- Setze in den Parametern Terraform core log level oder Terraform provider log level.
- Starte sie. Die plan- und apply-Jobs setzen
TF_LOG_COREundTF_LOG_PROVIDERfür die Dauer des Laufs.
GitHub Actions¶
Die wiederverwendbaren Workflows environment_canary.yml und environment_prod.yml akzeptieren dieselben zwei Inputs. Übergib sie vom
aufrufenden Workflow:
jobs:
deploy:
uses: <organisation>/<code repository>/.github/workflows/environment_canary.yml@<version>
with:
environment: canary
regions: '["weu"]'
deployList: ${{ inputs.deployList }}
defaultRunnerGroup: <runner group>
terraformLogCore: DEBUG
terraformLogProvider: DEFAULT
Prüfe deine Entry-pipeline
Diese Parameter sind für die Environment-pipelines des Code-Repositorys dokumentiert. Öffne das Template, das deine Entry-pipeline
(hub, spoke) aufruft, und suche nach terraformLogCore und terraformLogProvider. Wenn sie dort nicht sind, frage
den Owner des Code-Repositorys, wie du Terraform-Logging für deine Version aktivierst.
Das Logging prüfen¶
Im Job-Log Terraform Plan oder Terraform Apply (Azure DevOps) oder in der Step-Ausgabe (GitHub) erscheinen Terraform-Logzeilen mit dem
Level in Klammern, etwa [DEBUG], neben der normalen Ausgabe.
Wenn keine zusätzliche Ausgabe erscheint, sind beide Parameter noch DEFAULT, oder der Wert ist keines der obigen Level. Starte erneut mit
einem expliziten Level.
Defekte Agent-Konnektivität nach einem destroy wiederherstellen¶
Das Problem¶
Wenn der connectivity-layer zerstört wird, wird die virtual hub connection zwischen dem virtuellen Netzwerk der Agents und dem hub
entfernt. Wenn die Verbindung internet_security_enabled = true hat, läuft der gesamte Internet-Traffic der Agents über die hub-
Firewall, und diese Route verschwindet mit der Verbindung. Die Agents verlieren dann ihren Weg zu Azure DevOps und melden keine
Job-Ausgabe mehr, sodass der Lauf, der den destroy ausgeführt hat, zu hängen scheint.
Vorbeugen¶
Setze internet_security_enabled = false auf jeder hub connection, deren Netzwerk pipeline-Agents hostet. Die Agents erreichen dann
Azure DevOps direkt über das Internet, unabhängig vom hub. In
environments/<env>/<region>/connectivity.auto.tfvars:
virtual_hub_connections = {
<connection name> = {
internet_security_enabled = false # agents use direct internet, not the hub firewall
remote_virtual_network_id = "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/virtualNetworks/<agents vnet>"
routings = null
virtual_hub_id = null
}
}
Siehe auch die Einstellung für spokes in der Spoke-JSON-Referenz (InternetSecurityEnabled).
Die Agents der Plattform selbst laufen im Netzwerk der Job runners, siehe Provisioning.
Ohne Terraform apply wiederherstellen¶
Wenn die Konnektivität bereits defekt ist, ändere die Verbindung direkt über die Azure REST API. Die Option
az network vhub connection update --internet-security wird in älteren Azure-CLI-Versionen nicht unterstützt, und der
Resource Provider akzeptiert kein PATCH auf hub connections. Lies die Verbindung, ändere sie und schreibe sie zurück (GET und PUT).
-
Finde den virtual hub und seine resource group.
az network vhub list ` --subscription <connectivity-subscription-id> ` --query "[].{name:name, rg:resourceGroup}" ` -o table -
Prüfe, dass die Verbindung existiert.
az network vhub connection list ` --vhub-name <vhub-name> ` --resource-group <resource-group> ` --subscription <connectivity-subscription-id> ` --query "[].{name:name, internetSecurity:properties.enableInternetSecurity}" ` -o table -
Deaktiviere Internet Security mit GET und PUT.
$url = "https://management.azure.com/subscriptions/<connectivity-subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/virtualHubs/<vhub-name>/hubVirtualNetworkConnections/<connection-name>?api-version=2023-09-01" $conn = az rest --method get --url $url | ConvertFrom-Json $conn.properties.enableInternetSecurity = $false az rest --method put --url $url --body ($conn | ConvertTo-Json -Depth 20 -Compress) -
Warte, bis das Update abgeschlossen ist.
do { Start-Sleep -Seconds 10 $state = az rest --method get --url $url | ConvertFrom-Json Write-Host "$(Get-Date -Format 'HH:mm:ss') - provisioningState: $($state.properties.provisioningState)" } until ($state.properties.provisioningState -ne 'Updating') -
Übernimm den Fix in den Code. Setze
internet_security_enabled = falsein derconnectivity.auto.tfvarsder betroffenen Region, damit das nächste apply deine Änderung nicht rückgängig macht (Änderungs-Workflow). Eine Änderung in Azure ohne passende Änderung im Code ist Drift (Incident-Management).
Den Managed DevOps Pool mit den Smoke-Tests prüfen¶
Die eigenen Job runners der Plattform laufen auf einem Managed DevOps Pool (MDP) (Provisioning). Die Smoke-Tests prüfen, dass der Pool korrekt deployt ist und VMs starten und Agents bei Azure DevOps registrieren kann. Führe sie nach jedem infrastructure-Deployment aus und wenn Jobs auf Agents warten.
Was sie prüfen¶
| Bereich | Prüfungen |
|---|---|
| Azure Resource Manager | Der Pool existiert in der resource group. Sein Provisioning-Status ist Succeeded. Die maximale Concurrency liegt über 0. Die SKU ist gültig. Statusinformationen sind verfügbar (ein null-Status deutet auf Netzwerkprobleme) |
| Registrierung bei Azure DevOps | Der Pool ist in der Organisation registriert, hat den Typ automation (managed pool) und ist als hosted markiert |
| Images | Die erwarteten Images sind konfiguriert: Windows Server 2025 und 2022, Ubuntu 24.04 und 22.04 (jeweils als <image>/latest) |
| Agent-Konnektivität | Agents lassen sich über die Azure-DevOps-API abfragen, und keiner steckt im Zustand never connected (ein Zeichen für ein fehlgeschlagenes Bootstrap) |
| Netzwerk | Das Agent-Subnetz ist konfiguriert und referenziert. Das DevCenter-Projekt existiert und ist verknüpft. Das Organisationsprofil zeigt auf die richtige Azure-DevOps-Organisation. Parallelität ist konfiguriert |
Ausführen¶
Die Smoke-Tests laufen automatisch nach Invoke-XebiaInfrastructure -Action Apply, das die infrastructure-pipeline
aufruft. Um sie separat auszuführen, zum Beispiel bei der Fehlersuche, verwende den Dev Container
(Die Tests lokal ausführen):
# In the dev container, from the root of the code repository
Import-Module ./src/Xebia.Mcp/Xebia.Mcp.psd1 -Force
Initialize-XebiaDotEnv
$config = Resolve-XebiaMcpConfiguration -Path $env:MCP_CONFIG
Test-XebiaMcpSmoke -Config $config
Du musst mit az login angemeldet sein und Zugriff auf die subscription des Pools haben, plus die Berechtigung Agent Pools (Read &
manage) in Azure DevOps. Das Ergebnis wird auf der Konsole angezeigt und als NUnit-XML-Datei geschrieben
(artifacts/testresults-smoke.xml), die eine pipeline veröffentlichen kann.
Für ausführliche Ausgabe setze vor dem Aufruf $VerbosePreference = 'Continue'.
Häufige Fehler¶
| Symptom | Ursache | Lösung |
|---|---|---|
statuses: null oder resources: [] |
Die Firewall blockiert den CIDR des Agent-Subnetzes | Füge das Agent-Subnetz einer Firewall-IP-group mit Outbound-Allow-Regeln für Port 443 hinzu (und Port 80, wenn deine Agents einfaches HTTP brauchen). Prüfe ip_groups/ und firewall_rule_configuration/ der Region (Zugriff der Build-Agents) |
agentConnectedTime: null und receiveTime: null |
Das NAT Gateway ist aus, oder die Firewall blockiert den ausgehenden Traffic der Agents | Aktiviere das NAT Gateway auf dem Agent-Subnetz oder erlaube dem Agent-Subnetz auf der Firewall den Zugang zum Internet. Wenn das Netzwerk mit aktivierter Internet Security an den hub angebunden ist, läuft der gesamte Internet-Traffic über die Firewall, und das NAT Gateway wird umgangen |
| Agents starten, können aber Azure-Hostnamen nicht auflösen | Eine Catch-all-Weiterleitungsregel (.) im DNS Resolver schickt jede Anfrage an einen öffentlichen DNS-Server. Azure-interne Namen, die der Pool verwendet, lassen sich nur über Azure DNS (168.63.129.16) auflösen |
Entferne die Catch-all-Regel. Erstelle nur Weiterleitungsregeln pro Domain, nie eine Catch-all-Regel (DNS-Design) |
MDP quota preflight failed |
Nicht genug Quota für die SKU-Familie | Fordere beim Azure support mehr Quota für Microsoft.DevOpsInfrastructure an |
Weiter gehen¶
- Lies die Pool-Ressource direkt mit
az restgegenMicrosoft.DevOpsInfrastructure/pools/<pool>der resource group der Job runners (API-Version2024-10-19). - Liste die Agents mit der Azure-DevOps-REST-API auf: Hole die Pool-ID aus
_apis/distributedtask/pools?poolName=<pool>, lies dann_apis/distributedtask/pools/<id>/agents?includeCapabilities=true, mit einem Token für die Azure-DevOps-Ressource. - End-to-End-Test. Stelle eine kleine Test-pipeline in die Queue, die pro Image einen Job auf dem Pool ausführt. Jeder Job sollte innerhalb von 5 bis 10 Minuten einen Agent bekommen und abschließen, und der Agent sollte danach deallokiert werden.
Private Ressourcen aus einem Dev Container erreichen¶
Arbeit an spokes braucht oft Zugriff auf private Ressourcen (Key Vaults, Storage-Accounts) aus einem Entwicklungs-Container. Diese Anleitung verbindet einen Windows-Rechner mit WSL2 und Docker Desktop über Point-to-Site-VPN mit dem hub und korrigiert DNS im Container, damit private Namen aufgelöst werden.
Bevor du anfängst¶
- Ein Windows-Host mit WSL2 und Docker Desktop und lokale Admin-Rechte, um den Azure VPN Client zu installieren.
- Zugriff auf die subscription und resource group des Point-to-Site-VPN-Gateways und die Berechtigung, VPN-Client- Profile zu erzeugen.
- Das
Xebia.Mcp-Modul im Dev Container. - Ein Point-to-Site-VPN-Gateway im hub. Es ist optional, standardmäßig aus und wird mit einer Standardänderung eingerichtet (Point-to-Site-VPN aktivieren unten und Entwicklerzugriff).
1. Das Point-to-Site-Gateway prüfen¶
Öffne im Azure-Portal das Point-to-Site-VPN-Gateway in der connectivity resource group, dann Point-to-site configuration. Prüfe den Adresspool der Clients, die Authentifizierungsmethode (zum Beispiel Microsoft Entra ID oder Zertifikate) und den Tunneltyp. Wenn die Plattform-Automatisierung es konfiguriert hat, prüfe nur die Einstellungen.
2. Das VPN-Client-Profil herunterladen¶
Aus dem Portal: Wähle im Gateway Download VPN client und speichere die Zip-Datei. Oder aus dem Dev Container:
$profile = Invoke-XebiaAzureCli -ScriptBlock {
az network p2s-vpn-gateway vpn-client generate `
--subscription '<subscription-id>' `
--resource-group '<resource-group-name>' `
--name '<p2s-gateway-name>'
} -WhatIf:$false | ConvertFrom-Json
Invoke-WebRequest -Uri $profile.profileUrl -OutFile ./vpn-client-profile.zip
Expand-Archive -Path ./vpn-client-profile.zip -DestinationPath ./vpn-client-profile -Force
3. Den Azure VPN Client installieren und das Profil importieren¶
- Installiere den Azure VPN Client aus dem Microsoft Store oder über deine Software-Verteilung im Unternehmen.
- Starte ihn und wähle Import. Wähle die Zip-Datei oder navigiere zur entpackten
AzureVPN/VpnSettings.xml. - Wähle das importierte Profil und Connect. Melde dich an, wenn du gefragt wirst. Der Status muss Connected sein.
Schnelle Prüfungen unter Windows:
Resolve-DnsName '<private-resource-name>'
Test-NetConnection '<private-ip-or-fqdn>' -Port 443
Test-NetConnection bestätigt nur, dass TCP-Port 443 offen ist. Um zu bestätigen, dass der Endpoint das erwartete Service-
Zertifikat präsentiert, führe die TLS-Prüfung unter Die Verbindung prüfen aus.
4. WSL-Networking konfigurieren¶
Aktualisiere WSL aus Windows PowerShell mit wsl --update und prüfe wsl --version. Erstelle oder bearbeite %UserProfile%\.wslconfig:
[wsl2]
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true
Wende es an: Schließe alle WSL-Terminals, führe wsl --shutdown in Windows PowerShell aus, verbinde den Azure VPN Client neu und öffne dann WSL
und den Dev Container erneut.
5. Den Container auf den hub-DNS ausrichten¶
Wenn Namen im Container weiterhin zu öffentlichen Adressen aufgelöst werden, erzwinge vorübergehend den hub-DNS-Server:
Import-Module Xebia.Mcp -Force
Set-XebiaLocalDns -NameServer <hub DNS server IP>
Wenn du die Aufgabe beendest, stelle den ursprünglichen DNS wieder her:
Set-XebiaLocalDns -Restore
Set-XebiaLocalDns behält eine Backup-Datei von resolv.conf (/tmp/xebia-localdns-resolv.conf.bak). Ein erneuter Aufruf mit
-NameServer, solange das Backup existiert, wird absichtlich blockiert: Stelle zuerst wieder her. -Restore stellt die Datei wieder her und löscht das Backup.
Die Verbindung prüfen¶
Führe diese Befehle im Dev Container aus, nachdem das VPN verbunden ist. Ersetze den Vault-Namen und die private IP durch die der Ressource, die du testest.
# 1. The name resolves to the private endpoint address
[System.Net.Dns]::GetHostAddresses('<vault-name>.vault.azure.net') | Select-Object -ExpandProperty IPAddressToString
# 2. TCP port 443 is open
$tcpClient = [System.Net.Sockets.TcpClient]::new(); $tcpClient.Connect('<private-ip>', 443); "TCP OK"; $tcpClient.Dispose()
# 3. The endpoint presents the expected certificate
$tcpClient = [System.Net.Sockets.TcpClient]::new('<private-ip>', 443)
$callback = [System.Net.Security.RemoteCertificateValidationCallback] { param($sender, $certificate, $chain, $errors) $true }
$sslStream = [System.Net.Security.SslStream]::new($tcpClient.GetStream(), $false, $callback)
$sslStream.AuthenticateAsClient('<vault-name>.vault.azure.net')
$sslStream.RemoteCertificate.Subject
$sslStream.RemoteCertificate.Issuer
$sslStream.Dispose(); $tcpClient.Dispose()
# 4. A real call
az keyvault secret list --vault-name <vault-name> --maxresults 1 -o table
Erwartet: Der Name wird zur privaten IP aufgelöst, TCP OK wird ausgegeben, ein von Microsoft ausgestelltes Zertifikat für vault.azure.net wird
angezeigt, und der letzte Befehl schlägt nicht mit SSL: UNEXPECTED_EOF_WHILE_READING fehl. Ein leerer Vault liefert eine leere Ausgabe, die
den Netzwerk- und TLS-Pfad trotzdem belegt. Wenn die TLS-Prüfung mit einem EOF fehlschlägt oder kein Zertifikat zurückgibt, zeigt DNS auf eine private
IP, aber der Container erreicht den Private Endpoint nicht.
Probleme¶
| Symptom | Was zu tun ist |
|---|---|
| Das VPN ist verbunden, aber private Namen werden zu öffentlichen Adressen aufgelöst | Prüfe, dass das Windows-VPN verbunden ist. Prüfe, dass mirrored Networking nach wsl --shutdown aktiv ist. Führe im Container Set-XebiaLocalDns -NameServer <hub DNS server IP> aus |
Set-XebiaLocalDns meldet, dass das Backup bereits existiert |
Führe Set-XebiaLocalDns -Restore aus und setze dann den neuen Name Server |
| Keine Route vom Container zum privaten DNS-Server | Prüfe, dass die Routen des VPN-Profils den hub und die privaten DNS-Bereiche enthalten. Verbinde das Profil neu. Starte WSL neu und öffne den Container erneut |
| DNS löst zum Private Endpoint auf und TCP 443 ist offen, aber TLS schlägt mit EOF fehl | Siehe unten |
TLS schlägt mit EOF fehl, während TCP gelingt, sowohl von Windows als auch aus dem Container. Das ist nicht nur ein WSL-Problem: Die TCP- Verbindung wird geöffnet, aber der TLS-Handshake mit dem Azure-Service wird nicht abgeschlossen. Prüfe in dieser Reihenfolge:
- Die IP des Private Endpoints überschneidet sich nicht mit einem lokalen oder Firmennetzwerk. Zum Beispiel steht ein lokales Netzwerk
192.168.123.0/24im Konflikt mit einem Private-Endpoint-Bereich eines spokes darin. - Das VPN-Profil routet den gesamten Adressbereich des virtuellen Netzwerks des spokes, nicht nur den Bereich des DNS-Servers.
- DNS löst den Namen sowohl von Windows als auch aus dem Container zur IP des Private Endpoints auf.
- Die Private-Endpoint-Verbindung ist genehmigt und zeigt auf die erwartete Ressource.
- Wenn es weiterhin fehlschlägt, eskaliere an den Netzwerk-Owner mit dem DNS-Ergebnis, der Quell-IP unter Windows, dem Namen des VPN-Interfaces, der IP des Private Endpoints und dem TLS-EOF-Fehler.
Das Point-to-Site-VPN-Feature aktivieren¶
Die Plattform kann im hub ein Point-to-Site-VPN-Gateway erstellen. Das ist eine Standardänderung: Plattform-Features aktualisieren (Plattform-Features). Die Schritte für dieses Feature:
- Erstelle im Konfigurations-Repository einen branch. Ändere in
<env-folder>/<region>/connectivity.auto.tfvarsder Umgebung:- Setze
create_point_to_site_vpn_gateway = true. - Setze
point_to_site_vpn_gateway_connection_configuration: einenname, der deiner Namenskonvention folgt (das ältere Runbook verwendetvpnconf-<company>-connectivity-<env>-<region>-001), und einenvpn_client_address_poolmitaddress_prefixes(der CIDR für die VPN-Clients) undinternet_security_enabled(das ältere Runbook setzttrue). - Setze
entra_tenant_idauf die Tenant-ID der Organisation. - Setze
point_to_site_vpn_enterprise_app_idauf die Application-ID der Azure-VPN-Anwendung (siehe den Hinweis unten).
- Setze
- Prüfe die zugehörigen Variablen in
variables_point_to_site_vpn_gateway.tf(der DNS-Server des Gateways mussvirtual_network_dns_serversentsprechen, wie es ein Config-Test verlangt). - Führe
hubim ModusPlanfür die geänderte Umgebung und Region aus. Nur derconnectivity-layer sollte Änderungen zeigen. Wende auf canary an, dann auf prod, mit Genehmigung für prod. - Prüfe im Portal: Virtual WAN > Hubs > der hub der Region > Point-to-site configuration. Lade die Konfigurationsdatei herunter und teste die Verbindung mit dem Azure VPN Client.
- Merge den pull request.
Um das VPN für die Entwicklung zu nutzen, mache weiter mit Private Ressourcen aus einem Dev Container erreichen. Zu Forced Tunnelling und zum Design des Zugriffs pro workload siehe Entwicklerzugriff.
Die Application-ID des Azure VPN
Das ältere Runbook verwendet 41b23e61-6c1e-4545-b367-cd054e0ed4b4 für point_to_site_vpn_enterprise_app_id. Prüfe sie anhand der aktuellen
Dokumentation von Microsoft zu Azure VPN mit Entra-ID-Authentifizierung, bevor du sie verwendest, denn der Wert
hängt von der Cloud ab.