System.Web.HokusPokus czyli Continuous Deployment dla leniwych

1

Niektórzy twierdzą, że lenistwo to paradoksalnie potęga cywilizacji, bo gdyby nie ludzie leniwi, nie byłoby tylu wynalazków. Czy faktycznie tak jest? Może to nie lenistwo jest źródłem rozwoju, a odwieczna chęć człowieka do podbicia i podporządkowania sobie całego świata? Może lenistwo jest tylko nagrodą, efektem ubocznym takiego podporządkowania? Jakkolwiek by nie było, zostawmy te rozważania i weźmy się lepiej za coś konkretnego! W naszym świecie takie podporządkowanie niewątpliwie możemy nazwać automatyzacją i o niej warto pomyśleć w pracy programisty.

SoftwareHut - avatarAutorzy tekstuSoftwareHut – diamentowy sponsor konkursu „Daj Się Poznać”, białostocka firma o dużych aspiracjach. Dla swoich Klientów są solidnym partnerem w dziedzinie szeroko rozumianych usług IT oraz outsourcingu specjalistów.  Starają się łamać stereotypy związane ze sposobem postrzegania programistów, działać niestandardowo, jak tylko się da wspierać społeczności i ciekawe inicjatywy rodzące się w głowach prawdziwych pasjonatów! Swoją codzienną pracą „od kuchni” i „bez makijażu”  dzielą się na Facebooku oraz Snapchacie. Są firmą budowaną wokół ludzi i dla ludzi.
Aktualnie starają się wystartować z projektem nowego firmowego bloga i, jak twierdzą, ten post jest pierwszym konkretnym krokiem zrobionym w tym kierunku ;)

Ten krótki tekst ma za zadanie pokazać jak szybko, minimalistycznie i skutecznie za pomocą Visual Studio Online oraz Azure zrealizować proces Continuous Deployment, który może stać się bardzo dobrą bazą do dalszego rozwoju CD. Zaczynamy!

VSO, Azure + Continuous Deployment

W największym skrócie działa to tak: gdy pojawia się Git pull request, kod jest automatycznie wystawiany na Azure Website pod adresem url zawierającym nazwę gałęzi/brancha. Aplikację można uruchomić, zobaczyć, przetestować… Po zamknięciu pull requesta wszystko zostaje posprzątane i usunięte. Voila! Szybko, minimalistycznie i skutecznie. Prześledźmy zatem co, gdzie i kiedy się dzieje.

image

Ale ale, co dokładnie chcemy osiągnąć? Załóżmy, że nasz workflow wygląda następująco:

  1. Programista dostaje Work Item np. “Task nr 4 – zarządzanie użytkownikami”.
  2. Ponieważ pracujemy z podejściem feature branching, tworzona jest gałąź o nazwie np. 4-users i programista zaczyna implementację.
  3. Implementacja zostaje zakończona i programista zgłasza pull request o merge gałęzi 4-users do gałęzi master.
  4. Po zgłoszeniu tego pull requesta, aplikacja web zostaje wystawiona jako Azure Website pod adresem np. nazwaprojektu-4-users.azurewbsites.net
  5. Pull request przechodzi code review innego programisty i zostaje oznaczony jako Approved.
  6. Dział QA testuje aplikację pod wystawionym adresem i oznacza pull request jako Rejected.
  7. Programista poprawia błędy, commituje zmiany, pushuje.
  8. Aplikacja ponownie zostaje automatycznie wystawiona.
  9. Dział QA testuje aplikację i oznacza pull request jako Approved.
  10. Pull request zostaje zmergowany do gałęzi master.
  11. Aplikacja spod adresu nazwaprojektu-4-users.azurewebsites.net oraz wszystko z nią związane (np. baza danych) zostaje usunięte.

Magia

Skupmy się zatem na dwóch punktach dotyczących automagicznego wystawiania i usuwania aplikacji. Potrzebna będzie do tego subskrypcja Azure, a pierwszym krokiem jest połączenie VSO z Azure.

W wybranym projekcie przechodzimy do ustawień (ikona w prawym górnym rogu).

clip_image001

Następnie wybieramy “New Service Endpoint” i kolejno “Azure Classic“.

clip_image002

Wybieramy uwierzytelnianie przez certyfikat. Aby pobrać plik z certyfikatem i resztą danych do wypełnienia klikamy link “publish settings file

clip_image003

Teraz stwórzmy build aplikacji o nazwie PublishToAzure. W zakładce build klikamy znak plusa i wybieramy Visual Studio. Wybieramy gdzie są źródła naszego projektu i widzimy kroki naszego builda.

ts-build

  1. Wyrzucamy wszystkie kroki oprócz “build solution”
  2. W kroku “build solution” w “msbuild arguments” dodajemy /v:q /m
    • /v:q – to skrót od /verbosity:quiet , minimalizuje informacje, które wypisuje msbuild; potrafi to skrócić czas builda
    • /m – jeżeli będzie to możliwe, msbuild będzie kompilować nasz projekt na kilku rdzeniach
  3. Dodajemy następny krok “AzurePowershell” i jako skrypt dodajemy poniższy kod.
#aby zaimportować odpowiednie moduły (VSO robi to za nas, ale potrzebne jest to żeby odpalić i przetestować skrypt w ISE )
Import-Module "C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Azure.psd1"
Import-Module 'C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\AzureResourceManager.psd1'

