如何在单个Packer Azure-Arm模板中同时构建VHD和托管镜像?
问题:同一Packer模板同时支持构建VHD和Managed Image
我正在学习Packer,目前通过注释代码的不同部分可分别生成Managed Image和VHD,但同时配置两者输出参数时会触发报错:
Error: 2 error(s) occurred: * Either a VHD or a managed image can be built, but not both. Please specify either capture_container_name and capture_name_prefix or managed_image_resource_group_name and managed_image_name. * Specify either a VHD (storage_account and resource_group_name) or Managed Image (managed_image_resource_group_name and managed_image_name) output on windows_server2019.pkr.hcl line 10: (source code not available) ==> Wait completed after 0 seconds ==> Builds finished but no artifacts were created.
我的模板代码如下:
packer { required_plugins { windows-update = { version = "0.14.1" source = "github.com/rgl/windows-update" } } } source "azure-arm" "server_2019" { use_azure_cli_auth = true azure_tags = local.tags build_resource_group_name = var.resource_group_name build_key_vault_name = "EXAMPLE-RGP-${var.environment}-KVT" os_type = local.azure_sku.os_type image_publisher = local.azure_sku.image_publisher image_offer = local.azure_sku.image_offer image_sku = local.azure_sku.image_sku vm_size = local.azure_sku.vm_size shared_gallery_image_version_exclude_from_latest = false virtual_network_resource_group_name = local.network.virtual_network_resource_group_name virtual_network_name = local.network.virtual_network_name virtual_network_subnet_name = local.network.virtual_network_subnet_name private_virtual_network_with_public_ip = false communicator = "winrm" winrm_use_ssl = true winrm_insecure = true winrm_timeout = "3m" winrm_username = "winrm" winrm_password = var.winrm_password # VHD (Both VHD and Managed image can't be done at the same time, comment one of them out) resource_group_name = var.resource_group_name storage_account = lower("examplestorage${var.environment}blobevgimg") capture_container_name = "evergreen-images" capture_name_prefix = "packer_server2019" # Managed Image (Both VHD and Managed image can't be done at the same time, comment one of them out) managed_image_name = "packer_server2019" managed_image_resource_group_name = var.resource_group_name managed_image_storage_account_type = "Standard_LRS" shared_image_gallery_destination { resource_group = var.resource_group_name gallery_name = upper("GALLERY${var.environment}EVERGREENIMAGES") image_name = "Evergreen-Images-Windows" image_version = formatdate("YYYY.MM.DD", timestamp()) replication_regions = ["australiaeast", "australiasoutheast"] storage_account_type = "Standard_ZRS" } } build { sources = [ "sources.azure-arm.server_2019", ] provisioner "file" { source = "../scripts/ConfigureRemotingForAnsible.ps1" destination = "C:\\temp\\ConfigureRemotingForAnsible.ps1" } provisioner "windows-update" { search_criteria = "IsInstalled=0" filters = [ "exclude:$_.Title -like '*Preview*'", "include:$true", ] update_limit = 25 } }
我知道可通过拆分模板文件并单独调用CLI实现,但想了解是否有方法能在同一个模板文件中同时支持构建VHD和Managed Image?
解决方案
可以通过变量+条件配置的方式在同一个模板中实现两种输出类型的切换,无需拆分文件,以下是两种可行方案:
方案一:单Source块+条件参数赋值
通过定义变量控制输出类型,在Source块中对VHD和Managed Image的参数进行条件赋值,不生效的参数设为null(Packer会自动忽略null参数)。
修改后的模板示例:
packer { required_plugins { windows-update = { version = "0.14.1" source = "github.com/rgl/windows-update" } } } # 新增变量:指定输出类型,可选vhd或managed_image variable "output_type" { type = string description = "指定构建输出类型,可选值: vhd, managed_image" default = "managed_image" } source "azure-arm" "server_2019" { use_azure_cli_auth = true azure_tags = local.tags build_resource_group_name = var.resource_group_name build_key_vault_name = "EXAMPLE-RGP-${var.environment}-KVT" os_type = local.azure_sku.os_type image_publisher = local.azure_sku.image_publisher image_offer = local.azure_sku.image_offer image_sku = local.azure_sku.image_sku vm_size = local.azure_sku.vm_size shared_gallery_image_version_exclude_from_latest = false virtual_network_resource_group_name = local.network.virtual_network_resource_group_name virtual_network_name = local.network.virtual_network_name virtual_network_subnet_name = local.network.virtual_network_subnet_name private_virtual_network_with_public_ip = false communicator = "winrm" winrm_use_ssl = true winrm_insecure = true winrm_timeout = "3m" winrm_username = "winrm" winrm_password = var.winrm_password # VHD 配置:仅当output_type为vhd时生效 resource_group_name = var.output_type == "vhd" ? var.resource_group_name : null storage_account = var.output_type == "vhd" ? lower("examplestorage${var.environment}blobevgimg") : null capture_container_name = var.output_type == "vhd" ? "evergreen-images" : null capture_name_prefix = var.output_type == "vhd" ? "packer_server2019" : null # Managed Image 配置:仅当output_type为managed_image时生效 managed_image_name = var.output_type == "managed_image" ? "packer_server2019" : null managed_image_resource_group_name = var.output_type == "managed_image" ? var.resource_group_name : null managed_image_storage_account_type = var.output_type == "managed_image" ? "Standard_LRS" : null # 共享镜像库配置:仅当构建Managed Image时生效 dynamic "shared_image_gallery_destination" { for_each = var.output_type == "managed_image" ? [true] : [] content { resource_group = var.resource_group_name gallery_name = upper("GALLERY${var.environment}EVERGREENIMAGES") image_name = "Evergreen-Images-Windows" image_version = formatdate("YYYY.MM.DD", timestamp()) replication_regions = ["australiaeast", "australiasoutheast"] storage_account_type = "Standard_ZRS" } } } build { sources = [ "sources.azure-arm.server_2019", ] provisioner "file" { source = "../scripts/ConfigureRemotingForAnsible.ps1" destination = "C:\\temp\\ConfigureRemotingForAnsible.ps1" } provisioner "windows-update" { search_criteria = "IsInstalled=0" filters = [ "exclude:$_.Title -like '*Preview*'", "include:$true", ] update_limit = 25 } }
运行方式:
- 构建VHD:
packer build -var "output_type=vhd" windows_server2019.pkr.hcl - 构建Managed Image:
packer build -var "output_type=managed_image" windows_server2019.pkr.hcl
方案二:多Source块+变量选择构建目标
定义两个独立的Source块,分别对应VHD和Managed Image的配置,通过变量控制Build块中要运行的Source。
修改后的模板示例:
packer { required_plugins { windows-update = { version = "0.14.1" source = "github.com/rgl/windows-update" } } } # 新增变量:选择构建目标 variable "build_target" { type = string description = "选择构建目标,可选值: vhd, managed_image" default = "managed_image" } # 用于VHD构建的Source块 source "azure-arm" "server_2019_vhd" { use_azure_cli_auth = true azure_tags = local.tags build_resource_group_name = var.resource_group_name build_key_vault_name = "EXAMPLE-RGP-${var.environment}-KVT" os_type = local.azure_sku.os_type image_publisher = local.azure_sku.image_publisher image_offer = local.azure_sku.image_offer image_sku = local.azure_sku.image_sku vm_size = local.azure_sku.vm_size shared_gallery_image_version_exclude_from_latest = false virtual_network_resource_group_name = local.network.virtual_network_resource_group_name virtual_network_name = local.network.virtual_network_name virtual_network_subnet_name = local.network.virtual_network_subnet_name private_virtual_network_with_public_ip = false communicator = "winrm" winrm_use_ssl = true winrm_insecure = true winrm_timeout = "3m" winrm_username = "winrm" winrm_password = var.winrm_password # VHD专属配置 resource_group_name = var.resource_group_name storage_account = lower("examplestorage${var.environment}blobevgimg") capture_container_name = "evergreen-images" capture_name_prefix = "packer_server2019" } # 用于Managed Image构建的Source块 source "azure-arm" "server_2019_managed_image" { use_azure_cli_auth = true azure_tags = local.tags build_resource_group_name = var.resource_group_name build_key_vault_name = "EXAMPLE-RGP-${var.environment}-KVT" os_type = local.azure_sku.os_type image_publisher = local.azure_sku.image_publisher image_offer = local.azure_sku.image_offer image_sku = local.azure_sku.image_sku vm_size = local.azure_sku.vm_size shared_gallery_image_version_exclude_from_latest = false virtual_network_resource_group_name = local.network.virtual_network_resource_group_name virtual_network_name = local.network.virtual_network_name virtual_network_subnet_name = local.network.virtual_network_subnet_name private_virtual_network_with_public_ip = false communicator = "winrm" winrm_use_ssl = true winrm_insecure = true winrm_timeout = "3m" winrm_username = "winrm" winrm_password = var.winrm_password # Managed Image专属配置 managed_image_name = "packer_server2019" managed_image_resource_group_name = var.resource_group_name managed_image_storage_account_type = "Standard_LRS" shared_image_gallery_destination { resource_group = var.resource_group_name gallery_name = upper("GALLERY${var.environment}EVERGREENIMAGES") image_name = "Evergreen-Images-Windows" image_version = formatdate("YYYY.MM.DD", timestamp()) replication_regions = ["australiaeast", "australiasoutheast"] storage_account_type = "Standard_ZRS" } } build { # 根据变量选择要运行的Source sources = var.build_target == "vhd" ? ["sources.azure-arm.server_2019_vhd"] : ["sources.azure-arm.server_2019_managed_image"] provisioner "file" { source = "../scripts/ConfigureRemotingForAnsible.ps1" destination = "C:\\temp\\ConfigureRemotingForAnsible.ps1" } provisioner "windows-update" { search_criteria = "IsInstalled=0" filters = [ "exclude:$_.Title -like '*Preview*'", "include:$true", ] update_limit = 25 } }
运行方式:
- 构建VHD:
packer build -var "build_target=vhd" windows_server2019.pkr.hcl - 构建Managed Image:
packer build -var "build_target=managed_image" windows_server2019.pkr.hcl
内容的提问来源于stack exchange,提问作者philthy
相关产品推荐
相关产品推荐

