通过Azure DevOps Pipeline+Terraform创建VM并部署Java失败求助
解决方案:Terraform Azure Windows VM WinRM连接超时问题
核心问题拆解
你的问题根源集中在三点:
- Windows VM默认未启用WinRM远程管理及防火墙入站规则
- 用私有IP作为WinRM连接地址,若Azure DevOps Pipeline Agent不在同VNet则无法访问
- 动态公网IP字段未正确填充,导致无法用公网IP建立连接
分步解决
1. 预配置WinRM(关键)
不要依赖手动配置,在Terraform中通过虚拟机扩展自动初始化WinRM,确保VM启动后立即可用:
resource "azurerm_virtual_machine_extension" "winrm_config" { name = "WinRM-Config" virtual_machine_id = azurerm_windows_virtual_machine.vm.id publisher = "Microsoft.Compute" type = "CustomScriptExtension" type_handler_version = "1.10" settings = jsonencode({ commandToExecute = "powershell.exe -ExecutionPolicy Bypass -Command \"& { winrm quickconfig -q; winrm set winrm/config/service '@{AllowUnencrypted=\"true\"}'; winrm set winrm/config/service/auth '@{Basic=\"true\"}'; netsh advfirewall firewall set rule group=\"Windows Remote Management\" new enable=yes }\"" }) depends_on = [azurerm_windows_virtual_machine.vm] }
这段脚本会完成:
- 一键配置WinRM服务
- 允许非加密连接(测试场景用,生产建议改用HTTPS 5986端口)
- 启用Basic认证(匹配Terraform的WinRM连接配置)
- 开启防火墙WinRM入站规则组
2. 修正WinRM连接地址
放弃私有IP,改用公网IP连接(除非Pipeline Agent部署在同VNet内)。针对公网IP字段未填充的问题,确保资源关联和依赖正确:
# 创建动态公网IP resource "azurerm_public_ip" "vm_pip" { name = "vm-pip" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name allocation_method = "Dynamic" } # 网卡配置关联公网IP resource "azurerm_network_interface" "nic" { name = "vm-nic" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "internal" subnet_id = azurerm_subnet.subnet.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.vm_pip.id } } # VM关联网卡,添加依赖确保公网IP就绪 resource "azurerm_windows_virtual_machine" "vm" { name = "windows-vm" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location size = "Standard_D2s_v3" admin_username = var.admin_username admin_password = var.admin_password network_interface_ids = [azurerm_network_interface.nic.id] depends_on = [azurerm_public_ip.vm_pip] }
3. 修正Terraform Provisioner配置
用公网IP作为WinRM连接地址,添加超时设置,并依赖WinRM扩展执行完成:
resource "azurerm_windows_virtual_machine" "vm" { # ... 保留上述VM基础配置 ... # 上传Java安装脚本 provisioner "file" { source = "java.ps1" destination = "C:\\temp\\java.ps1" connection { type = "winrm" user = var.admin_username password = var.admin_password host = azurerm_public_ip.vm_pip.ip_address port = 5985 timeout = "10m" https = false insecure = true } depends_on = [azurerm_virtual_machine_extension.winrm_config] } # 执行Java安装脚本 provisioner "remote-exec" { inline = [ "powershell.exe -ExecutionPolicy Bypass -File C:\\temp\\java.ps1" ] connection { type = "winrm" user = var.admin_username password = var.admin_password host = azurerm_public_ip.vm_pip.ip_address port = 5985 timeout = "10m" https = false insecure = true } depends_on = [azurerm_virtual_machine_extension.winrm_config] } }
4. 验证NSG规则
确保网络安全组开放5985端口:
resource "azurerm_network_security_group" "nsg" { name = "vm-nsg" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name security_rule { name = "WinRM-HTTP" priority = 1001 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "5985" source_address_prefix = "*" # 生产环境建议限制为Pipeline Agent的IP段 destination_address_prefix = "*" } }
关键注意事项
- 生产环境禁止使用Basic认证和非加密连接,建议配置WinRM HTTPS(5986端口)并导入SSL证书
- 若Pipeline Agent部署在Azure同VNet内,可继续使用私有IP,但需确保Agent能访问VM的私有网络
- 公网IP的
ip_address字段需等资源完全创建后才会填充,depends_on能强制Terraform等待资源就绪
内容的提问来源于stack exchange,提问作者lcs
相关产品推荐
相关产品推荐

