Niedawno natknąłem się na stosunkowo mało popularne wciąż narzędzie w świecie DevOps, jakim są pipeline'y Azure DevOps. Od razu odczułem brak jakichkolwiek jasnych instrukcji lub artykułów na ten temat; nie wiem, czym to jest spowodowane, ale Microsoft zdecydowanie ma nad czym pracować, jeśli chodzi o popularyzację tego narzędzia. Dziś zbudujemy pipeline do automatyzowanego testowania w chmurze Azure.
Zadanie:
Mamy oprogramowanie, które buduje się przy użyciu tego samego Azure DevOps, zbierając je z projektu na WIX. Jeśli będzie zainteresowanie, napiszę również o tym narzędziu. Praktycznie jest to bardziej zoptymalizowany sposób automatyzacji budowy instalatorów Windows, zastępujący standardowy InstallShield. Nasze oprogramowanie pomyślnie się kompiluje i generuje artefakt, pewien setup.exe, który instaluje aplikację w systemie Windows. Trzeba zainstalować tę aplikację na maszynie wirtualnej przypominającej środowisko produkcyjne, skopiować tam zautomatyzowane testy przygotowane przez zespół testowy, uruchomić je i zebrać wyniki, aby ocenić, czy gałąź jest dobra, czy zła, zanim ją połączymy. Wszystko jak w GitLab, tylko przez...
Jako środowisko wirtualizacji, w którym będziemy uruchamiać nasze testy, oczywiście wykorzystamy Azure DevTest Labs, pewnego rodzaju jednostkę w subskrypcjach Azure, która została stworzona do uruchamiania różnych testowych rzeczy w rozsądnych cenach.
1. Integracja po stronie chmury
Na początek musimy zintegrować nasze DevTest Labs z Azure DevOps, do czego potrzebujemy pewnego Service Principal, właściwie konta serwisowego, które pozwala pipeline’om w chmurze na tworzenie/usuwanie tam zasobów dla siebie.
Przechodzimy do subskrypcji i znajdujemy usługę Azure Active Directory.

Znajdujemy Rejestracje Aplikacji i klikamy na Nową Rejestrację; to stworzy naszego service principal. Nie będę wchodził w szczegóły dotyczące wyboru ustawień przy tworzeniu, bo mogą się one różnić w zależności od subskrypcji.

Teraz musimy nadać uprawnienia naszemu service principal. W tym celu przechodzimy do subskrypcji, klikamy ikonę z kluczem. Wybieramy naszą subskrypcję.

Następnie w Kontroli Dostępu klikamy Przypisanie Roli i wyszukujemy stworzoną przed chwilą nazwę tego konta. Nadajemy rolę Współtwórcy, to wystarczy.

Następnie wracamy do naszego Service Principal w Azure AD i otwieramy jego właściwości. Później będą potrzebne wszystkie ID, które tam są, więc zapisujemy je.
Na tym kończą się nasze ustawienia portalu i przechodzimy do Azure DevOps.
2. Integracja z Azure DevOps
Najpierw przejdziemy do ustawień projektu i wybierzemy Połączenia usług. Tworzymy nowy element typu Azure Resource Manager.

Teraz potrzebne będą nam wszystkie ID, które zapisaliśmy. Klikamy na użyj pełnej wersji okna połączenia usług. Wprowadzamy wszystkie dane, które otrzymaliśmy od Service Principal. Naciskamy weryfikuj, a jeśli wszystko jest w porządku, zapisujemy połączenie. Teraz nasze potoki mogą go używać do łączenia się z chmurą.

3. Tworzenie potoku
Teraz przechodzimy do najciekawszej części, czyli budowy potoku. Otwieramy menu Pipelines-Builds

Wita nas menu tworzenia nowego buildu, które domyślnie spróbuje stworzyć nam plik YAML o odpowiedniej konfiguracji. Grzecznie odmawiamy tego i wybieramy klasyczną wersję. Zrozumiałe jest pragnienie Microsoftu, aby wszystko było jak u ludzi i umożliwić maksymalną personalizację potoków za pomocą YAML, ale skąpa dokumentacja i praktyczna niesprawność wielu modułów mówią nam, że na razie za wcześnie, aby korzystać z tej funkcjonalności.

Z bogatej gamy szablonów potrzebujemy prostego Pustego Potoku. Po jego utworzeniu wita nas puste okno edytora, w którym spędzimy całkiem sporo czasu.

Tak więc, naciskamy na + i trafiamy do pewnego sklepu z modułami, z którego potrzebujemy według listy następujące komponenty.

