Migracja Azure Scheduler do Logic Apps

Kwiecień 10, 2019 Grzegorz Oronowicz

Jakiś czas temu można było usłyszeć zapowiedź, że Microsoft planuje wyłączenie usługi Azure Scheduler i proponuje, aby przynieść ją do Logic Apps. Jeśli twoje zasoby mają kilka zdefiniowanych zadań to można to wykonać ręcznie klikając w portalu Azure. Co zrobić jeśli jest tego więcej? Na co zwrócić uwagę przy migracji? Jak użyć Terraform do IaC tak, aby rozbudowa była szybka a deploy odbywał się w trybie „enter i idę po kawę” 🙂

Sytuacja zastana

W naszym istniejącym systemie usługę wykorzystujemy do uruchamiania cyklicznych procesów działających w tle. Jest to jeden z mechanizmów naszego systemu, który jest zarządzany ręcznie. Nie mieliśmy skryptów ani wersjonowania w kodzie. Dodawanie nowych zadań to operacja powtarzalna, doskonale nadająca się do automatyzacji.

Samą migrację można by przeprowadzić pisząc skrypt w PowerShell lub używając specjalnie napisanej prostej aplikacji w języku dobrze znanym danemu zespołowi. Takie rozwiązania nie dają jednak dalszych korzyści, czyli w zakresie późniejszego zarządzania zasobami i łatwego dodawania kolejnych zadań.

Aktualnie nasza infrastruktura obejmuje 3 zasoby Azure Scheduler (w tym kilka testowych), w których jest po 40 zadań wykonywanych cyklicznie. Dodają one wiadomość do odpowiedniej kolejki tak, aby wzbudzić dany serwis lub jakieś zadanie w serwisie.

Poza usługami Azure Scheduler mamy kilka przestrzeni Azure ServiceBus i kilkanaście kolejek. Czasem jedna kolejka obsługuje kilka zadań.

Szybka matematyka:
Liczba zadań: 3 x 40 = 120
Liczba kolejek: 3 x 20 = 60

To dużo, jak na ręczne przeklikanie w portalu.

Chciałem również, by cała infrastruktura została opisana w kodzie czyli zastosować tak zwane podejście Infrastructure as Code. Do tego użyłem narzędzia Terraform.

Problem okazał się dość skomplikowany i duży. Trzeba było wszystko opisać w skryptach Terraform’a a to narzędzie nie posiada opcji generowania skryptów z istniejącej infrastruktury. Posiada wprawdzie import ale najpierw trzeba każdy element opisać w skryptach. Więc znowu miałem do wykonania120 zadań, około 60 kolejek + 3 przestrzenie i grupy zasobów. Wielkie zadanie.

Jak zjeść słonia?

Mądre przysłowie mówi, że “kawałek po kawałku”.

Co trzeba było zrobić, aby przeprowadzić całą migrację?

Miałem istniejącą infrastrukturę, nie miałem skryptów do Terraform’a. Z pomocą przyszedł powershell i AzureRm (do wersji 5.7 bo późniejsze nie mają wsparcia dla Azure Scheduler z racji tego, że usługa jest porzucana). Postanowiłem, że przeczytam dane i wygeneruje skrypty w powershellu.

Powstaje z tego krótka lista „to do”:

  1. Przeczytać informacje na temat istniejącej infrastruktury
  2. Stworzyć wzorzec dla Logic App tak, aby istniejąca funkcjonalność została zachowana.
  3. Wygenerować całą migrowaną infrastrukturę za pomocą powershell’a.
  4. Stworzyć nowe zasoby przy użyciu wygenerowanych skryptów w Terraform

Ad.1 Do tego użyłem powershella i AzureRm.

