Перейти к содержимому

Azure & Teamcity–автоматическое включение/выключение приложений

предлагает огромное количество опций и возможностей, в том числе и для автоматизации. В принципе, если вы планируете хостить свою работу исключительно там, то Вам даже не нужен Continuous Delivery сервер, так как всё необходимое уже есть в самом Azure. Однако, бесплатного ничего не бывает и за многое Azure вам выставит дополнительный счет.

Как известно, счет в Azure генерируется исходя из часов, в течении орых виртуальная машина была в состоянии Provisioned. Таким образом, тут есть возможность сэкономить – отключать машины и веб приложения через Портал (если выключать из машины, она всё равно будет генерить деньги) на ночь для тех окружений, которые не нужны по ночам (например, dev/QA/UAT окружения в негеографически распределенных командах).
Если у вас нет своего /Delivery (/) сервера и вы не планируете его внедрять, то Azure предлагает Azure Automations (биллинг по минутам, 500 минут (как будет видно позже, это маловато) предоставляются бесплатно) и этот runbook. Однако, если у вас уже есть CI/CD сервер, способный выполнять скрипты, то зачем генерировать излишнюю стоимость, если можно выполнять всё на этом сервере.

Скрипт для включения/выключения виртуальных машин:

#Switched Off or On set of VMs, passed as parameters
#Example usage: .\SwitchVmOnOff.ps1 username password 1 1 "some subscription name" "some-vm0";"some-vm1";"some-vm2"
#where
#username - user with co-administrator rights on subscription
#password - password for this user
#1 - boolean, if machine shall be switched off
#1 - is this VM v2 or no
#some sbuscription name - name of subscrtion
#"some-vm0";"some-vm1";"some-vm2" - machines to switch off

param(
    [string]$userName,
    [string]$password,
    [string]$switchOffString,
    [string]$useResourceManagerString,
    [string]$subscriptionName,
    [string]$machineNames
)

$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management..PSCredential ($userName, $secpasswd)
Add-AzureAccount -Credential $cred

Select-AzureSubscription -SubscriptionName $subscriptionName -Current

#Variables settings.  passes it as pure strings
if ($switchOffString -eq "1")
{
    $switchOff = $True
}
else
{
    $switchOff = $False
}
if ($useResourceManagerString -eq "1")
{
    $useResourceManager = $True
}
else
{
    $useResourceManager = $False
}

if ($useResourceManager)
{
    Switch-AzureMode AzureResourceManager
}
else
{
    Switch-AzureMode AzureServiceManagement
}
$vmList = Get-AzureVM
Write-Output "Number of  found in subscription: [$($vmList.Count)]"

$separator = ";",","
$option = [System.StringSplitOptions]::RemoveEmptyEntries
$machineNamesArray = $machineNames.Split($separator,$option)

foreach($entry in $machineNamesArray)
{
    $vm =  $vmList | where Name -eq $entry
    if ($switchOff)
    {
        Write-Output "Stopping VM [$($entry)]"
        $vm | Stop-AzureVM -Force
    }
    else
    {
        Write-Output "Starting VM [$($entry)]"
        $vm | Start-AzureVM
    }
}

Интеграция с Teamcity:

Так как у меня много машин, сгрупированных по разным подпискам, то, чтобы не мучаться, я создал темплейт, состоящий из одного шага с Powershell:

(в поле Script arguments: -userName %username% -password %password% -switchOffString %switchOff% -useResourceManagerString %useResourceManager% -subscriptionName %subscriptionName% %machineNames%)

Соотвественно, для каждого события (включение и выключении машин в подписке)нужно создать два билда (Включить и выключить) с параметрами как на скриншоте:

Параметры:

  • machineNames – имена машин, разделенные точкой с запятой (если есть пробелы – надо имя брать в кавычки)
  • password – пароль от администратора или ко-администратора подписки
  • subscriptionName – имя подписки (если есть пробелы – в кавычках)
  • switchOff – 1, если надо выключать, и 0, если надо включать
  • useResourceManager – если виртуалные машины развернуты в v2, то 1, если нет – то 0
  • username – имя администратора или ко-администратора подписки

Скрипт для включения/выключения веб приложений:

#Switched Off or On set of VMs, passed as parameters
#Example usage: .\SwitchWebAppOnOff.ps1 username password 1 "some subscription name" "some-vm0";"some-vm1";"some-vm2"
#where
#username - user with co-administrator rights on subscription
#password - password for this user
#1 - boolean, if machine shall be switched off
#some sbuscription name - name of subscrtion
#"some-vm0";"some-vm1";"some-vm2" - webapps to switch off

param(
    [string]$userName,
    [string]$password,
    [string]$switchOffString,
    [string]$subscriptionName,
    [string]$webAppsNames
)

$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($userName, $secpasswd)
Add-AzureAccount -Credential $cred

Select-AzureSubscription -SubscriptionName $subscriptionName -Current

#Variables settings. Teamcity passes it as pure strings
if ($switchOffString -eq "1")
{
    $switchOff = $True
}
else
{
    $switchOff = $False
}

$webAppsList = Get-AzureWebsite
Write-Output "Number of Web Apps found in subscription: [$($webAppsList.Count)]"

$separator = ";",","
$option = [System.StringSplitOptions]::RemoveEmptyEntries
$webAppsNamesArray = $webAppsNames.Split($separator,$option)

foreach($entry in $webAppsNamesArray)
{
    $webApp =  $webAppsList | where Name -eq $entry
    if ($switchOff)
    {
        Write-Output "Stopping WebApp [$($entry)]"
        $webApp | Stop-AzureWebsite
    }
    else
    {
        Write-Output "Starting WebApp [$($entry)]"
        $webApp | Start-AzureWebsite
    }
}

Тут тимплейт не отличается, просто поле Script Arguments содержит меньше параметров, так как нам не надо менять AzureMode:
-userName %username% -password %password% -switchOffString %switchOff% -subscriptionName %subscriptionName% %webAppsNames%

webAppsNames – строка, разделенная точками с запятой, также, как и machineNames

В качестве триггера для обоих билдов (включение/выключение) – я использую Schedule trigger по крону.
Выключение: Cron command: 0 30 21 ? * 2-6 *

Включение: Cron command: 0 30 8 ? * 2-6 *