#wczytanie zmiennych środowiskowych 
$branch = $Env:BUILD_SOURCEBRANCH
write-host "building branch $branch"
 
$project = $Env:SYSTEM_TEAMPROJECT

$urlprefix = "$project-"
$sources = $Env:BUILD_SOURCESDIRECTORY

$dir = "$sources\src\"

# wyciągniecie ze zmiennej branch właściwej nazwy gałęzi, bo jest tu ona podawana jako refs/costam/nazwabrancha

if( $branch.LastIndexOf('/') -gt 0)
{
    $branch = $branch.Substring($branch.LastIndexOf('/')+1)
}

# url ma postać nazwaprojektu-nazwabrancha
$url = $urlprefix +  $branch 

$dbName = $url

# w nazwach baz danych niedozwolone jest korzystanie ze znaku myślnika
$dbName = $dbName.Replace('-','_')

# jeżeli strona już istnieje to usuń ją
$website = Get-AzureWebsite -name $url 
if($website -ne $null)
{ 
    Write-Host "Deleting website with url $url"
    Remove-AzureWebsite $url -Force
}

# stwórz nowy website o podanym urlu
$website = New-AzureWebsite $url
Write-Host "Creating website with url $url"
try
{
    #usuń bazę danych
    Write-Host "Attempt to remove database  $dbName"
    Invoke-Sqlcmd -ServerInstance "$sqlServerName" "DROP DATABASE $dbName" -Username $login -Password $password -QueryTimeout 2000
}
catch{}

#przywróć backup
try
{
    $sql = " RESTORE DATABASE $dbName
    FROM DISK = 'c:\db\backups\backup.bak'
     WITH MOVE 'naszprojekt' TO 'c:\db\$dbName.mdf',
          MOVE 'naszprojekt_log' TO 'c:\db\$dbName.ldf',
          MOVE 'naszprojekt_dev_filestream' TO 'c:\db\$dbName', NOUNLOAD,  REPLACE,  STATS = 10
    GO ";

    Write-Host "Attempt to create database  $dbName"
    Invoke-Sqlcmd -ServerInstance "$sqlServerName" $sql -Username $login -Password $password  -QueryTimeout 2000
}
catch{}

#zbuduj paczkę do deploymentu
#ważny parametr BuildingProject - przed publishem builduje projekt, bez tego następuje tylko skopiowanie plików

&"C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" "$dir\Project.Web\Web.csproj" /p:DeployOnBuild=true   /p:VisualStudioVersion=14.0 /v:q /p:Configuration=Release /t:Package /p:BuildingProject=true

# publish paczki z podmianą connection stringów
Publish-AzureWebsiteProject -package  "$dir\Project.Web\obj\Release\Package\Web.zip" -name $url  -ConnectionString @{ "DBConnection" = "Data Source=$sqlServerName;Initial Catalog=$dbName;User Id=$login;Password=$password"; }

Nazewnictwo website w konwencji {nazwa_projektu}-{nazwa_brancha} ma taką zaletę, że podczas ręcznego zarządzania website’ami przez manage.windowsazure.com mamy je posortowane według projektów.

Następnym krokiem jest stworzenie kolejnego builda, tym razem takiego, który usunie aplikację z Azure. Nazwijmy go RemoveFromAzure. W tym buildzie obchodzi nas tylko krok “AzurePowershell“, a ważne są tu dwie linijki:

Remove-AzureWebsite $url -Force 

Invoke-Sqlcmd -ServerInstance "$sqlServerName" "DROP DATABASE $dbName" -Username $login -Password $password -QueryTimeout 2000

Ostatnim krokiem jest napisanie małej aplikacji web. VSO posiada mechanizm Web Hook, który przy wystąpieniu wybranego zdarzenia potrafi wysłać POST na podany przez nas url. W taki sposób możemy zintegrować VSO z naszym firmowym Slackiem, ale my wykorzystamy to w inny sposób.

Schemat działania naszej aplikacji.

  1. Programista tworzy pull request.
  2. Web Hook powiadamia naszą aplikację
  3. Nasza aplikacja w zależności od tego jaki jest status pull requesta (updated, closed czy abandoned)
    • triggeruje build PublishToAzure
    • triggeruje build RemoveFromAzure

Podsumowanie

Plusy takiego rozwiązania:

  • nowe funkcje są gotowe do testowania najszybciej jak to możliwe
  • zerowy czas poświęcony na wystawianie wersji aplikacji dla działu QA
  • po skończonej pracy nad zadaniem wystawiona aplikacja zostaje usunięta

Minusy:

  • wystawiane website są domyślnie tworzone w darmowym planie, który przewiduje ograniczone zasoby np. pamięci RAM
  • można dodać krok builda “AzureResourceManager” i tam zmienić plan na np. “Basic”, wtedy miejmy już na uwadze, że wiąże się to z dodatkowymi kosztami

Powyższy tekst to tylko propozycja w jaki sposób można najprościej podejść do tematu Continuous Deployment. Pamiętajcie, że nieważne jest w jaki sposób to zrealizujecie, ważne jest, że spróbujecie to wdrożyć u siebie i dalej dostosowywać do swoich potrzeb. Wszystko po to, aby jak najwięcej czasu zostało nam na kodowanie, czyli to, co wszyscy lubimy najbardziej.

Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.