Aby przeczytać istniejącą infrastrukturę należy posiadać odpowiednie uprawnienia do konta. Ja posiadałem użytkownika domenowego, który już na początku nie miał uprawnień do czytania za pomocą API powershell. Na początek musiałem zdobyć uprawnienia. Potem trzeba było się tylko zalogować i napisać skrypt Powershell’owy. Wiązało się to z przeczytaniem zasobów, przekonwertowaniem ich nazw w odpowiedniej konwencji do nowej a następnie wygenerowanie skryptu w Terraform, którego później mógłbym użyć już przy tworzeniu nowych zasobów.

Pobranie kolekcji zadań odbywa się poprzez wywołanie funkcji: Get-AzureRmSchedulerJob

Zadanie ze Scheduler’a składa się z dwóch podstawowych elementów: Schedule, Action.

Pierwsza sekcja opisuje kiedy ma być uruchomienie, druga co ma się wydarzyć

Moduł AzureRM nie jest w stanie przeczytać wszystkich informacji. Jeśli zadanie ma zdefiniowaną sekcję zaawansowaną, nie da rady odczytać informacji. Wtedy pozostają skomplikowane wywołania typu REST.

Zastosowałem tutaj drogę “na skróty” tzn. nie migrowałem sekcji zaawansowanej, ponieważ tylko kilka zadań miało ją zdefiniowaną i to uzupełniałem ręcznie. Takie rozwiązanie było lepsze i prostsze dla mojego przypadku.

Ad.2

Okazuje się, że stworzenie Logic Apps w Terraform nie jest prostą sprawą ponieważposiada on tylko podstawowe wpisy do definiowania Logic Apps czyli: Workflow, Trigger i prostej akcji. Dodawanie wiadomości na kolejkę jest nieco bardziej skomplikowane Okazało się, że skrypty Terraform nie są w stanie wspierać całkowitej funkcjonalności jaką chciałem osiągnąć.

Innym rozwiązaniem było użycie ARM templates z Azure. Wadą tego rozwiązania jest brak możliwości zaimportowania zasobu do Terraform.Albo stworzymy taki zasób w Terraformie i będziemy już nim zarządzać albo nic innego nie da się zrobić. Na szczęście będę generować skrypty i tworzyć nowe Logic Apps dlatego takie rozwiązanie jest akceptowalne.

Tworząc Logic Apps okazało się, że nazwa zasobu nie może mieć więcej niż 64 znaki. Dotychczasowe rozwiązanie w Azure Scheduler pozwalało nazywać zasoby dłuższymi znakami więc trzeba było rozwiązać to obcinając nazwę.

Kolejną rzeczą były różnice pomiędzy Azure Scheduler a Logic Apps jeśli chodzi o wywołania. Jednostki czasu w AS zapisane były w języku angielskim ale w liczbie mnogiej natomiast w Logic Apps jednostka jest liczbie pojedynczej.

Dlatego w powershellu musiałem przeprowadzić konwersję. Na szczęście język angielski jest dość prosty i wystarczyło tak naprawdę na końcu obciąć “s”.

Innym wyzwaniem był fakt, że już mieliśmy stworzone zasoby Service Bus. Były one umieszczone w innej subskrypcji oraz innej grupie zasobów. Tworzenie nowego zasobu o tej samej nazwie nie wchodziło w grę (nazwa była juz zajęta) dlatego należało przenieść zasób do nowej grupy w nowej subskrypcji i zaimportować go do Terraform. Najpierw napisałem skrypty powershell, które zapisują przestrzeń Service Bus i jego kolejki jako zasoby w Terraform a następnie zaimportowałem je do Terraform’a.

Trudności przysporzyło definiowanie czasu wyzwalacza. Dla różnych jednostek trzeba było użyć innych obiektów opisujących czas uruchomienia.

Chodziło tutaj głównie o obiekt schedule. Dla jednostki Day należało wypełnić właściwości hours, minutes. Dla Week dodatkowo właściwość weekDays, a dla pozostałych obiekt powinien być pusty. Więc mieliśmy 3 przypadki. Na szczęście udało się zastosować obejście przy pomocy klauzuli if w ARM i sekcji ze zmiennymi.
https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-workflow-actions-triggers#recurrence-trigger

