Jak rozgrzać aplikację w chmurze Azure

Jak rozgrzać aplikację w chmurze Azure

Piotr Stapp 5 czerwca 2017

W tym artykule opiszę proces wdrażania aplikacji w środowisku Azure i użycie narzędzi deweloperskich dostarczonych przez Microsoft. Temat jest nieoczywisty, dlatego mam nadzieję, że rozwieję wszystkie wątpliwości.

Ten artykuł bazuje na instalacji Umbraco, ale biorąc pod uwagę moje doświadczenia powinien pasować do większości projektów ASP.NET. Jeżeli jednak mielibyście jakieś problemy to dajcie znać!

 

Utworzenie definicji build

Po pierwsze: potrzebujemy definicji buildu (bladego pojęcia nie mam, jak to powinno brzmieć po polsku). W najbardziej typowym przypadku odpowiedni będzie template ASP.NET (Preview).

Jeżeli zdarzy się taki nieszczęśliwy przypadek i jednak nie będzie działał, to polecam poniższą komendę uruchamianą w katalogu projektu:

 

msbuild.exe YourProject.sln /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="c:\tmp\"

 

Z mojego doświadczenia wynika że najczęściej spotykanymi błędami są:

  • brak dodanych plikow do csproj (często powiązany z plikiem gitignore)
  • złe referencje NuGet (na przykład inny numer w csproj a inny w packages.config)

Chwila cierpliwości, złość, trzymanie kciuków... i jest upragniony sukces!

 

Niech stanie się instalacja

Powino być łatwo prawda? Kilka kroków i już.

Zacznijmy od definicji (release definition). W większości przypadków naszym wyborem będzie zwykły template Azure App Service Deployment. Potem będziemy dodawać dodatkowe kroki (czyli tasks):

 

 

W następnym kroku wizard możecie zaznaczyć opcję Continuous deployment, dzięki której każdy build naszej aplikacji będzie powodował jej automatyczną próbę instalacji. Uważam, że dla środowiska typu dev powyższa opcja powinna być zaznaczona. Dla wyższych środowisk - musicie się sami zastanowić.

Wracając do tematu: kliknięcie przycisku Create tworzy nam listę kroków jak na screenshocie poniżej:

 

 

 


Do uzupełnienia mamy Azure subscription i App Service name. I jesteśmy gotowi do pierwszej instalacji!

Proponuję jeszcze zmienić nazwę Enviroment 1 na coś bardziej znaczącego, na przykład: dev, uat czy perf. Klikamy +Release i wszystko powinno działać. W moim przypadku pierwsza instalacja przebiegła bez problemów. Natomiast gdy spróbowałem jeszcze raz, dostałem poniższy błąd:

 

Error Code: ERROR_FILE_IN_USE More Information: Web Deploy cannot modify the file 'XYZ.dll' on the destination because it is locked by an external process. In order to allow the publish operation to succeed, you may need to either restart your application to release the lock, or use the AppOffline rule handler for .Net applications on your next publish attempt. Learn more at http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_FILE_IN_USE.

 

Żeby go naprawić musimy rozwinąć sekcję Additional Deployment Options w kroku Deploy Azure App Service. By na szybko pozbyć się błędu, sugeruję zaznaczyć opcję Take App Offline, tak jak poniżej:

 

 

Gotowi?

 

Można puszczać?

 

Stój!!!!

 

Są jeszcze dwie dodatkowe opcje, które warto rozważyć!

 

  1. Remove additional files at destination – jeżeli jej nie zaznaczysz, to po kilku instalacjach może się okazać, że masz śmietnik na serwerze. Co więcej: jeżeli zostaną na serwerze stare pliki Adobe Flash (np. przychodzące z ZeroClipboard), to może się okazać, że zostawiliście dziurę na atak XSS. Niestety, ta opcja też nie jest bez wad. Jeżeli zapisujecie jakiekolwiek pliki na serwerze, to instalacja je usunie. Oczywiście zapis do systemu plików w przypadku usługi Azure App Service nie jest najlepszym pomysłem, ale co tu dużo mówić: zdarza się. I to pewnie regularnie. Więc jeżeli macie takie pliki, to ważna dla Was jest opcja numer 2...

  2. Exclude files from the App_Data folder – jak można znaleźć w dokumentacji zadaniem katalogu App_Data jest właśnie przechowywanie plików aplikacji. Na przykład bazodanowe pliki mdf (więcej na ten temat tutaj). Więc jeżeli już musicie zapisywać jakieś pliki, to właśnie tam. 

    W mojej opinii warto zaznaczyć obie opcje, dzięki czemu będziemy mieli zarówno wyczyszczony śmietnik, jak i pozostawione, istotne dla nas pliki.

 

Rozgrzanie aplikacji

Najsmutniejszą rzeczą dotyczącą klasycznych aplikacji ASP.NET jest ich czas startu. Niezależnie od ich wielkości, zawsze jest on zbyt wolny.

Oczywiście kilka rzeczy możemy zoptymalizować. Świetnym przykładem jest używanie Razor Generator do kompilacji naszych widoków MVC podczas kompilacji, zamiast uruchamiania aplikacji. Innym przykładem jest dobry wybór kontenera IoC (więcej informacji tutaj).

Ale nawet wprowadzenie wszystkich zmian nie powoduje, że nasza aplikacja jest wystarczająco szybka dla pierwszego użytkownika.
Najprostszym sposobem na rozwiązanie tego problemu jest „rozgrzanie” aplikacji samemu, czyli przed wejściem pierwszego klienta.

