Lokale Entwicklung von Azure Functions: Behebung der häufigen Fehlerpunkte
Erfahren Sie, wie Core Tools, Sprachlaufzeiten und Azurite miteinander übereinstimmen müssen, und erhalten Sie praktische Lösungen für Probleme mit local.settings.json, Auslösern sowie Fehlern beim Debuggen.
Hören Sie auf, sich mit Emulatoren, defekten Bindings und rätselhaften Fehlern herumzuschlagen – hier ist, was wirklich funktioniert
Falls ein einfacher func start-Befehl jemals ohne Vorwarnung einen Bildschirm voller roter Texte angezeigt hat, sind Sie keineswegs der Einzige. Azure Functions funktioniert hervorragend, sobald es in die Cloud bereitgestellt wird, doch beim problemlosen Laufen auf dem eigenen Laptop verbringen viele Entwickler versehentlich den ganzen Nachmittag damit.
Dieser Leitfaden verzichtet auf die glatt polierte Marketingversion von „lokaler Entwicklung“ und geht stattdessen darauf ein, was tatsächlich schiefgeht, die dahinterliegenden Gründe sowie praktische Lösungen – basierend auf den häufig auftretenden Problemen, mit denen Entwickler konfrontiert sind.
1. Warum die lokale Entwicklung von Azure Functions schwieriger ist, als es sein sollte
Die Ausführung von Azure Functions auf dem eigenen Rechner bedeutet nicht einfach nur die Ausführung von Code. Im Grunde erstellt man lokal eine komplette Cloud-Laufzeitumgebung: den Functions-Host, Trigger-Bindungen, Speicherkolonnen sowie gelegentlich auch Mechanismen zur Authentifizierung – und das ohne jemals direkt auf Azure zuzugreifen. Dafür sind bei jedem Schritt drei separate Komponenten erforderlich, die miteinander übereinstimmen müssen:
- Die Core Tools CLI von Microsoft, die als Ersatz für die in der Cloud bereitgestellte Functions-Laufzeit dient
- Jede Programmiersprache und SDK, in der die Funktionen geschrieben sind – sei es Node.js, Python, .NET, Java oder PowerShell
- Azurite, ein kleiner Emulator, der Azure Storage nachahmt, sodass Kolonnen, Blob-Dateien und Tabellen auch ohne echtes Cloud-Konto funktionieren
Falls eine dieser drei Komponenten die falsche Version ist, schlecht konfiguriert ist oder einfach nicht aktiviert ist, treten die üblichen Probleme auf: Funktionen, die nicht funktionieren, Meldungen wie „Storage-Konto nicht gefunden“ oder ein Host, der stumm abgeschaltet wird. Sobald Sie verstehen, wie diese drei Komponenten voneinander abhängen, verschwindet der größte Teil der Frustration.
2. Was Sie tatsächlich installieren müssen
Bevor Sie den Code einer Funktion anfassen, stellen Sie sicher, dass Sie Folgendes bereit haben:
- Azure Functions Core Tools, das Kommandozeilenwerkzeug, mit dem der Functions-Host auf Ihrem Computer ausgeführt wird
npm install -g azure-functions-core-tools@4 --unsafe-perm true
- Ein Sprachlaufzeitumfeld, das zu Ihrer gewünschten Azure-Version passt (zum Beispiel Node.js 18/20, Python 3.9–3.11 oder .NET 8)
- Azurite, der Emulator, der lokal als Ersatz für Azure Storage dient
npm install -g azurite
- VS Code in Kombination mit der Azure Functions-Erweiterung – nicht zwingend erforderlich, aber sie macht das Debuggen und das Aufbauen von Projekten erheblich einfacher
Eine schnelle Überprüfung, die es lohnt, vor dem Weitermachen durchzuführen:
func --version
node --version # or python --version / dotnet --version
Ein Versionsunterschied zwischen den Core Tools und dem Laufzeitumfeld Ihrer Programmiersprache ist einer der heimtückischsten und häufigsten Gründe dafür, dass etwas an einem Rechner einwandfrei funktioniert und an einem anderen fehlschlägt.
3. Einrichtung Ihrer ersten lokalen Function App
Nutzen Sie die CLI, um ein völlig neues Projekt aufzubauen:
func init MyFunctionApp --worker-runtime node
cd MyFunctionApp
func new --name HttpTriggerExample --template "HTTP trigger"
Durch Ausführung erhalten Sie eine Ordnerstruktur mit einer host.json, einer local.settings.json sowie einem Verzeichnis, das den Code Ihres Triggers enthält. host.json kümmert sich um einrichtungsbezogene Einstellungen für den gesamten Host, wie beispielsweise das Protokollierungsverhalten, Erweiterungspakete und Zeitlimits. local.settings.json ist eine Datei, die ausschließlich für Ihren Rechner bestimmt ist; sie verursacht beim ersten Ausführen so viel Verwirrung, dass eine eigene Erklärung angebracht ist.
4. Die Datei local.settings.json – Was sie tut und warum sie zu Verwirrung führt
Diese Datei speichert Ihre lokalen Umgebungsvariablen und Verbindungsstrings. Sie wird niemals an Azure gesendet; ihr ganzes Ziel besteht in der Konfiguration ausschließlich für den lokalen Betrieb.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node"
}
}
Zwei häufige Fehler erklären den Großteil der Beschwerden „Der Host startet überhaupt nicht“:
- Vergessen, AzureWebJobsStorage einzustellen. Fast jede Auslösekategorie – Timer, Queue, Blob – benötigt eine Speicherverbindung, selbst bei lokalen Ausführungen. Die Verwendung von UseDevelopmentStorage=true weist den Host auf Azurite statt auf ein aktives Azure Storage-Konto hin.
- Falsche Einstellung von FUNCTIONS_WORKER_RUNTIME. Wenn dieser Wert nicht mit der tatsächlich verwendeten Sprache übereinstimmt (node, python, dotnet, java, powershell), lädt der Host Ihre Funktionen einfach nicht, wodurch in der Regel nur eine vage Fehlermeldung angezeigt wird, anstatt klar mitgeteilt zu werden, dass die Laufzeit nicht passt.
5. Azurite: Ihr lokaler Speicheralterator (und warum Sie ihn nicht überspringen können)
Azurite ersetzt Azure Storage für alle lokal ausgeführten Anwendungen und emuliert Warteschlangen, Blob-Daten und Tabellen direkt auf Ihrem Rechner. Das Überspringen dieses Schritts ist die häufigste Ursache für StorageException-Fehler oder abgelehnte Verbindungen, sobald ein Warteschlangen- oder Blob-Trigger zum Einsatz kommt.
Führen Sie es in einem dedizierten Terminalfenster aus, bevor Sie Ihre Funktionsanwendung starten:
azurite --silent --location ./azurite-data --debug ./azurite-data/debug.log
Falls Sie lieber in VS Code arbeiten möchten, ermöglicht die Azurite-Erweiterung es Ihnen, den Emulator über einen einzigen Eintrag in der Befehlspalette zu starten – ohne dass ein separates Terminal erforderlich ist. Welchen Weg Sie auch wählen, lassen Sie ihn während der gesamten Sitzung laufen; es ist äußerst leicht, zu vergessen, dass er nicht aktiv ist, und dadurch zehn Minuten mit der Behebung einer „Verbindungsfehler“-Meldung zu verschwenden, die eigentlich nur bedeutet, dass der Emulator nie gestartet wurde.
6. Ausführen und Testen von über HTTP ausgelösten Funktionen
Sobald Azurite bereit ist, starten Sie Ihre Function App:
func start
Ihre Terminalanzeige zeigt die lokale URL jeder Funktion an, ähnlich wie folgt:
Http Functions:
HttpTriggerExample: [GET,POST] http://localhost:7071/api/HttpTriggerExample
Falls es sich um eine GET-Anfrage handelt, können Sie diese mit curl, Postman oder einem Browser aufrufen:
curl "http://localhost:7071/api/HttpTriggerExample?name=Dev"
Falls statt einer Antwort Stille herrscht, prüfen Sie auf eine Port-Kollision – ein verbleibender func start-Prozess oder eine andere Instanz könnte bereits Port 7071 belegen. Das Beenden solcher ungebetener Functions-Host-Prozesse (suchen Sie nach func im Task Manager oder führen Sie auf macOS/Linux pkill -f func aus) löst das Problem in der Regel sofort.
7. Lokales Testen von Nicht-HTTP-Triggern (Timer, Queue, Blob, Service Bus)
HTTP-Trigger sind der einfache Fall. Für die anderen ist etwas mehr Vorbereitung nötig:
- Timer-Auslöser starten automatisch gemäß ihrem CRON-Plan sobald der Host gestartet wird, ohne weitere Voraussetzungen. Um früher zu testen, können Sie vorübergehend "RunOnStartup": true zur Definition des Auslösers hinzufügen, damit er sofort ausgelöst wird.
- Warteschlangen-Auslöser benötigen eine tatsächliche Nachricht, die in einer von Azurite unterstützten Warteschlange wartet. Sie können eine Testnachricht über den Azure Storage Explorer hinzufügen, der mit Azurite genauso kommuniziert wie mit einem echten Speicherkonto, oder über die Storage-Erweiterung der Azure CLI unter Verwendung Ihrer lokalen Verbindungszeichenkette.
local.settings.json zu verwenden.Dies ist einer der offenen Mängel bei der lokalen Entwicklung von Functions: Einige Triggerarten lassen sich einfach nicht vollständig lokal nachgebildet werden, und sie als solche zu behandeln, verschwendet nur Zeit.
8. Debugging in VS Code
Hier beginnt die lokale Einrichtung, wirklich ihren Wert zu zeigen. Sobald die Azure Functions-Erweiterung installiert ist:
- Öffnen Sie den Ordner Ihres Projekts in VS Code.
- Platzieren Sie Breakpoints an den Stellen, an denen Sie sie im Trigger-Code benötigen.
- Drücken Sie F5 – VS Code kümmert sich automatisch um das Kompilieren des Projekts, den Start von Azurite, sofern dies eingerichtet ist, den Start des Functions-Hosts sowie das Anhängen des Debuggers, und zwar ohne manuelle Schritte.
Die automatisch generierten Dateien .vscode/launch.json und tasks.json koordinieren all das im Hintergrund. Wenn Breakpoints die Ausführung nicht stoppen, überprüfen Sie, ob die Einstellung preLaunchTask in launch.json tatsächlich Ihren Code vor dem Start des Hosts neu kompiliert – ein veralteter Build ist ein subtiler, aber häufiger Grund dafür, dass Breakpoints ignoriert zu werden scheinen.
9. Häufige Fehler und wie man sie tatsächlich behebt
Jene bestimmte Zeile verursacht bei Entwicklern mehr Verwirrung als jedes tatsächliche Defekt im Functions-Laufzeitumfeld selbst. Aus Sicherheitsgründen wird local.settings.json absichtlich aus Ihrem Bereitstellungs-Paket weggelassen, was bedeutet, dass alle dort gespeicherten Geheimnisse oder Konfigurationswerte nicht automatisch mit Ihrer Anwendung nach Azure übertragen werden – Sie müssen sie separat hinzufügen, entweder über das Azure-Portal oder mithilfe von CLI-/Pipeline-Werkzeugen.
10. Ausführung von Functions lokal mit Docker
Falls Ihr Team möchte, dass lokale und Produktivumgebungen exakt übereinstimmen – oder Sie einen benutzerdefinierten Linux-Container validieren müssen – bietet Azure Functions ebenfalls einen auf Docker basierenden Ansatz:
func init MyFunctionApp --worker-runtime node --docker
cd MyFunctionApp
docker build -t my-function-app .
docker run -p 7071:80 -it my-function-app
Der Ansatz verursacht im Vergleich zu einer einfachen func start-Funktion mehr Overhead, beseitigt aber eine ganze Reihe von Problemen vom Typ „Es funktioniert bei mir“, insbesondere für Teams, die Anwendungen in benannten Containern bereitstellen oder eine strenge Übereinstimmung auf Betriebssystemebene mit dem, was in der Produktion läuft, benötigen.
11. Geheime Informationen und Umgebungsvariablen auf die richtige Weise verwalten
Commitpen Sie local.settings.json nicht in den Quellcode-Controllern. Es dient dazu, während der Entwicklung echte Verbindungsstrings zu speichern, und standardmäßig werden in vorgefertigten Projekten solche Dateien von Git ausgeschlossen – überprüfen Sie daher unbedingt Ihren .gitignore, um sicherzugehen. Bei der Zusammenarbeit im Team:
- Teilen Sie eine bereinigte Version, wie zum Beispiel
local.settings.json.example, die mit Platzhalterwerten statt echten Geheiminformationen gefüllt ist.
12. Best Practices für einen reibungslosen lokalen Entwicklungszyklus
- Starten Sie Azurite vor dem Start des Functions-Hosts – die Reihenfolge ist wichtig, da einige Auslöser bereits beim Start nach Speicherinhalten suchen.
- Legen Sie die von Ihrem Team verwendete Version der Core Tools entweder in Ihren Dokumenten oder in einem Setup-Skript fest. Versionenunterschiede zwischen Maschinen sind zwar unauffällig, beeinträchtigen aber die Produktivität erheblich.
- Führen Sie immer
func start --verboseaus, wenn Sie ein Startproblem verfolgen – das Standard-Logging-Niveau verschleiert oft die eigentliche Ursache. - Starten Sie den Host jedes Mal neu, wenn Sie
host.jsonoderlocal.settings.jsonändern; weder Datei wird durch Hot Reload erkannt. - Halten Sie eine Ressource niedriger Ebene in Azure für Auslösetypen wie Service Bus oder Event Grid bereit, da diese nicht vollständig in einem lokalen Emulator nachgebildet werden können.
Zusammenfassung
Die lokale Entwicklung für Azure Functions ist grundsätzlich nicht fehlerhaft – sie setzt sich einfach aus mehreren Komponenten zusammen, die alle im Einklang bleiben müssen. Die meisten Anleitungen überspringen genau die Teile, die echte Probleme verursachen: die korrekte Emulation von Speicher, Abweichungen im Worker-Runtime sowie die Grenzen dessen, was Ihre lokale Einrichtung simulieren kann und was nicht. Sobald diese drei Aspekte klar sind, wirkt func start nicht mehr wie ein Glücksspiel, sondern ist nur noch ein weiterer gewöhnlicher Befehl.
Falls es eine einzige Gewohnheit gibt, die man aus all dem mitnehmen sollte, dann ist es folgende: Überprüfen Sie stets, ob Azurite tatsächlich läuft, bevor Sie mit der Behebung anderer Probleme beginnen. Diese eine Nachlässigkeit kostet still und heimlich mehr Zeit als jedes echte Fehler im Funktionscode.
Verwandte Artikel
- Node.js Command Reference for Local Development and Production Servers – Eine übersichtliche Kommandoreferenz, die Versionenverwaltung in Node.js, Paketmanager, Umgebungs-Einrichtung, Debugging, PM2 sowie Linux-Deployment ohne Ausfallzeiten behandelt.