1. 概述

作为Windows Azure的用户,使用Azure的过程中,最担心的事情就是还没到月底,预设的费用就快消耗完了(下面两张账单图是我最讨厌看到的)。但是仔细分析自己的费用列表,发现绝大部分费用消耗在虚拟机上,而Azure的虚拟机是按照开机时间来计费的,因此迫切需要找到一个方案来节省虚拟机的开销。最简单的方案就是在不需要的时候将虚拟机自动关闭,需要的时间让其自动开机。在Google了一通以后,发现可以通过Azure的自动化(Automation)功能达到上述目的。下面介绍我在Azure上的实践,通过设置Azure Automation,实现定时自动启动和关闭虚拟机。

Azure 添加member azure authoring_Azure

 

Azure 添加member azure authoring_IIS_02

2. 必要条件

1. Windows Azure的订阅账户

2. 在Azure中有可以正常启动和关闭的虚拟机。可以参考这个链接创建一个虚拟机https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-tutorial/ 

3. 创建自动化账户 Automation

按照Azure的描述,Automation自动化账户是自动化资源的容器,使用Automation自动化账户可以将自动化的资源与分配给其他自动化账户的资源隔离。如果你从未在Azure订阅中创建过自动化账户,参考下面介绍创建一个:

Azure 添加member azure authoring_IIS_03

Azure 添加member azure authoring_Azure 添加member_04

4. 创建和管理证书

4.1 在IIS中创建证书

在Azure订阅中运行自动化的任务(脚本),需要使用基于证书的认证。你可以使用第三方的商业证书,也可以在任意一台安装了Internet Infomation Services (IIS)的服务器上创建一个证书。下面介绍如何在Windows Server 2012中使用IIS创建一个自签名的证书:

Azure 添加member azure authoring_Machine_05

Azure 添加member azure authoring_Azure 添加member_06

Azure 添加member azure authoring_IIS_07

4.2 从IIS中导出.pfx证书

Azure 添加member azure authoring_Azure 添加member_08

Azure 添加member azure authoring_IIS_09

4.3 从IIS中导出.cer证书

Azure 添加member azure authoring_Azure 添加member_10

Azure 添加member azure authoring_Machine_11

Azure 添加member azure authoring_Azure_12

Azure 添加member azure authoring_Machine_13

Azure 添加member azure authoring_IIS_14

Azure 添加member azure authoring_Machine_15

4.4 将.cer证书上传到订阅账户

Azure 添加member azure authoring_Azure_16

Azure 添加member azure authoring_IIS_17

5. 配置自动化脚本

  5.1 配置资产,准备自动化脚本运行过程中需要的素材

Azure 添加member azure authoring_Azure_18

Azure 添加member azure authoring_IIS_19

Azure 添加member azure authoring_Azure_20

Azure 添加member azure authoring_Azure 添加member_21

Azure 添加member azure authoring_Azure 添加member_22

(上传之前导出的.pfx证书)

Azure 添加member azure authoring_Machine_23

Azure 添加member azure authoring_Azure_24

Azure 添加member azure authoring_Azure_25

(自动化证书名称需要使用证书在IIS中的友好名称;订阅ID可以在Azure的设置中查询到)

5.2 配置自动化脚本

Runbook是执行自动化操作的脚本。可以通过左下角的“新建”按钮从脚本库中快速创建一个脚本,也可以完全自定义一个脚本:

Azure 添加member azure authoring_Azure 添加member_26

Azure 添加member azure authoring_Azure_27

(创建好脚本后,选择脚本,进入编辑页面)

Azure 添加member azure authoring_Azure_28

Azure 添加member azure authoring_IIS_29

(在“创作”中编辑自动化运行的脚本,脚本如下,其中高亮部分是需要根据实际情况修改的内容:)

