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

如何实现每次执行pulumi up时新建VM而非更新现有虚拟机?

一、修改Pulumi脚本实现每次pulumi up新建VM

原脚本的核心问题是资源的逻辑ID(vsphere.VirtualMachine的第一个参数"pulumi-vm")和VM名称'pulumi-vm'固定,Pulumi会将其识别为同一资源,因此每次执行只会更新而非创建新VM。要解决这个问题,需要为每次创建的VM生成唯一标识,以下是修改后的脚本:

import pulumi
import pulumi_vsphere as vsphere
import pulumi_random as random

# 生成6位随机字符串作为唯一后缀,确保每次运行资源标识不同
unique_suffix = random.RandomString("vm-suffix",
    length=6,
    special=False,
    upper=False,
).result

# vSphere资源配置
datastore_name = 'roels-bart'
network_name = 'VM Network'
resource_pool_name = 'test'
datacenter_name = 'StudentDC'
template_name = 'CleanUbuntu'

# 查询vSphere基础资源
datacenter = vsphere.get_datacenter(name=datacenter_name)
datastore = vsphere.get_datastore(name="roels-bart", datacenter_id=datacenter.id)
network = vsphere.get_network(name="VM Network", datacenter_id=datacenter.id)
pool = vsphere.get_resource_pool(name="Resources", datacenter_id=datacenter.id)
template = vsphere.get_virtual_machine(name="CleanUbuntu", datacenter_id=datacenter.id)

# 构建带唯一后缀的资源ID和VM名称
vm_resource_id = pulumi.Output.concat('pulumi-vm-', unique_suffix)
vm_name = pulumi.Output.concat('pulumi-vm-', unique_suffix)

# 创建新虚拟机
virtual_machine = vsphere.VirtualMachine(vm_resource_id,
    name=vm_name,
    datastore_id=datastore.id,
    resource_pool_id=pool.id,
    num_cpus=1,
    memory=1024,
    guest_id='ubuntu64Guest',
    scsi_type='pvscsi',
    network_interfaces=[{
        'network_id': network.id,
        'adapter_type': 'vmxnet3',
    }],
    clone={
        'template_uuid': template.id,
    },
    disks=[
        {
            'label': 'disk0',
            'size': 20,
            'eagerly_scrub': False,
            'thin_provisioned': True,
        },
    ],
)

# 导出VM属性
pulumi.export('vm_name', virtual_machine.name)
pulumi.export('vm_id', virtual_machine.id)

关键修改点:

  • 引入pulumi_random模块生成随机字符串作为唯一后缀,避免资源标识重复
  • 将VM的逻辑ID和名称都设置为带唯一后缀的值,确保Pulumi每次都识别为新资源
  • 使用pulumi.Output.concat处理动态生成的字符串,符合Pulumi异步输出特性

二、Flask应用中运行Pulumi的最佳实践

推荐使用Pulumi Automation API实现Web界面触发VM创建,这是官方支持的从应用内调用Pulumi的可靠方式,替代命令行调用。以下是核心建议:

1. 基础实现示例

from flask import Flask, request, jsonify
from pulumi import automation as auto

app = Flask(__name__)

@app.route('/create-vm', methods=['POST'])
def create_vm():
    # 获取用户输入参数
    params = request.json
    vm_name = params.get('vm_name', f'web-vm-{auto.utils.random_name()}')
    num_cpus = params.get('num_cpus', 1)
    memory = params.get('memory', 1024)

    def pulumi_program():
        # 复用vSphere资源查询与VM创建逻辑,替换为用户参数
        import pulumi_vsphere as vsphere
        datacenter = vsphere.get_datacenter(name='StudentDC')
        datastore = vsphere.get_datastore(name='roels-bart', datacenter_id=datacenter.id)
        network = vsphere.get_network(name='VM Network', datacenter_id=datacenter.id)
        pool = vsphere.get_resource_pool(name='Resources', datacenter_id=datacenter.id)
        template = vsphere.get_virtual_machine(name='CleanUbuntu', datacenter_id=datacenter.id)

        vm = vsphere.VirtualMachine(vm_name,
            name=vm_name,
            num_cpus=num_cpus,
            memory=memory,
            datastore_id=datastore.id,
            resource_pool_id=pool.id,
            guest_id='ubuntu64Guest',
            scsi_type='pvscsi',
            network_interfaces=[{'network_id': network.id, 'adapter_type': 'vmxnet3'}],
            clone={'template_uuid': template.id},
            disks=[{'label': 'disk0', 'size': 20, 'eagerly_scrub': False, 'thin_provisioned': True}]
        )
        return {'vm_id': vm.id, 'vm_name': vm.name}

    # 创建独立的Pulumi栈,避免资源冲突
    stack = auto.create_or_select_stack(
        stack_name=f'web-stack-{auto.utils.random_name()}',
        project_name='vsphere-vm-web-service',
        program=pulumi_program
    )

    # 设置vSphere认证配置(建议用环境变量存储敏感信息)
    stack.set_config('vsphere:server', auto.ConfigValue(value='你的vSphere服务器地址'))
    stack.set_config('vsphere:username', auto.ConfigValue(value='你的vSphere用户名', secret=True))
    stack.set_config('vsphere:password', auto.ConfigValue(value='你的vSphere密码', secret=True))
    stack.set_config('vsphere:allowUnverifiedSsl', auto.ConfigValue(value='true'))

    # 执行pulumi up
    up_result = stack.up(on_output=lambda line: print(line))
    return jsonify({
        'status': 'success',
        'vm_name': up_result.outputs['vm_name'].value,
        'vm_id': up_result.outputs['vm_id'].value
    })

if __name__ == '__main__':
    app.run(debug=True)

2. 核心最佳实践

  • 隔离资源栈:为每个用户请求创建独立的Pulumi栈(用随机后缀或用户ID命名),避免资源冲突,同时方便后续清理
  • 异步任务处理:pulumi up是耗时操作,Flask需配合Celery等异步任务队列处理,返回任务ID给用户,前端轮询获取执行状态
  • 权限管理:
    • 敏感信息(vSphere认证、Pulumi状态后端密钥)通过环境变量或秘密管理工具存储,禁止硬编码
    • 配置Pulumi远程状态后端(如S3、GCS),支持多实例共享状态
  • 参数验证:对用户输入的VM参数(CPU、内存、名称等)做合法性校验,避免无效配置导致执行失败
  • 错误处理:捕获Automation API异常,返回清晰的错误信息(如vSphere连接失败、资源不足)
  • 资源清理:提供VM删除接口,调用stack.destroy()清理对应栈的资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:59:54