Azure Automation na příkladu změny tieru webové aplikace

Azure platforma v sobě obsahuje obrovské množství automatizace. Škálování počtu VM či nodů hostujících webové aplikace, začleňování do balanceru a asi tisíc dalších věcí. Někdy ale můžete chtít svoje vlastní automatizace a pak můžete například napsat velmi mocné PowerShell skripty, které kromě Azure rozhýbou i vaše operační systémy či aplikace. Jedna věc je ale poslat z notebooku skript do Azure a druhá mít centralizovaný orchestrovaný rámec, který funguje i když se veze váš notebook v metru. To je Azure Automation a dnes si ho vyzkoušíme.

Azure Automation

O co jde? V nejjednodušší podobě si to představte jako sdílený server, kde máte svoje uzavřené PowerShell prostředí (tam si můžete instalovat různé další moduly a jste odděleni od ostatních) a nad tím je systém, který spouští vaše skripty jak potřebujete. Možná v pravidelných časech, možná jako reakci na nějaký alert nebo čeká na webhook na REST zavolání z jiného libovolného nástroje či je integrován s OMS. Tyto skripty mohou nejen ovládat Azure jako takový, ale samozřejmě dělat další operace - přistupovat do operačních systémů, exportovat data z databáze, rozesílat emaily a notifikace uživatelům a tak podobně.

Možná se ptáte proč zapřísáhlý zastánce desired state, tedy deklarativních automatizačních postupů, propaguje workflow model (imperativní přístup), tedy krok za krokem řešení ve skriptech? Tyto dva světy se totiž výborně doplňují. Pro provisioning infrastruktury v Azure bych určitě šel do ARM šablon, případně Terraformu či CloudForms (a pro jednodušší situace možná Ansible či Chef). Pro provisioning vnitřku VM (OS, aplikace) bych volil Ansible, případně Chef či Puppet a pro Windows svět (pakliže váš tým je zaměřen jen tímto směrem) PowerShell DSC. Jsou ale situace, kdy potřebujete procesní přístup. Udělej tohle, pak tamto. Vyzkoušej něco a podle odpovědi postupuj dál. Zjistit si něco z externích zdrojů a zařid se podle toho. To je také velmi důležité, desired state procesní pohled nezachycuje. Někdy tedy bude naprosto ideální použít jednoduše oboje. Azure Automation bude orchestrovat komplexní proces (třeba DR), ale pro některé úkony se rozhodně nemusí stydět zavolat ARM a PowerShell DSC.

Azure Automation ale dokáže tahat i za vaší on-premises infrastrukturu a pro ten účel existuje koncept Hybrid Runbook Worker. Jde v zásadě o agenta, kterého nainstalujete na VM v on-premises a ten komunikuje s Azure Automation (nemusíte tedy otevírat žádné porty dovnitř do vaší infrastruktury, je to bezpečné). Ten si z Azure stáhne zadanou práci a lokálně ji provede.

Azure Automation kromě klasických PowerShell skriptů umožňuje používat také PowerShell Workflow. V čem je jiné? Především jde o schopnost paralelizace, tedy úkony se neřeší sekvenčně jak u běžného skriptu, ale můžete definovat co může být prováděno současně a dramaticky tak zrychlit běh celého workflow. Druhým aspektem je schopnost vytváření checkpointů, tedy komplexní workflow může v určitém místě uchovat svůj stav a vy máte možnost z tohoto bodu pokračovat dál. To nabízí větší robustnost, která je vhodná zejména pro velmi komplexní operace jako je disaster recovery vašeho datového centra.

Posledním velkým bodem je orchestrace úkonů PowerShell DSC, tedy desired state konfigurace vašich Windows strojů. Definujete co v něm chcete nebo naopak nechcete mít a robot to uvede do požadovaného stavu. I to je možné pořídit v rámci Azure Automation.

Vytvořme si automation účet

Nejprve si pojďme vytvořit Azure Automation účet.

Určíme si jméno a lokalitu a také necháme vytvořit Run As účet. Pod ním bude Azure Automation vykonovávat svoje zásahy do Azure, takže víte přesně co udělal robot a co člověk. Máte možnost si s tím pohrát i ručně a mít ještě víc pod kontrolou, ale to já teď nepotřebuji.

Po pár minutách bude náš automatizační účet připraven. Všimněte si, že nám byly vytvořeny i čtyři příkladové Runbooky. Na stránce vidíme přehled Runbooků (zjednodušeně řešeno skriptů), Joby (spuštěné úlohy), Assety (například nainstalované moduly, časové rámce pro kalendář, proměnné apod.), hybridní "makáči" a věci kolem desired state konfigurace OS (DSC).

Ukázka - škálujeme App Service