Zanim przejdziemy do konfiguracji zadań potoku, musimy utworzyć i umieścić w projekcie kilka plików. Będą to szablon ARM naszej wirtualnej maszyny, który wygenerujemy w Azure DevTest Labs, skrypt do pobierania IP maszyny po jej utworzeniu oraz, opcjonalnie, skrypty naszych testów lub tego, co chcemy uruchomić na hoście.
4. Generacja szablonu ARM
Aby stworzyć wirtualkę, musimy najpierw wygenerować dla niej szablon, plik json, który umieścimy w kodzie projektu, aby potok mógł go stamtąd odczytać.
Idziemy do naszego laboratorium i znajdujemy menu Formuły (reusable bases), klikamy utwórz nową.

Zobaczymy długą listę obrazów jako bazy, wybór rozmiaru maszyny, to wszystko takie samo jak przy tworzeniu wirtualki. Na tym etapie nie będziemy się zatrzymywać, od razu przejdziemy do ostatniego punktu właściwości maszyny, a mianowicie artefaktów. Możesz użyć dowolnych konfiguracji potrzebnych do twojego środowiska. Na przykład dodaję maszynę do domenę Dodaję na nią konto serwisowe jako administratora, aby pipeline mógł później uzyskać dostęp do tej maszyny za pomocą tego konta. To wszystko może się różnić, ale do pomyślnego przetestowania kodu potrzebujemy jednego artefaktu, na którym zatrzymamy się dokładniej. Aby na naszą maszynę zainstalować najnowszą wersję oprogramowania, które testujemy, wykorzystamy artefakt „Pobierz artefakt Azure Pipelines i uruchom skrypt”. Pamiętacie, na początku mówiłem, że gdzieś kompilowany jest build z instalatorem aplikacji? Teraz musimy poinstruować maszynę wirtualną, a konkretniej szablon, aby poszła i pobrała ten artefakt. I nie tylko go pobrała, ale również zainstalowała, dlatego wypełniamy specjalne pola określające projekt, nazwę builda i klucz tajny. Klucz tajny, jak w każdym systemie tego typu, jest generowany w koncie, w tym przypadku w Azure DevOps i zapisywany w Secrets w waszej laborze. Jest tu małe zastrzeżenie, w Secrets go zapiszemy, ale dla szablonu to nic nie zmienia, będzie on uruchamiany przez innego użytkownika w ramach pipeline'u, dlatego musimy jeszcze raz ręcznie wprowadzić klucz tajny do szablonu.
Kolejnym artefaktem, który należy obowiązkowo dodać, jest „Skonfiguruj WinRM”, będzie on potrzebny do późniejszego dostępu do maszyny. Jest tam tylko jeden parametr, hostname. Ponieważ go wcześniej nie znamy, skorzystamy z zmiennej %COMPUTERNAME%.

Więc dodaliśmy wszystkie potrzebne artefakty, przechodzimy do celu, dla którego tutaj przyszliśmy. Wyciągamy wygenerowany szablon ARM w zakładce Zaawansowane tego samego okna tworzenia formuły.

Kopiujemy zawartość strony do pliku VMtemplate.json i umieszczamy go w katalogu głównym projektu. Chmura nie jest nam już potrzebna, wracamy do pipeline'u.
5. Konfiguracja pipeline'u
Zacznijmy od najważniejszego i najciekawszego, tworzenia wirtualnej maszyny, dla której zrobiliśmy wszystkie te integracje i szablony. W punkcie Azure RM Subscription wybieramy nasze połączenie serwisowe, które skonfigurowaliśmy w punkcie 2. Następnie powinna pojawić się dostępna nam laboratoria. Potem wybieramy json, który wygenerowaliśmy i definiujemy kilka obowiązkowych zmiennych. Login i hasło do maszyny można ustawić bezpośrednio lub za pomocą zmiennych, ale nie jestem pewien, czy to działa, ponieważ cokolwiek bym tam nie wpisał, nie mogłem później zalogować się na maszynę tymi danymi. Najważniejsze to nadać nazwę maszyny, aby była jak najbardziej unikalna. W tym celu używam zmiennej środowiskowej budowy.

