Lokalna rozwój funkcji Azure: naprawa częstych problemów technicznych
Dowiedz się, jak narzędzia podstawowe, środowiska wykonawcze języków oraz Azurite muszą być skoordynowane, i otrzymaj praktyczne rozwiązania dotyczące pliku local.settings.json, wyzwalaczy oraz błędów debugowania.
Koniec z walką z emulatorami, uszkodzonymi powiązaniami i tajemniczymi błędami — oto co naprawdę działa
Jeśli zwykły polecenie func start kiedykolwiek pokazało ci ekran wypełniony czerwonym tekstem bez uprzedzenia, nie jesteś jedyną osobą w takiej sytuacji. Azure Functions funkcjonuje doskonale po rozwiązaniu go w chmurze, ale sprawienie, by działał płynnie na twoim własnym laptopie, powoduje, że wielu programistów marnuje całe popołudnie bez żadnego powodu.
To przewodnik pomija wypolerowaną, marketingową wersję pojęcia „rozwój lokalny” i zamiast tego analizuje to, co naprawdę idzie nie tak, przyczyny tych problemów oraz praktyczne rozwiązania, czerpane z trudności, z którymi programiści regularnie się spotykają.
1. Dlaczego rozwój lokalnych Azure Functions wydaje się trudniejszy, niż powinien być
Zapewnianie działania Azure Functions na własnym komputerze to nie tylko wykonywanie kodu. W rzeczywistości tworzysz lokalnie cały środowisko chmurowe: host Functions, powiązania wyzwalaczy, kolejki przechowywania, a czasami także mechanizmy autoryzacji, przy czym w ogóle nie musisz korzystać z samego Azure. Aby to funkcjonowało, na każdym etapie konieczne jest zachowanie synchronizacji trzech odrębnych elementów:
- Core Tools CLI od Microsoftu, który pełni rolę zamiennika środowiska Functions dostarczanego normalnie przez sam Azure
- Język programowania i SDK, w którym napisane są twoje funkcje – może to być Node.js, Python, .NET, Java lub PowerShell
- Azurite, mały emulator, który symuluje Azure Storage, dzięki czemu kolejki, pliki i tabele działają bez konieczności posiadania rzeczywistego konta w chmurze
Jeśli którykolwiek z tych trzech elementów to nieprawidłowa wersja, źle skonfigurowany lub po prostu wyłączony, napotkasz typowe problemy: funkcje, które odmawiają działania, komunikaty „konto przechowywania nie znaleziono” lub serwer, który cicho się wyłącza. Gdy zrozumiesz, jak te trzy elementy są ze sobą powiązane, większość frustracji zniknie.
2. Co naprawdę musisz zainstalować
Zanim dotkniesz jakiegokolwiek kodu funkcji, upewnij się, że masz przygotowane następujące elementy:
- Azure Functions Core Tools – narzędzie wiersza poleceń, które uruchamia serwer Functions na twoim komputerze
npm install -g azure-functions-core-tools@4 --unsafe-perm true
- Język w czasie wykonywania zgodny z Twoją docelową wersją Azure (np. Node.js 18/20, Python 3.9–3.11 lub .NET 8)
- Azurite – emulator, który zastępuje lokalnie usługę Azure Storage
npm install -g azurite
- VS Code w połączeniu z rozszerzeniem Azure Functions — nie jest to obowiązkowe, ale znacznie ułatwia debugowanie oraz tworzenie szkieletu projektu
Szybka weryfikacja, którą warto przeprowadzić przed dalszym postępem:
func --version
node --version # or python --version / dotnet --version
Różnica wersji pomiędzy Core Tools a środowiskiem wykonawczym Twojego języka to jeden z najsubtelniejszych i najczęstszych powodów, dla których coś działa poprawnie na jednym komputerze, a zawodzi na innym.
3. Konfiguracja pierwszej lokalnej aplikacji funkcji
Użyj CLI do stworzenia zupełnie nowego projektu:
func init MyFunctionApp --worker-runtime node
cd MyFunctionApp
func new --name HttpTriggerExample --template "HTTP trigger"
Uruchomienie tego skutkuje strukturą folderów zawierającą plik host.json, plik local.settings.json oraz katalog z kodem wyzwalacza. Plik host.json zarządza ustawieniami ogólnymi dla hosta, takimi jak zachowanie logowania, pakiety rozszerzeń i limity czasowe. Plik local.settings.json jest przeznaczony wyłącznie dla twojego komputera i powoduje na początkowym uruchomieniu tyle zamieszania, że wymaga osobnego wyjaśnienia.
4. Plik local.settings.json — co robi i dlaczego wprowadza w błąd
Ten plik przechowuje lokalne zmienne środowiskowe oraz łańcuchy połączeń. Nigdy nie jest wysyłany do Azure; jego jedynym celem jest konfiguracja wyłącznie na poziomie lokalnym.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node"
}
}
Dwa często popełniane błędy tłumaczą większość skarg typu „host nawet się nie uruchamia”:
- Zapomnienie o ustawieniu AzureWebJobsStorage. Prawie każda kategoria wyzwalaczy — Timer, Queue, Blob — wymaga połączenia z magazynem, nawet podczas uruchamiania lokalnego. Użycie parametru UseDevelopmentStorage=true skierowuje host na Azurite zamiast na rzeczywisty konto Azure Storage.
- Niewłaściwe ustawienie FUNCTIONS_WORKER_RUNTIME. Gdy nie odpowiada on językowi, w którym faktycznie pracujesz (node, python, dotnet, java, powershell), host po prostu nie załaduje twoich funkcji, co zwykle skutkuje niejasnym błędem zamiast wyraźnego komunikatu o niezgodności języka.
5. Azurite: Twój lokalny emulator magazynu (i dlaczego nie możesz go pominąć)
Azurite zastępuje Azure Storage dla aplikacji działających lokalnie, emulując kolejki, obiekty typu blob oraz tabele bezpośrednio na Twoim komputerze. Pomijanie tego kroku jest główną przyczyną błędów StorageException lub odrzucanych połączeń, gdy tylko pojawi się wyzwalacz typu kolejka lub blob.
Zainstaluj go w dedykowanym oknie terminala przed uruchomieniem aplikacji funkcji:
azurite --silent --location ./azurite-data --debug ./azurite-data/debug.log
Jeśli wolisz pracować w VS Code, rozszerzenie Azurite umożliwia uruchomienie emulatora za pomocą pojedynczego wpisu w paletce poleceń, bez konieczności korzystania z osobnego terminala. Niezależnie od wybranej metody, upewnij się, że emulator będzie działał przez całą sesję – bardzo łatwo zapomnieć, że nie jest aktywny, co może skutkować stratą dziesięciu minut na rozwiązywanie problemu z komunikatem „połączenie nieudane”, który w rzeczywistości oznacza jedynie, że emulator nigdy nie został uruchomiony.
6. Uruchamianie i testowanie funkcji wyzwalanych przez HTTP
Gdy Azurite będzie gotowe, uruchom swoje aplikacje funkcyjne:
func start
Twój terminal wyświetli lokalną adres URL każdej funkcji, mniej więcej w takim stylu:
Http Functions:
HttpTriggerExample: [GET,POST] http://localhost:7071/api/HttpTriggerExample
Możesz do niej uzyskać dostęp za pomocą curl, Postman lub przeglądarki, jeśli jest to żądanie GET:
curl "http://localhost:7071/api/HttpTriggerExample?name=Dev"
Jeśli zamiast odpowiedzi otrzymasz ciszę, sprawdź, czy nie ma kolizji portów – pozostały proces func start lub zupełnie inna instancja mogą już zajmować port 7071. Zakończenie błądzących procesów hostujących funkcje (poszukaj func w Menedżerze zadań lub uruchom pkill -f func na macOS/Linux) zazwyczaj natychmiast rozwiązuje ten problem.
7. Testowanie lokalnych wyzwalaczy nie-HTTP (Timer, Queue, Blob, Service Bus)
Wyzwalacze HTTP to prosty przypadek. Pozostałe wymagają nieco większej przygotowania:
- Wyzwalacze timera uruchamiają się automatycznie zgodnie z ustalonym harmonogramem CRON zaraz po uruchomieniu hosta, bez konieczności dodawania czegokolwiek dodatkowo. Aby przetestować je wcześniej, możesz tymczasowo dodać do definicji wyzwalacza "RunOnStartup": true, aby ten uruchomił się natychmiast.
- Wyzwalacze z kolejki wymagają rzeczywistej wiadomości czekającej w kolejce obsługiwaniej przez Azurite. Możesz dodać wiadomość testową za pośrednictwem Azure Storage Explorer, który komunikuje się z Azurite tak samo jak z prawdziwym kontem przechowywania, lub za pomocą rozszerzenia storage w Azure CLI skierowanego do Twojej lokalnej ciągu połączeń.
local.settings.json.To jeden z prawdziwych braków w rozwoju funkcji lokalnych: niektóre typy wyzwalaczy po prostu nie mogą być w pełni odtworzone lokalnie, a traktowanie ich tak, jakby można to było zrobić, tylko marnuje twój czas.
8. Debugowanie w VS Code
Tutaj lokalna konfiguracja naprawdę zaczyna się sprawdzać. Po zainstalowaniu rozszerzenia Azure Functions:
- Otwórz folder swojego projektu w VS Code.
- Umieść punkty przerwania tam, gdzie są potrzebne, wewnątrz kodu wyzwalacza.
- Naciśnij F5 — VS Code samodzielnie buduje projekt, uruchamia Azurite, jeśli jest do tego skonfigurowany, startuje host Functions oraz podłącza debuggera, wszystko bez konieczności wykonywania ręcznych kroków.
Autogenerowane pliki .vscode/launch.json i tasks.json koordynują to wszystko w tle. Jeśli punkty przerwania nie zatrzymują wykonywania kodu, sprawdź, czy ustawienie preLaunchTask w pliku launch.json rzeczywiście ponownie nie buduje twojego kodu przed uruchomieniem hosta — przestarzała wersja budowanego projektu jest subtelnym, ale częstym powodem, dla którego punkty przerwania wydają się być ignorowane.
9. Powszechne błędy i sposoby ich naprawy
To konkretna linijka powoduje większe zamieszanie u programistów niż jakikolwiek rzeczywisty defekt w samym środowisku wykonywania Functions. Z powodów bezpieczeństwa plik local.settings.json jest celowo pomijany w pakiecie instalacyjnym ze względu na bezpieczeństwo, co oznacza, że żadne tajemnice ani wartości konfiguracyjne przechowywane tam nie trafią automatycznie razem z aplikacją do Azure — musisz je dodać osobno, albo przez portal Azure, albo za pomocą narzędzi CLI/pipeline.
10. Uruchamianie Functions lokalnie z użyciem Dockera
Jeśli twój zespół chce, aby środowiska lokalne i produkcyjne były identyczne — lub jeśli musisz zweryfikować niestandardowy kontener Linuxa — Azure Functions oferuje również rozwiązanie oparte na Dockerze:
func init MyFunctionApp --worker-runtime node --docker
cd MyFunctionApp
docker build -t my-function-app .
docker run -p 7071:80 -it my-function-app
Taki podejście wiąże się z większym obciążeniem w porównaniu z prostym func start, ale eliminuje całą klasę problemów typu „działa na moim komputerze”, szczególnie w zespołach, które używają spersonalizowanych kontenerów lub wymagają ścisłej spójności na poziomie systemu operacyjnego z tym, co działa w produkcji.
11. Prawidłowe zarządzanie sekretami i zmiennymi środowiskowymi
Nie dodawaj pliku local.settings.json do kontroli wersji. Jest on przeznaczony do przechowywania rzeczywistych ciągów połączeń podczas rozwoju, a projekty oparte na szablonach domyślnie wykluczają go z git – sprawdź dokładnie swój plik .gitignore, aby mieć pewność. Pracując w zespole:
- Dziel się wersją wyczyśczoną, na przykład
local.settings.json.example, wypełnioną wartościami tymczasowymi zamiast rzeczywistych sekretów.
12. Najlepsze praktyki dla sprawnego lokalnego cyklu rozwoju
- Zaczynaj uruchamianie Azurite przed uruchomieniem hosta Functions — kolejność ma znaczenie, ponieważ niektóre wyzwalacze sprawdzają zasoby przechowywania zaraz po uruchomieniu.
- Określ dokładnie wersję Core Tools używaną przez twoją zespół, czy to w dokumentacji, czy w skrypcie konfiguracyjnym. Różnice wersji pomiędzy maszynami stanowią cichy, ale realny hamulec produktywności.
- Uruchamiaj
func start --verboseza każdym razem, gdy próbujesz rozwiązać problem z uruchamianiem — domyślny poziom logowania często ukrywa prawdziwą przyczynę. - Zrestartuj host za każdym razem, gdy edytujesz plik
host.jsonlublocal.settings.json; żaden z tych plików nie jest aktualizowany podczas szybkiego ładowania. - Zachowaj dostępny zasób niskiego poziomu w Azure dla typów wyzwalaczy takich jak Service Bus lub Event Grid, które nie mogą być w pełni zreplikowane w lokalnym emulatorze.
Ostateczne uwagi
Rozwój lokalny dla Azure Functions nie jest zasadniczo uszkodzony — po prostu składa się z kilku elementów, które muszą być ze sobą skoordynowane, a większość przewodników pomija właśnie te części, które powodują prawdziwe trudności: poprawne emulowanie pamięci przechowywania, niezgodności w środowisku wykonywania zadań oraz granice tego, co lokalne ustawienia mogą symulować, a czego nie. Gdy te trzy kwestie staną się jasne, polecenie func start przestanie wydawać się ryzykowne i stanie się zwykłym, rutynowym poleceniem.
Jeśli istnieje jeden nawyk, który warto przyjąć z tego wszystkiego, to jest nim następujący: zawsze sprawdzaj, czy Azurite rzeczywiście działa, zanim zaczniesz rozwiązywać jakiekolwiek inne problemy. Ta jedna zaniedbanie potajemnie marnuje więcej czasu niż jakikolwiek prawdziwy błąd w kodzie funkcji.
Literatura pokrewna
- Node.js Command Reference for Local Development and Production Servers — Przewodnik poleceń ułatwiający nawigację, obejmujący zarządzanie wersjami Node.js, menedżery pakietów, konfigurację środowiska, debugowanie, PM2 oraz wdrażanie systemów Linux bez przerwy w działaniu.