Vyzkoušejme si řešení následující situace. Mám App Service Plan v kategorii Basic 2, kde hostuji web appku, API a funkce. Azure mi nabízí možnost automaticky škálovat přidáváním a ubíráním nodů, což je skvělé a rozhodně ideální cesta. Jenže moje situace je specifická - jde o opravdu malinkatou aplikaci, která se v noci vůbec nebude používat. Vždy jí stačí pouze jeden node a v noci ji navštíví maximálně jeden zbloudilý uživatel. Jak to řešit? Co kdybychom na noc přepnuli aplikaci do Free tieru? Zůstane dostupná (ačkoli bez jakékoli garance výkonu, takže naprosto nevhodná pro produkci - ale to mi nevadí), ale neplatím za ni. Ráno bych zas servisní plán přehodil zase do B2. Tohle Azure sám o sobě nezajišťuje (ono to má totiž konsekvence, protože nižší tier třeba nemá všechny vlastnosti vyššího a ty se před tím musí odkonfigurovat). V mém případě tedy ideální pro vyzkoušení Azure Automation, s kterým se dá dělat úplně cokoli.

Takhle vypadá moje prostředí.

Moje skripty budou potřebovat příslušné Azure moduly, tak se podívejme, jaké máme nainstalované v základu.

Jak vidno AzureRM.Websites, který budeme potřebovat, tam není. Přidáme z galerie.

Nejprve budeme potřebovat nejnovější AzureRM.profile modul. Najděte ho a provedeme instalaci.

Najděte Websites modul a nainstalujeme.

 

Tím jsme připraveni. Nejprve jsem si udělal testovací skriptík, který pouštím z notebooku, a který mi ukazuje, v jakém tieru aktuálně moje aplikace běží a zda odpovídá.

while ($true) {
    $time = Get-Date
    $tier = (Get-AzureRmAppServicePlan -ResourceGroupName automation-demo -Name demo-plan).Sku.Size
    $service = (Invoke-WebRequest "https://automationdemofunkce.azurewebsites.net/api/funkce?code=iChXT3UHOTB05jJ6xJtK9rL9sN6C1mt3VGuRhxZsExWlXzz3oyeIxw==").Content
    Write-Host $time.ToLongTimeString() " -> Tier: " $tier "   Odpoved sluzby: " $service
    sleep 1
}

Aktuálně mi píše tohle:

10:58:26  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
10:58:28  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
10:58:31  -> Tier:  B2    Odpoved sluzby:  "Ziju!"

Běžím tedy v "denním režimu". Připravil jsem následující skript. Ten jako vstupní parametr má jméno resource groupy a servisního plánu (aby byl trochu univerzálnější). Následně se přihlásí do Azure Run As účtem (s tím si nelamte hlavu, já kód zkopíroval z ukázkového skriptu a nehodlám ho měnit). Na konci pak jsou kroky potřebné ke shození servisního plánu do Free vrstvy. Potíž je, že v Basic mají služby by default nastaveno AlwaysOn, tedy že zůstávají plně aktivní i pokud je nikdo nepoužívá. Free vrstva tohle nepodporuje, tedy musí to být vypnuté (pokud dlouho nikdo nepřistupuje, web se uspí a při první požadavku se musí dostat do paměti, takže první request po dlouhé době může trvat třeba pár vteřin). Musíme tedy AlwaysOn povypínat a pak můžeme změnit tier. Vypadá to celkově takhle:

<#
    .DESCRIPTION
        Scale App Services to Free
#>

Param(
  [string]$rgName,
  [string]$planName
)