Następnie konfigurujemy jeszcze jeden istotny element. Po uruchomieniu maszyny musimy jakoś znać jej parametry, a lepiej, aby nie tylko my, ale i pipeline o tym wiedział. W tym celu tworzymy skrypt, na przykład GetLabVMParams.ps1 i umieszczamy go w projekcie. Tekst skryptu wziąłem z witryny Microsoft, ale trochę go dostosowałem do własnego środowiska, ponieważ pobierał PublicIP i FQDN maszyny. Ani jednego, ani drugiego nie posiadam, ale mam PrivateIP, którego niełatwo zdobyć, dlatego dopisałem fragment.
Param( [string] $labVmId)
$labVmComputeId = (Get-AzureRmResource -Id $labVmId).Properties.ComputeId
# Pobierz nazwę grupy zasobów laboratorium VM
$labVmRgName = (Get-AzureRmResource -Id $labVmComputeId).ResourceGroupName
# Pobierz nazwę laboratorium VM
$labVmName = (Get-AzureRmResource -Id $labVmId).Name
# Pobierz adres IP publiczny laboratorium VM
# $labVMIpAddress = (Get-AzureRmPublicIpAddress -ResourceGroupName $labVmRgName -Name $labVmName).IpAddress
# Pobierz FQDN laboratorium VM
# $labVMFqdn = (Get-AzureRmPublicIpAddress -ResourceGroupName $labVmRgName -Name $labVmName).DnsSettings.Fqdn
# Pobierz prywatny adres IP laboratorium VM
$VmNetworkdetails= (((Get-AzureRmVM -ResourceGroupName $labVmRgName -Name $labVmName).NetworkProfile).NetworkInterfaces).Id
$nicname = $VmNetworkdetails.substring($VmNetworkdetails.LastIndexOf("/"+1))
$labVMnetwork = (Get-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $labVmRgName)|Select-Object -ExpandProperty IPConfigurations
$labVMIpAddress = $labVMnetwork.PrivateIpAddress
# Ustal zmienną labVmRgName do przechowywania nazwy grupy zasobów laboratorium VM
Write-Host "##vso[task.setvariable variable=labVmRgName;]$labVmRgName"
# Ustal zmienną labVMIpAddress do przechowywania adresu IP laboratorium VM
Write-Host "##vso[task.setvariable variable=labVMIpAddress;]$labVMIpAddress"
# Ustal zmienną labVMFqdn do przechowywania nazwy FQDN laboratorium VM
Write-Host "##vso[task.setvariable variable=labVMFqdn;]$labVMFqdn"
Write-Output $labVMIpAddress
Set-Item wsman:localhostclienttrustedhosts * -ForceZ całego skryptu potrzebujemy tylko zmienną labVMIpAddress. Możliwe, że coś jeszcze będzie wam potrzebne, dlatego niczego nie usuwałem, a jedynie skomentowałem zbędne fragmenty.
Wyjaśnię również ostatnią linię skryptu, która pozwala naszej maszynie build na dostęp do dowolnego hosta przez WinRM.
Następnym krokiem uruchamiamy nasz niesamowity skrypt. Będzie on wymagał tego samego połączenia z chmurą oraz zmiennej wejściowej z ID maszyny, które będzie już znane z poprzedniego etapu. Jak? Tutaj należy wspomnieć o tak wspaniałej rzeczy, jak zmienne wyjściowe. Każdy krok może mieć listę zmiennych, które są przekazywane dalej, do następnych kroków pipeline'u. Odpowiednio dla naszego super skryptu taką zmienną będzie labVMIpAddress, nie zapomnij jej podać.

Następnie wykonuję dość proste rzeczy, które mogą się różnić w zależności od przypadku. Wykonuję zdalny skrypt, aby utworzyć udział, do którego później załaduję swoje skrypty.
New-Item "C:test" –type directory
New-SMBShare –Name "test" –Path "C:test" –FullAccess everyoneZ nazwy zadań jasno wynika, że następnie kopiujemy jakiś przykładowy skrypt na maszynę i w kolejnym kroku go wykonujemy. Jako adres zdalnej maszyny przyda nam się nasza zmienna $(labVMIpAddress). Następnie używamy zadania „pobierz artefakt z udziału” i kopiujemy wyniki wykonania skryptu do naszego środowiska budowania, a potem tym samym standardowym zadaniem zapisujemy te pliki w artefakcie budowania. Po tym, jak maszyna nie będzie nam już potrzebna, w ostatnim kroku ją usuwamy. Główną trudnością, jak widać z objętości artykułu, jest integracja z chmurą i nawiązanie kontaktu z wirtualną maszyną, którą stworzyłeś, a potem już można bawić się tyle, ile potrzeba.
To mój pierwszy artykuł, więc nie oceniajcie surowo, z chęcią przyjmę uwagi.
Źródło: habr.com