workflow Start-VM-danzhang-win7            
{             
    param()             
    #connection       
       $MyConnection = "AzureConnection-1"             
       $MyCert = "AutomationCredential-1"             
  
    # Get the Azure Automation Connection             
    $Con = Get-AutomationConnection -Name $MyConnection             
    if ($Con -eq $null)             
    {             
        Write-Output "Connection entered: $MyConnection does not exist in the automation service. Please create one `n"   
    }             
    else             
    {             
        $SubscriptionID = $Con.SubscriptionID             
        $ManagementCertificate = $Con.AutomationCertificateName             
       
    }       # Get Certificate & print out its properties            
    $Cert = Get-AutomationCertificate -Name $MyCert             
    if ($Cert -eq $null)             
    {             
        Write-Output "Certificate entered: $MyCert does not exist in the automation service. Please create one `n"   
    }             
    else             
    {             
        $Thumbprint = $Cert.Thumbprint             
    }        #Set and Select the Azure Subscription            
         Set-AzureSubscription `             
            -SubscriptionName "My Azure Subscription" `             
            -Certificate $Cert `             
            -SubscriptionId $SubscriptionID `        #Select Azure Subscription            
         Select-AzureSubscription `             
            -SubscriptionName "My Azure Subscription"
    Write-Output "-------------------------------------------------------------------------"       Write-Output "Starting the VM.."
       # Please type the name of your Domain Controllers
    
    inlinescript{             
   
# function to get local time (example Convert UTC tome to Indian Time Zone)             
Function Get-LocalTime($UTCTime)             
{             
$strCurrentTimeZone = 'India Standard Time'             
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)             
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)             
Return $LocalTime             
}#convert date time to UTC time Zone            
$date = (Get-Date).ToUniversalTime()             
# call function to get local time             
$locatTime= Get-LocalTime($date)             
#get day of week eg. Friday             
$locatTimeDayOfWeek= ($locatTime).DayOfWeek             
#get current day of the date eg. if current date is 21 November 2014 09:55:18 then day will be 21             
$localTimeDay= ($locatTime).Day#$locatTimeDayOfWeek            
#$localTimeDay
#do not start VM on saturday and Sunday if($locatTimeDayOfWeek -ne "Saturday" -and $locatTimeDayOfWeek -ne "Sunday")            
{             
#$sample = Get-AzureWinRMUri -ServiceName $Using:CloudServiceName -Name $Using:VMName             
$StartOutPut = Start-AzureVM -ServiceName "danzhang-win7" -Name "danzhang-win7"             
Write-Output $"Virtual Machine danzhang-win7 started."             
Write-Output $StartOutPut }            
elseif($localTimeDay -le 7 -and $locatTimeDayOfWeek -eq "Saturday")             
{             
$StartOutPut = Start-AzureVM -ServiceName "danzhang-win7" -Name "danzhang-win7" Write-Output $"Virtual Machine danzhang-win7 started."             
Write-Output $StartOutPut             
}             
else{             
Write-Output "Virtual Machine is not started, because today is not a working day."             
}             
}             
       
}

Azure 添加member azure authoring_Azure_30

(保存并点击“测试”按钮运行脚本)

Azure 添加member azure authoring_Azure 添加member_31

(如果脚本正确,你会在输出窗口中看到成功的提示,同时看到虚拟机已经启动了;点击“发布”按钮发布脚本)

创建关闭虚拟机脚本的过程与上面完全一致,脚本的内容参考下表:

workflow Stop-VM-danzhang-win7            
{             
    param()             
    #connection             
       $MyConnection = "AzureConnection-1"             
       $MyCert = "AutomationCredential-1"             
       
    # Get the Azure Automation Connection             
    $Con = Get-AutomationConnection -Name $MyConnection             
    if ($Con -eq $null)             
    {             
        Write-Output "Connection entered: $MyConnection does not exist in the automation service. Please create one `n"   
    }             
    else             
    {             
        $SubscriptionID = $Con.SubscriptionID             
        $ManagementCertificate = $Con.AutomationCertificateName             
       
    }       # Get Certificate & print out its properties            
    $Cert = Get-AutomationCertificate -Name $MyCert             
    if ($Cert -eq $null)             
    {             
        Write-Output "Certificate entered: $MyCert does not exist in the automation service. Please create one `n"   
    }             
    else             
    {             
        $Thumbprint = $Cert.Thumbprint             
    }        #Set and Select the Azure Subscription            
         Set-AzureSubscription `             
            -SubscriptionName "My Azure Subscription" `             
            -Certificate $Cert `             
            -SubscriptionId $SubscriptionID `        #Select Azure Subscription            
         Select-AzureSubscription `             
            -SubscriptionName "My Azure Subscription"
    Write-Output "-------------------------------------------------------------------------"       Write-Output "Stoping the VM.."
       # Please type the name of your Domain Controllers
    
    inlinescript{             
   
# function to get local time (example Convert UTC tome to Indian Time Zone)             
Function Get-LocalTime($UTCTime)             
{             
$strCurrentTimeZone = 'India Standard Time'             
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)             
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)             
Return $LocalTime             
}#convert date time to UTC time Zone            
$date = (Get-Date).ToUniversalTime()             
# call function to get local time             
$locatTime= Get-LocalTime($date)             
#get day of week eg. Friday             
$locatTimeDayOfWeek= ($locatTime).DayOfWeek             
#get current day of the date eg. if current date is 21 November 2014 09:55:18 then day will be 21             
$localTimeDay= ($locatTime).Day#$locatTimeDayOfWeek            
#$localTimeDay
#do not start VM on saturday and Sunday if($locatTimeDayOfWeek -ne "Saturday" -and $locatTimeDayOfWeek -ne "Sunday")            
{ 
#$StopOutPut = Start-AzureVM -ServiceName "mkadamvm" -Name $Using:test 
#$sample = Get-AzureWinRMUri -ServiceName $Using:CloudServiceName -Name $Using:VMName
$StopOutPut = Stop-AzureVM -ServiceName "danzhang-win7" -Name "danzhang-win7" -Force            
Write-Output $"Virtual Machine danzhang-win7 Stopped."             
Write-Output $StopOutPut}            
elseif($localTimeDay -le 7 -and $locatTimeDayOfWeek -eq "Saturday")             
{             
$StopOutPut = Stop-AzureVM -ServiceName "danzhang-win7" -Name "danzhang-win7" -Force Write-Output $"Virtual Machine danzhang-win7 Stopped."            
Write-Output $StartOutPut             
}             
else{             
Write-Output "Virtual Machine is not started, because today is not a working day."             
}             
}             
}

  5.3配置日程,实现定时运行脚本

脚本调试成功以后,就可以通过“计划日程”定期运行脚本,以实现定期启动和关机的目标。

Azure 添加member azure authoring_Azure_32

Azure 添加member azure authoring_Azure_33

Azure 添加member azure authoring_Azure 添加member_34

(注意这里的时间是20小时格式的,并且你不需要考虑时区,系统会自动按照你本地的时区做转换)

可以按照上面的操作,设置关闭虚拟机的时间。

  ALM MVP 张洪君