$connectionName = "AzureRunAsConnection"
try
{
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

    "Logging in to Azure..."
    Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

$PropertiesObject = @{alwaysOn = $false;}
$sites = Get-AzureRmWebApp -ResourceGroupName $rgName
foreach ($site in $sites) {
    Set-AzureRmResource -PropertyObject $PropertiesObject -ResourceGroupName $rgName -ResourceType Microsoft.Web/sites/config -ResourceName ($site.SiteName+"/web") -ApiVersion 2015-08-01 -Force
}
Set-AzureRmAppServicePlan -ResourceGroupName $rgName -Name $planName -Tier Free

 

Založme tedy nový Runbook.

Bude typu PowerShell (existuje i grafický editor, ale pokud vládnete PowerShellem, je to podstatně rychlejší).

Vložte zmíněný kód, klikněte Save a pojďme si to otestovat.

Vyplňte parametry.

Teď už stačí kliknout na tlačítko Start. V tento okamžik se vytvoří úloha a je zařazena do fronty. Neznamená to, že se začne provádět hned - Azure řídí zdroje a pokud je moc lidí, budete muset chvilku počkat. SLA na tuto službu zní, že 99,9% vašich jobů bude spuštěno do 30 minut. Většinou jsem zaznamenal čekací doby do deseti minut, v každém případě s tím ale ve svých plánech počítejte (pokud má být něco v 7:00 hotové, skript trvá 10 minut, tak naplánujte spuštění pro jistotu na 6:20).

Tady je výsledek mého sledovacího skriptu.

12:09:51  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
12:09:53  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
12:09:56  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
12:09:58  -> Tier:  F1    Odpoved sluzby:  "Ziju!"
12:10:10  -> Tier:  F1    Odpoved sluzby:  "Ziju!"

Jak vidno vše se povedlo, od teď jedu ve Free tieru. Jsem spokojen, Runbook pojďme publikovat.

Přidejte ještě druhý Runbook, který bude dělat opak:

<#
    .DESCRIPTION
        Scale App Services to B2
#>

Param(
  [string]$rgName,
  [string]$planName
)

$connectionName = "AzureRunAsConnection"
try
{
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

    "Logging in to Azure..."
    Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

$PropertiesObject = @{alwaysOn = $true;}
$sites = Get-AzureRmWebApp -ResourceGroupName $rgName
Set-AzureRmAppServicePlan -ResourceGroupName $rgName -Name $planName -Tier Basic -WorkerSize Medium
foreach ($site in $sites) {
    Set-AzureRmResource -PropertyObject $PropertiesObject -ResourceGroupName $rgName -ResourceType Microsoft.Web/sites/config -ResourceName ($site.SiteName+"/web") -ApiVersion 2015-08-01 -Force
}

Výborně. Předpokládejme, že požadavek byl, že se má služba ve všední dny ráno v 7 zapnout a večer v 7 shodit do Free. Založme si tyto časové okamžiky.

Definujme všední dny ráno.

Dále pak večerní vypínání.

Tyto pak nastavíme pro naše dva Runbooky.

Kromě času nastavte také parametry, tedy vstupy našeho Runbooku.

Nastavte pro oba Runbooky a automatizaci máme hotovou. Vyzkoušejme ještě jednu věc. Dejme tomu naše zapínadlo můžeme nechat reagovat na webhook, tedy nespouštět jen na základě času, ale na vyžádání třeba z nějaké jiné aplikace.

Vytvořím webhook s platností jeden rok. URL si skopírujte, budeme ho potřebovat.

Vyzkoušíme si zavolat webhook z notebooku z PowerShellu, ale stejným způsobem to jednoduše udělá vaše aplikace.

Invoke-WebRequest "https://s2events.azure-automation.net/webhooks?token=b0%2fvVr5Xfmukv5URsLmbrZt3rTKbP0lcd9%2b8ZHtye%2fM%3d" -Method Post

Průběh můžete sledovat v GUI. Je tam vidět, že webhook byl úspěšně zavolán a úloha je naplánovaná.

Po chvilce zjišťuji, že moje služba se přepnula do B2. Funguje to.

12:29:05  -> Tier:  F1    Odpoved sluzby:  "Ziju!"
12:29:07  -> Tier:  F1    Odpoved sluzby:  "Ziju!"
12:29:09  -> Tier:  F1    Odpoved sluzby:  "Ziju!"
12:29:12  -> Tier:  F1    Odpoved sluzby:  "Ziju!"
12:29:14  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
12:29:16  -> Tier:  B2    Odpoved sluzby:  "Ziju!"
12:29:18  -> Tier:  B2    Odpoved sluzby:  "Ziju!"

Kolik to bude stát

Nechme pro dnešek stranou PowerShell DSC, který se licencuje na nody (o tomto řešení někdy příště) a podívejme se na orchestrační engine samotný. Jednotkou pro billing je tady čas běhu vašich skriptů. V dnešní ukázce mluvíme o asi 1-2 minutách na spuštění. Pokud se vejdete do 500 minut měsíčně, je pro vás služba zcela zdarma. Placená verze ale není nijak drahá - za 20 hodin čistého času běhu skriptů zaplatíte 2 EUR.

 

Automatizaci mám velmi rád a používal bych desired state všude tam, kde je to možné, tedy ARM šablony pro Azure zdroje, PowerShell DSC pro Windows OS nebo univerzální infrastrukturní Terraform či CloudForms nebo konfigurační Ansible, Chef, Puppet. Jsou ale situace, kdy potřebujete orchestrovat víc věcí dohromady a zásadní je workflow, tedy nějaký proces, postup (teď tohle, pak tamto a nakonec něco dalšího), ne desired state. V takovém případě nad to dejte Azure Automation.



Jak na Terraform pro Azure služby, které jsou zatím jen v Preview Automatizace
Datové hřiště - zpracování proudu událostí s Azure Stream Analytics nakopnuté Terraformem Automatizace
Datové hřiště - generátory fake dat do kontejneru zabalené Terraformem v Azure nahozené Automatizace
Datové hřiště - jak si hrát s daty bez sebemenšího kliknutí s Terraform a Azure Automatizace
Federace tokenů GitHub Actions s Azure Active Directory pro přístup z vaší CI/CD do Azure bez hesel Automatizace