1
2
3
4
5
6
7
8
"schedule": {
    // Applies only when frequency is Day or Week. Separate values with commas.
    "hours": [  ],
    // Applies only when frequency is Day or Week. Separate values with commas.
    "minutes": [  ],
    // Applies only when frequency is Week. Separate values with commas.
    "weekDays": [ "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday" ]
}


Po zakończeniu miałem już ARM template, który potrafił stworzyć pojedyncze logic app realizujące zadanie z Azure Scheduler’a. Opisałem je za pomocą skryptu Terraform z odpowiednimi parametrami. Byłem gotowy do wygenerowania całej listy z istniejącej infrastruktury.

 

Ad.3 Generowanie całej infrastruktury za pomocą Powershell’a.

Okazuje się, że Terraform ma swój własny język opisu zasobów. A ja miałem już istniejące zasoby. Dodatkowo Terraform nie posiada opcji importu tak żeby zostały utworzone skrypty. Posiada tylko opcję importu do stanu ale żeby to zrobić najpierw trzeba opisać każdy z zasobów, a tego było zbyt dużo. Z rozwiązaniem przyszedł Powershell i generowanie Terraformowych skryptów z już istniejących danych.
Pierwszym zadaniem była organizacja struktury plików i folderów w Terraform.  Przyjęliśmy podział, w którym na najwyższym poziomie były środowiska, później funkcjonalności a na końcu tak zwane template za pomocą których generowałem odpowiednie zasoby.

PowerShell w łatwy sposób pozwalał wygenerować pliki oraz skrypt z przygotowanego wcześniej wzorca (template). Pozostało tylko dostarczyć odpowiednich zmiennych i poskładać wszystko razem w pętli. Enter i skrypt gotowy, trzeba go tylko umieścić w odpowiednim miejscu w projekcie.

 

Ad.4 Stworzyć nowe zasoby przy użyciu wygenerowanych skryptów w Terraform

Wygenerowaną zawartość w Powershell umieściłem w projekcie Terraform. Zaimportowałem zasoby, które już istnieją. Najpierw odbyły się testy na środowisku developerskim, musiałem nanieść poprawki i byłem gotowy do końcowego importu. Przygotowanie do importu.
Na podstawie testów powstał plan migracji:

  1. Stworzenie nowej Resource Group
  2. Przeniesienie istniejącej infrastruktury (Service Bus)
  3. Import zasobów do Terraform za pomocą wygenerowanego wcześniej skryptu
  4. Stworzenie reszty zasobów – Logic Apps za pomocą Terraform (terraform apply)
  5. Zainicjowanie połączenia do Service Bus (ręcznie)
  6. Wyłączenie Azure Scheduler
  7. Monitoring aplikacji
  8. Radzenie sobie z wyjątkami (dotychczas zasoby tworzone były ręcznie)

Dzień migracji

Wszystko było gotowe i cała operacja wymagała paru kliknięć w portalu, Resztę załatwił Terraform. A ja mogłem pójść na kawę 🙂

W ten oto sposób udało się przeprowadzić skomplikowaną migrację, zawierającą sporą ilość zadań. Zasoby obecnie mam zapisane w Terraform, wersjonowanym przez repozytorium. Mogę śledzić historię zmian. Proces został zautomatyzowany i dodanie nowego zadania to kolejny wpis i wykonanie komendy w linii poleceń. Dodatkową korzyścią jest zarządzanie całymi środowiskami. Nie korzystam z zasobów, mogę je usunąć i ograniczyć koszty. A jak będę ich potrzebować to mam skrypt. Jeśli ktoś coś pozmienia w portalu to zawsze mam obecny stan w skryptach i mogę zasoby odtworzyć.

Najnowsze wpisy