You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Terraform实现Azure虚拟机非工作时段自动启停?

How to Implement Azure VM Auto-Start/Stop During Off-Hours with Terraform

Let me start by clearing up that earlier misconception: you absolutely can build this auto-start/stop workflow with Terraform. The claim that runbook parameters block this isn’t true—we just need to properly configure the right automation resources, runbooks, variables, and schedules together. I’ve implemented this exact setup for multiple clients, so let’s walk through a working, modular solution that matches what you’ve used in the Azure portal.

Core Prerequisites

  • Make sure you’re using the latest azurerm Terraform provider (v3.x+ recommended)
  • You’ll need permissions to create Automation Accounts, Runbooks, Variables, and Job Schedules in your Azure subscription
  • Grab the pre-built PowerShell runbook code for starting/stopping VMs from the Azure portal’s Runbook Gallery (search for "Start Azure VMs" and "Stop Azure VMs" to copy their code)

Terraform Configuration Breakdown

Step 1: Create the Automation Account & Resource Group

This is the foundation for hosting all your scheduling resources:

resource "azurerm_resource_group" "automation_rg" {
  name     = "vm-auto-schedule-rg"
  location = "eastus" # Swap with your preferred region
}

resource "azurerm_automation_account" "vm_scheduler" {
  name                = "vm-start-stop-automation"
  location            = azurerm_resource_group.automation_rg.location
  resource_group_name = azurerm_resource_group.automation_rg.name
  sku_name            = "Basic" # Basic tier is fully sufficient for this use case
}

Step 2: Deploy the Start/Stop Runbooks

Instead of linking to external galleries (to avoid external dependencies), we’ll use local script files. Create a scripts folder in your Terraform workspace, paste the official runbook code into Start-AzureVMs.ps1 and Stop-AzureVMs.ps1, then reference them in Terraform:

# Stop VMs Runbook
resource "azurerm_automation_runbook" "stop_vms" {
  name                = "StopVMs"
  location            = azurerm_resource_group.automation_rg.location
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  runbook_type        = "PowerShell"
  content             = file("./scripts/Stop-AzureVMs.ps1")
}

# Start VMs Runbook
resource "azurerm_automation_runbook" "start_vms" {
  name                = "StartVMs"
  location            = azurerm_resource_group.automation_rg.location
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  runbook_type        = "PowerShell"
  content             = file("./scripts/Start-AzureVMs.ps1")
}

Step 3: Configure Runbook Parameters with Automation Variables

The runbooks need details like which VMs to target and your subscription ID. Storing these as Automation Variables makes them easy to update later without modifying runbook code:

# Comma-separated list of VM resource IDs to manage
resource "azurerm_automation_variable_string" "target_vms" {
  name                = "TargetVMs"
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  value               = "/subscriptions/your-sub-id/resourceGroups/vm-rg/providers/Microsoft.Compute/virtualMachines/vm1,/subscriptions/your-sub-id/resourceGroups/vm-rg/providers/Microsoft.Compute/virtualMachines/vm2"
  description         = "List of VMs to start/stop (comma-separated resource IDs)"
}

# Your Azure Subscription ID
resource "azurerm_automation_variable_string" "subscription_id" {
  name                = "SubscriptionID"
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  value               = "your-subscription-id"
}

Now we’ll set up daily schedules for off-hours stops (e.g., 7 PM local time) and morning starts (e.g., 7 AM local time). Adjust the time zone and start time to match your team’s working hours:

# Daily schedule to stop VMs at 7 PM Eastern Time
resource "azurerm_automation_schedule" "stop_vms_schedule" {
  name                = "StopVMs-Daily-1900EST"
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  frequency           = "Day"
  interval            = 1
  start_time          = "2024-01-01T19:00:00Z" # Convert local time to UTC if needed
  time_zone           = "Eastern Standard Time"
}

# Daily schedule to start VMs at 7 AM Eastern Time
resource "azurerm_automation_schedule" "start_vms_schedule" {
  name                = "StartVMs-Daily-0700EST"
  resource_group_name = azurerm_resource_group.automation_rg.name
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  frequency           = "Day"
  interval            = 1
  start_time          = "2024-01-01T07:00:00Z"
  time_zone           = "Eastern Standard Time"
}

# Link stop schedule to the StopVMs runbook with parameters
resource "azurerm_automation_job_schedule" "stop_vms_job" {
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  resource_group_name     = azurerm_resource_group.automation_rg.name
  runbook_name            = azurerm_automation_runbook.stop_vms.name
  schedule_name           = azurerm_automation_schedule.stop_vms_schedule.name

  parameters = {
    "VMResourceIDs"   = azurerm_automation_variable_string.target_vms.value
    "SubscriptionID"  = azurerm_automation_variable_string.subscription_id.value
  }
}

# Link start schedule to the StartVMs runbook with parameters
resource "azurerm_automation_job_schedule" "start_vms_job" {
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  resource_group_name     = azurerm_resource_group.automation_rg.name
  runbook_name            = azurerm_automation_runbook.start_vms.name
  schedule_name           = azurerm_automation_schedule.start_vms_schedule.name

  parameters = {
    "VMResourceIDs"   = azurerm_automation_variable_string.target_vms.value
    "SubscriptionID"  = azurerm_automation_variable_string.subscription_id.value
  }
}

Critical Post-Deployment Step: Grant Permissions

Your Automation Account needs permission to manage VMs. Create a system-assigned managed identity for the account, then assign the Virtual Machine Contributor role to it:

# Enable system-assigned managed identity for the Automation Account
resource "azurerm_automation_account_identity" "vm_scheduler_identity" {
  automation_account_name = azurerm_automation_account.vm_scheduler.name
  resource_group_name     = azurerm_resource_group.automation_rg.name
  type                    = "SystemAssigned"
}

# Assign VM Contributor role to the identity
resource "azurerm_role_assignment" "automation_vm_access" {
  scope                = "/subscriptions/your-sub-id" # Limit to specific resource groups if preferred
  role_definition_name = "Virtual Machine Contributor"
  principal_id         = azurerm_automation_account_identity.vm_scheduler_identity.principal_id
}

Troubleshooting Tips

  • Test Runbooks First: After applying the config, manually trigger the runbooks from the Azure portal to verify they can start/stop your VMs before relying on the schedule.
  • Parameter Names: Double-check that the parameter names in your azurerm_automation_job_schedule match exactly what the runbook expects (you can view these in the runbook’s "Parameters" tab in the portal).
  • Time Zone Gotchas: Ensure your start_time aligns with the time_zone you set—use UTC as a fallback if you’re unsure about time zone conversions.

Alternative: Deploy the Full Portal Solution via Terraform

If you want to replicate the exact dashboard and pre-configured resources from the portal’s Start/Stop solution, you can use Terraform to deploy the official ARM template. Save the template content from Azure’s documentation as a local JSON file, then use:

resource "azurerm_resource_group_template_deployment" "vm_start_stop_solution" {
  name                = "vm-start-stop-solution"
  resource_group_name = azurerm_resource_group.automation_rg.name
  template_content    = file("./start-stop-vms-solution.json")

  parameters = {
    "automationAccountName" = azurerm_automation_account.vm_scheduler.name
    "vmList"                = azurerm_automation_variable_string.target_vms.value
    "stopTime"              = "19:00"
    "startTime"             = "07:00"
    "timeZone"              = "Eastern Standard Time"
    "enableSchedule"        = "true"
  }
}

内容的提问来源于stack exchange,提问作者atefeh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 13:03:12