Istnieje całkiem pokaźny zestaw tasków w VSTS, za pomocą których możemy stworzyć i uruchomić testy wydajnościowe naszej aplikacji. Ale nie istnieje task, za pomocą którego możemy po prostu stworzyć wywołanie kilku URL. Całe szczęście możemy stworzyć prosty skrypt PowerShell, który wykona za nas brudną robotę:

 

param(
[Parameter(Mandatory)]
[string]
$rootUrl
)#Make sure that website is alive
for($tryIndex=0; $tryIndex -le 10; $tryIndex++){
try{
$time = Measure-Command{Invoke-WebRequest $rootUrl -UseBasicParsing -ErrorAction Stop -ErrorVariable siteIsNotAlive}
Write-Host "Site is running"
Write-Host "wget $rootUrl in $($time.TotalSeconds)"
break;
}
catch{
Write-Host "Sleep + repeat"
Start-Sleep -s 1
}
}#url suffixes
$suffixes = @("/", "/url_1", "url_2")$suffixes | ForEach-Object{
$url = $rootUrl+$_;
$time = Measure-Command{Invoke-WebRequest $url -UseBasicParsing}
Write-Host "wget $url in $($time.TotalSeconds)"
}

 

 

Po przeczytaniu powyższego kodu pewnie zastanawiasz się, o co chodzi w części za Make sure that website is alive. Wszystko wynika z faktu, że start aplikacji nie jest natychmiastowy. W momencie, gdy nasza strona jest jeszcze offline, zwracany jest po prostu błąd HTTP.

Żeby użyć powyższego skryptu można go albo wrzucić bezpośrednio w VSTS, albo mieć w repozytorium kodu razem z solucją. Osobiście wolę drugą opcję, ponieważ kod instalacyjny jest takim samym kodem, jak każdy inny. Powinien więc być w repozytorium 😊

Niestety, po commit nie możemy go użyć od razu. Wszystko dlatego, że znajduje się wewnątrz paczki MSDeploy. Żeby to naprawić, porzebujemy poprawić plik csproj, żeby kopiował powyższy plik PowerShell w to samo miejsce, co paczkę MSDeploy. Powyższa zmiana wygląda następująco:

 

<Target Name="CopyDeployScriptToPackageFolder" AfterTargets="Package">
<Copy SourceFiles="$(MSBuildProjectDirectory)\deployment\warm-up.ps1" DestinationFolder="$(PackageLocation)" />
</Target>

 

Teraz nowy krok w VSTS jest banalnie łatwy:

 

Downtime

Jeżeli czytasz tę sekcję, to prawdopodobnie martwi Cię kolejny problem: czas downtime (czy też offline) jest za długi. Prawda jest taka, że nieważne, jak krótki jest, zawsze okaże się za długi, ponieważ [TU WSTAW SWÓJ WAŻNY POWÓD].

Ale jest na to sposób w Azure. Potrzebujemy użyć tak zwanych slotów. Niestety, nie ma nic za darmo. I żeby skorzystać z tej funkcjonalności, potrzebujemy planu Standard albo Premium.

Po migracji na wybrany plan, dodanie nowego slotu to bułka z masłem. Wystarczy kliknąć Add slot w zakładce Deployments na wybranym App Service:

 

 

Po utworzeniu slotu możemy dokonać zmiany w kroku Deploy Azure App Service. Zaznaczamy po prostu opcję Deploy to slot i wybieramy utworzony wcześniej slot. Dodatkowo musimy pamiętać, by zmienić argumenty naszego skryptu PowerShell tak, by teraz rozgrzewał nam slot, a nie końcową aplikację.

Ostatnia kwestia to zamiana slotów. Tutaj sprawa jest prosta. Dodajemy nowy krok do naszego workflow. Tym razem jest to task o nazwie Azure App Service Manage. W momencie pisania był on oznaczony jako PREVIEW, ale działa bez żadnych problemów.

Dzięki użyciu slotów i ich zamianie dostajemy dodatkowy bonus. Łatwo przywrócić nam poprzednią wersję. Wystarczy zamienić sloty jeszcze raz. Jedna drobna uwaga: należy pamiętać żeby uruchomić na slot nim zaczniemy go rozgrzewać. Żeby to zrobić, dodajemy jeszcze raz krok o nazwie Azure App Service Manage i wybieramy w nim opcję uruchomienia slotu.

Całość wygląda następująco:

 

 

Niestety, na sam koniec muszę wspomnieć o jednej wadzie powyższego rozwiązania. Mianowicie: przestajemy móc używać folderu App_data do przetrzymywania w nim ważnych plików dla aplikacji. Wynika to z faktu, że nie synchronizuje się on pomiędzy slotami. Żeby uzyskać persystentne dane, potrzebujemy innych narzędzi z Azure, jak na przykład bloby, zewnętrzne logowanie, baza SQL czy inne.

Dziękuję, jeśli dotarliście aż tutaj. Jeżeli macie do mnie jakieś pytania lub wątpliwości - służę pomocą :) Adres e-mail znajdziecie w sekcji kontakt.

 

Piotr Stapp, FinAi.com

Warszawa, 5 czerwca 2017 roku

Location icon Facebook icon Twitter icon Google+ icon LinkedIn icon Technology icon Business icon Marketing icon Phone icon Mail icon User icon Tag icon Bubble icon Arrow right icon Arrow left icon Calendar PR Contact