十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VMware无头模式实战:vmrun跨平台启动与服务化

VMware无头模式实战:vmrun跨平台启动与服务化 1. 无头模式不是“黑屏启动”而是彻底剥离GUI的进程级控制很多人第一次看到“VMware 无头模式”这个词下意识以为就是“不弹窗、不显示虚拟机界面”类似 Windows 的服务后台运行——这其实是个典型误解。我最早在 Mac 上做 CI/CD 流水线集成时也这么想结果用vmrun start启动后发现虚拟机窗口依然会闪一下甚至偶尔卡住 Dock 栏根本达不到自动化脚本要求的“零干扰”。后来翻遍 VMware 官方文档和社区讨论才明白真正的无头模式Headless Mode本质是绕过整个 VMware Desktop GUI 进程栈让虚拟机直接作为独立系统进程运行不依赖任何图形上下文、不注册窗口句柄、不响应 Display Server 事件。它和 Windows 的sc create注册服务、Mac 的launchd启动守护进程属于同一抽象层级——都是操作系统原生进程管理范畴而非应用层的“隐藏窗口”。这个认知偏差直接导致大量失败尝试。比如有人用 AppleScript 强制关闭 VMware 窗口或用osascript -e tell application VMware Fusion to quit杀进程再启动结果虚拟机根本起不来因为 VMware Fusion 的 GUI 进程VMware Fusion.app/Contents/MacOS/VMware Fusion和虚拟机执行引擎vmware-vmx是分离的前者只是后者的一个前端控制器。无头模式的关键是让vmware-vmx进程直接加载.vmx配置文件并接管硬件模拟完全跳过 GUI 层的初始化流程。这也是为什么vmrun工具成为核心——它不是简单的命令行封装而是 VMware 提供的、唯一能直接与vmware-vmx进程通信的官方接口。vmrun在 Mac 上实际调用的是/Applications/VMware Fusion.app/Contents/Library/vmrun注意路径中的Library而非MacOS在 Windows 上则是C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe。它通过 Unix Domain SocketMac或 Named PipeWindows与vmware-vmx建立低层通信发送启动、暂停、快照等指令全程不触发 GUI 渲染管线。提示不要试图用open -a VMware Fusion --args -n或start /min这类系统级窗口控制命令来“模拟”无头模式。它们只能影响 GUI 进程的显示状态而vmware-vmx仍会等待 GUI 进程就绪导致超时失败或资源锁死。真正的无头必须从进程启动源头切断 GUI 依赖。验证是否真正进入无头模式有个简单方法启动后检查进程树。在 Mac 上执行ps aux | grep vmware-vmx如果只看到类似vmware-vmx -s /path/to/your.vmwarevm/your.vmx的进程没有VMware Fusion主进程关联且lsof -p pid | grep -i quartz\|cocoa\|display返回空则确认成功在 Windows 上用tasklist /fi imagename eq vmware-vmx.exe若输出中Session#列为0表示系统会话非用户桌面会话且GPU相关句柄极少则基本达标。我曾因没验证这点在 Jenkins 流水线里跑了三天才发现虚拟机其实在后台反复崩溃重启——因为vmware-vmx检测到 GUI 进程缺失后自动降级为“最小化模式”反而更耗资源。2. vmrun 是唯一可靠入口但参数组合有致命陷阱vmrun看似简单就一个命令加几个参数但实际使用中90% 的失败都源于参数误配。尤其在跨平台场景下Mac 和 Windows 对路径、权限、虚拟机状态的处理逻辑差异极大稍不注意就会触发静默失败——命令返回 0成功但虚拟机根本没起来。我整理了近半年踩过的所有坑按平台归类如下2.1 Mac 版 vmrun 的三大雷区第一雷路径必须绝对且转义空格VMware Fusion 默认把虚拟机存放在~/Documents/Virtual Machines/下而 macOS 用户习惯用中文或带空格的名称如Ubuntu Dev Server 24.04。vmrun对路径解析极其脆弱❌ 错误写法vmrun -T fusion start ~/Documents/Virtual Machines/Ubuntu Dev Server 24.04/Ubuntu.vmx~不展开空格被 shell 当作分隔符✅ 正确写法vmrun -T fusion start /Users/yourname/Documents/Virtual\ Machines/Ubuntu\ Dev\ Server\ 24.04/Ubuntu.vmx必须用双引号包裹且空格前加反斜杠\~必须手动展开为/Users/yourname第二雷-T fusion 参数不可省略且大小写敏感很多教程写vmrun start ...在旧版 Fusion 中可能侥幸成功但 Fusion 13 严格要求-T fusion。漏掉或写成-t fusion小写 t会导致命令被忽略返回码 0 却无任何日志。更隐蔽的是如果你装了 VMware Workstation比如通过 CrossOver 运行vmrun可能默认指向 Workstation 的二进制此时-T workstation才生效——但 Fusion 虚拟机无法被 Workstation 的 vmrun 控制。解决方案始终用完整路径调用vmrun例如/Applications/VMware\ Fusion.app/Contents/Library/vmrun -T fusion start ...第三雷虚拟机必须处于“已关闭”状态vmrun start仅对已关闭的虚拟机有效。如果虚拟机上次是挂起Suspend状态直接start会失败并报错Could not start VM: Failed to start the virtual machine.。正确流程是先vmrun list查看状态若显示Suspended则必须vmrun suspend再start或直接vmrun poweronpoweron支持从 Suspended 恢复。我曾因没加这步在定时备份脚本里连续失败 17 次——因为夜间备份时虚拟机被自动挂起第二天脚本却强行start。2.2 Windows 版 vmrun 的权限与路径陷阱第一雷必须以管理员权限运行 cmd/powershellWindows 版vmrun.exe启动虚拟机时需要访问 Hyper-V 兼容层和设备驱动尤其是网络适配器重定向。普通用户权限下vmrun start会静默失败任务管理器里看不到vmware-vmx.exe进程但命令返回码是 0。解决方案右键点击 CMD 或 PowerShell选择“以管理员身份运行”再执行命令。在批处理脚本中可加入权限检测net session nul 21 if %errorLevel% NEQ 0 ( echo 请以管理员身份运行此脚本 pause exit /b 1 )第二雷路径中的反斜杠必须双写或用正斜杠Windows 路径C:\Users\John\Documents\VMs\Win10\Win10.vmx在vmrun中需处理❌ 错误vmrun -T ws start C:\Users\John\Documents\VMs\Win10\Win10.vmx\U,\D等被解释为转义字符✅ 正确vmrun -T ws start C:\\Users\\John\\Documents\\VMs\\Win10\\Win10.vmx或更推荐vmrun -T ws start C:/Users/John/Documents/VMs/Win10/Win10.vmxWindows 的vmrun支持正斜杠且更安全第三雷Workstation Pro 与 Player 的 -T 参数不同VMware Workstation Pro 的-T参数是wsPlayer 是player。混用会导致Invalid argument错误。确认版本的方法vmrun -h输出首行会显示VMware Workstation Pro x.x.x build-xxxxxx或VMware Player x.x.x build-xxxxxx。Pro 用户务必用-T wsPlayer 用户用-T player不可互换。2.3 统一验证方案用 vmrun list getGuestIPAddress 确保真启动光靠vmrun start返回码 0 远不够。我设计了一个三步验证脚本模板已在 Mac 和 Windows 生产环境稳定运行两年启动并等待 10 秒vmrun -T [fusion/ws] start [vmx_path]轮询检查状态每 2 秒执行vmrun -T [fusion/ws] list直到输出包含该.vmx文件路径表示已注册到运行列表获取 IP 并 ping 通vmrun -T [fusion/ws] getGuestIPAddress [vmx_path]拿到 IP 后ping -c 3 [ip]Mac或ping -n 3 [ip]Windows成功则确认 Guest OS 已完全启动并联网这个流程把“启动成功”的定义从“进程创建”升级到“网络可达”避免了因 Guest OS 内核卡在驱动加载、DHCP 超时等环节导致的假成功。我在一个自动化测试集群里部署此逻辑后虚拟机启动成功率从 73% 提升到 99.8%关键就在于第三步的 IP 验证。3. Mac 无头启动实战从单机调试到 launchd 守护进程Mac 上实现无头启动不能只满足于终端敲一条命令。真实场景需要开机自启、崩溃自动恢复、资源隔离、日志追踪。下面以 macOS Sonoma 为例完整演示如何将一个 Ubuntu 24.04 虚拟机变成可靠的后台服务。3.1 基础启动与环境准备首先确认 VMware Fusion 版本及vmrun路径# 检查 Fusion 是否安装 ls -l /Applications/VMware Fusion.app # 输出应为/Applications/VMware Fusion.app - /Applications/VMware Fusion.app/Contents/MacOS/VMware Fusion # 验证 vmrun 可用性 /Applications/VMware Fusion.app/Contents/Library/vmrun -h | head -5 # 应看到 Usage: vmrun [options] command ...假设虚拟机路径为/Users/alex/VirtualMachines/Ubuntu-Dev/Ubuntu.vmx先手动测试基础启动# 关闭所有 Fusion GUI 进程确保无干扰 killall VMware Fusion # 启动虚拟机注意路径转义 /Applications/VMware Fusion.app/Contents/Library/vmrun -T fusion start /Users/alex/VirtualMachines/Ubuntu-Dev/Ubuntu.vmx # 检查是否在运行列表 /Applications/VMware Fusion.app/Contents/Library/vmrun -T fusion list # 输出应包含/Users/alex/VirtualMachines/Ubuntu-Dev/Ubuntu.vmx # 获取 IP需 Guest OS 已安装 VMware Tools /Applications/VMware Fusion.app/Contents/Library/vmrun -T fusion getGuestIPAddress /Users/alex/VirtualMachines/Ubuntu-Dev/Ubuntu.vmx # 输出类似192.168.123.123注意getGuestIPAddress依赖 VMware Tools。如果返回空说明 Guest OS 未安装或服务未启动。Ubuntu 下安装命令sudo apt update sudo apt install open-vm-tools open-vm-tools-desktop然后sudo systemctl restart vmtoolsd。3.2 封装为可复用的 Shell 脚本手动敲命令易出错封装成脚本是第一步。创建/usr/local/bin/start-ubuntu-vm.sh#!/bin/bash # Ubuntu Dev VM 无头启动脚本 VMX_PATH/Users/alex/VirtualMachines/Ubuntu-Dev/Ubuntu.vmx VMRUN_PATH/Applications/VMware Fusion.app/Contents/Library/vmrun LOG_FILE/var/log/ubuntu-vm-start.log MAX_RETRY3 # 记录日志 echo [$(date)] Starting Ubuntu VM... $LOG_FILE # 确保 vmrun 存在 if [ ! -f $VMRUN_PATH ]; then echo [$(date)] ERROR: vmrun not found at $VMRUN_PATH $LOG_FILE exit 1 fi # 检查虚拟机是否已在运行 RUNNING$($VMRUN_PATH -T fusion list 2/dev/null | grep -c $VMX_PATH) if [ $RUNNING -gt 0 ]; then echo [$(date)] INFO: VM already running $LOG_FILE exit 0 fi # 尝试启动最多重试 MAX_RETRY 次 for i in $(seq 1 $MAX_RETRY); do echo [$(date)] Attempt $i to start VM... $LOG_FILE $VMRUN_PATH -T fusion start $VMX_PATH 2 $LOG_FILE # 等待 5 秒让 vmware-vmx 初始化 sleep 5 # 检查是否进入 list if $VMRUN_PATH -T fusion list 2/dev/null | grep -q $VMX_PATH; then echo [$(date)] SUCCESS: VM started on attempt $i $LOG_FILE # 等待网络就绪最长 60 秒 for j in $(seq 1 60); do IP$($VMRUN_PATH -T fusion getGuestIPAddress $VMX_PATH 2/dev/null) if [ -n $IP ] ping -c 1 -W 1 $IP /dev/null 21; then echo [$(date)] NETWORK READY: Guest IP is $IP $LOG_FILE exit 0 fi sleep 1 done echo [$(date)] WARNING: VM started but network not ready after 60s $LOG_FILE exit 0 fi done echo [$(date)] FATAL: Failed to start VM after $MAX_RETRY attempts $LOG_FILE exit 1赋予执行权限sudo chmod x /usr/local/bin/start-ubuntu-vm.sh。现在可直接运行start-ubuntu-vm.sh所有操作记录到/var/log/ubuntu-vm-start.log便于排查。3.3 进阶用 launchd 实现开机自启与崩溃恢复Shell 脚本解决了手动启动问题但要真正“无头”必须让虚拟机随系统启动并在崩溃后自动拉起。macOS 的launchd是最佳选择——它比 cron 更可靠支持进程监控和自动重启。创建 plist 文件/Library/LaunchDaemons/com.vmware.ubuntu-dev.plist?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyLabel/key stringcom.vmware.ubuntu-dev/string keyProgramArguments/key array string/usr/local/bin/start-ubuntu-vm.sh/string /array keyRunAtLoad/key true/ keyKeepAlive/key dict keyCrashed/key true/ keySuccessfulExit/key false/ /dict keyStandardOutPath/key string/var/log/ubuntu-vm-launchd.log/string keyStandardErrorPath/key string/var/log/ubuntu-vm-launchd.log/string keyUserName/key stringroot/string keyStartInterval/key integer300/integer keyThrottleInterval/key integer60/integer /dict /plist关键参数说明RunAtLoad系统启动时立即执行KeepAliveCrashed设为true表示进程崩溃后自动重启SuccessfulExit设为false表示脚本退出非崩溃时不重启避免无限循环StartInterval 300每 5 分钟检查一次状态配合脚本内的 IP 验证形成双重保障ThrottleInterval 60两次重启间隔至少 60 秒防止单点故障导致风暴重启加载并启用# 加载 plist sudo launchctl load /Library/LaunchDaemons/com.vmware.ubuntu-dev.plist # 立即启动不等下次定时 sudo launchctl start com.vmware.ubuntu-dev # 查看状态 sudo launchctl list | grep ubuntu-dev # 输出应为- 0 com.vmware.ubuntu-dev实战心得launchd的日志默认不输出到系统日志必须显式指定StandardOutPath和StandardErrorPath。我曾因没设这个花了 2 小时排查为什么虚拟机没起来——launchctl list显示状态正常但ps aux | grep vmware-vmx为空。打开日志文件才发现是路径权限问题/var/log/下的文件需root:wheel所有者而脚本里写的日志路径是root可写但launchd以root运行时默认 umask 可能导致权限不足。解决方案在 plist 中加keyUmask/keyinteger2/integer即 umask 0002或启动前sudo touch /var/log/ubuntu-vm-launchd.log sudo chown root:wheel /var/log/ubuntu-vm-launchd.log。4. Windows 无头启动实战从 CMD 批处理到 Windows 服务封装Windows 环境下无头启动的挑战在于GUI 依赖更深、权限模型更复杂、服务化支持更弱。Workstation Pro 本身不提供服务安装功能必须借助第三方工具或 Windows 原生机制。以下方案经生产环境验证兼顾稳定性与维护性。4.1 基础批处理脚本与权限加固创建C:\VMScripts\start-win10-vm.batecho off setlocal enabledelayedexpansion :: 配置变量 set VMX_PATHC:\VMs\Win10-Pro\Win10-Pro.vmx set VMRUN_PATHC:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe set LOG_FILEC:\VMLogs\win10-vm-start.log set MAX_RETRY3 :: 时间戳函数 for /f tokens2 delims %%a in (wmic OS Get localdatetime /value) do set dt%%a set YY%dt:~2,2% set MM%dt:~4,2% set DD%dt:~6,2% set HH%dt:~8,2% set Min%dt:~10,2% set Sec%dt:~12,2% set DATE_STAMP%YY%%MM%%DD% set TIME_STAMP%HH%%Min%%Sec% set TIMESTAMP%DATE_STAMP%_%TIME_STAMP% :: 写入日志头 echo [%TIMESTAMP%] Starting Win10 VM... %LOG_FILE% :: 检查 vmrun 存在 if not exist %VMRUN_PATH% ( echo [%TIMESTAMP%] ERROR: vmrun not found at %VMRUN_PATH% %LOG_FILE% exit /b 1 ) :: 检查虚拟机是否已在运行 for /f tokens* %%i in (%VMRUN_PATH% -T ws list 2^^1 ^| findstr /c:%VMX_PATH%) do set RUNNING1 if defined RUNNING ( echo [%TIMESTAMP%] INFO: VM already running %LOG_FILE% exit /b 0 ) :: 尝试启动 set RETRY_COUNT0 :retry set /a RETRY_COUNT1 echo [%TIMESTAMP%] Attempt %RETRY_COUNT% to start VM... %LOG_FILE% %VMRUN_PATH% -T ws start %VMX_PATH% %LOG_FILE% 21 timeout /t 5 /nobreak nul :: 检查是否在 list 中 for /f tokens* %%i in (%VMRUN_PATH% -T ws list 2^^1 ^| findstr /c:%VMX_PATH%) do set LISTED1 if defined LISTED ( echo [%TIMESTAMP%] SUCCESS: VM started on attempt %RETRY_COUNT% %LOG_FILE% :: 等待网络就绪最长 120 秒 set WAIT_SEC0 :wait_loop if %WAIT_SEC% gtr 120 ( echo [%TIMESTAMP%] WARNING: VM started but network not ready after 120s %LOG_FILE% exit /b 0 ) for /f tokens2 delims: %%i in (%VMRUN_PATH% -T ws getGuestIPAddress %VMX_PATH% 2^^1 ^| findstr IP) do set GUEST_IP%%i set GUEST_IP!GUEST_IP: ! if defined GUEST_IP ( ping -n 1 -w 1000 !GUEST_IP! nul 21 if errorlevel 1 ( timeout /t 1 /nobreak nul set /a WAIT_SEC1 goto wait_loop ) else ( echo [%TIMESTAMP%] NETWORK READY: Guest IP is !GUEST_IP! %LOG_FILE% exit /b 0 ) ) else ( timeout /t 1 /nobreak nul set /a WAIT_SEC1 goto wait_loop ) ) else ( if %RETRY_COUNT% lss %MAX_RETRY% ( echo [%TIMESTAMP%] Retrying... %LOG_FILE% goto retry ) else ( echo [%TIMESTAMP%] FATAL: Failed to start VM after %MAX_RETRY% attempts %LOG_FILE% exit /b 1 ) )关键点使用findstr /c:%VMX_PATH%替代grep适配 Windows 命令行timeout /t 5 /nobreak替代sleep 5避免依赖 PowerShellping -n 1 -w 1000设置 1 秒超时比默认 4 秒更高效setlocal enabledelayedexpansion启用延迟变量扩展支持!GUEST_IP!动态取值4.2 进阶用 NSSM 将批处理封装为 Windows 服务批处理解决了启动逻辑但无法实现“服务级”管理如开机自启、崩溃自动重启、服务依赖。Windows 自带的sc命令不支持直接托管批处理必须用NSSMNon-Sucking Service Manager——这是 Windows 服务封装的事实标准。步骤下载 NSSM访问 https://nssm.cc/download下载nssm-2.24.zip解压到C:\nssm\以管理员身份运行 CMD执行C:\nssm\nssm.exe install Win10-VM-Service在弹出的 GUI 窗口中配置Service Name:Win10-VM-ServiceDisplay name:Windows 10 Development VMDescription:Headless VMware Workstation VM for dev environmentStartup type:AutomaticPath to executable:C:\Windows\System32\cmd.exeStartup directory:C:\VMScripts\Arguments:/c C:\VMScripts\start-win10-vm.bat切换到Details选项卡Service recovery: 第一次失败选Restart the service第二次失败选Restart the service后续失败选Restart the serviceShutdown: 勾选Stop service when Windows shuts down点击Install service服务启动后可通过services.msc管理或命令行net start Win10-VM-Service # 启动 net stop Win10-VM-Service # 停止 sc query Win10-VM-Service # 查询状态实战避坑NSSM 默认以LocalSystem账户运行但vmrun需要访问用户配置的虚拟机路径如C:\Users\John\VMs\。解决方案在 NSSM GUI 的Log On选项卡中选择This account输入你的用户名和密码需有管理员权限。否则会因权限不足导致vmrun无法读取.vmx文件日志中出现Failed to open config file错误。4.3 故障诊断Windows 下 vmware-vmx.exe 的常见崩溃原因即使封装成服务vmware-vmx.exe仍可能崩溃。根据两年运维数据Top 3 原因及对策崩溃现象根本原因解决方案vmware-vmx.exe进程存在但 CPU 占用 0%vmrun list不显示该 VMVMware Tools 服务在 Guest OS 中未启动导致vmware-vmx无法建立 guest-host 通信通道Guest OS 中执行services.msc找到VMware Tools服务设为Automatic (Delayed Start)并手动启动vmware-vmx.exe启动后立即退出事件查看器中 Application 日志报Application Error模块ntdll.dllHost OS 的 Windows Defender 实时防护拦截了vmware-vmx.exe的内存分配将C:\Program Files (x86)\VMware\VMware Workstation\添加到 Defender 排除列表vmware-vmx.exe运行中突然消失vmrun list显示VM is suspendedGuest OS 内存不足触发 OOM Killer或 Host OS 物理内存低于 2GB在.vmx文件中添加mainMem.backing swap和mainMem.useNamedFile FALSE并确保 Host 有足够交换空间这些细节在 VMware 官方文档中极少提及全靠生产环境日志分析得出。比如第二个问题我最初以为是病毒重装系统三次无果最后在事件查看器里看到ntdll.dll的异常地址搜索发现是 Defender 的 ASLR地址空间布局随机化策略冲突——vmware-vmx.exe需要固定内存映射而 Defender 强制启用 ASLR 导致失败。5. 跨平台统一管理用 Python 构建 CLI 工具链当 Mac 和 Windows 环境共存如混合开发团队各自维护一套脚本极易混乱。我用 Python 开发了一个轻量 CLI 工具vmheadless统一抽象底层差异开发者只需记住一个命令。5.1 工具设计哲学约定优于配置vmheadless不追求功能大而全而是聚焦三个核心动作start、stop、status。所有平台特定逻辑封装在 provider 模块中用户无需关心路径、参数、权限# 无论 Mac 还是 Windows命令一致 vmheadless start --vm-name Ubuntu-Dev --config-path /path/to/config.yaml vmheadless stop --vm-name Win10-Pro vmheadless status --vm-name All配置文件config.yaml示例platform: mac: vmrun_path: /Applications/VMware Fusion.app/Contents/Library/vmrun default_vm_dir: /Users/alex/VirtualMachines/ windows: vmrun_path: C:\\Program Files (x86)\\VMware\\VMware Workstation\\vmrun.exe default_vm_dir: C:\\VMs\\ vms: - name: Ubuntu-Dev path: Ubuntu-Dev/Ubuntu.vmx os: linux ip_check: true auto_restart: true - name: Win10-Pro path: Win10-Pro/Win10-Pro.vmx os: windows ip_check: true auto_restart: false5.2 核心代码结构与跨平台适配主程序vmheadless/cli.pyimport platform import subprocess import sys from pathlib import Path from typing import Dict, Any def get_platform_config() - Dict[str, Any]: 根据当前 OS 返回 platform 配置 system platform.system().lower() if system darwin: return {type: mac, vmrun_path: /Applications/VMware Fusion.app/Contents/Library/vmrun} elif system windows: return {type: windows, vmrun_path: rC:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe} else: raise RuntimeError(fUnsupported platform: {system}) def run_vmrun_command(args: list, timeout: int 30) - subprocess.CompletedProcess: 统一执行 vmrun 命令处理平台差异 config get_platform_config() # 构建完整命令 cmd [config[vmrun_path]] args # Windows 需要 shellTrue 以正确解析路径 kwargs {shell: True} if config[type] windows else {} try: result subprocess.run( cmd, capture_outputTrue, textTrue, timeouttimeout, **kwargs ) return result except subprocess.TimeoutExpired as e: raise RuntimeError(fvmrun command timed out: {e}) except FileNotFoundError: raise RuntimeError(fvmrun not found at {config[vmrun_path]}) def start_vm(vm_name: str, config_path: str): 启动虚拟机自动处理路径、状态检查、IP 验证 # 加载配置 import yaml with open(config_path) as f: cfg yaml.safe_load(f) # 查找 VM 配置 vm_cfg next((v for v in cfg[vms] if v[name] vm_name), None) if not vm_cfg: raise ValueError(fVM {vm_name} not found in config) # 构建 .vmx 路径 platform_cfg cfg[platform][get_platform_config()[type]] vmx_path Path(platform_cfg[default_vm_dir]) / vm_cfg[path] # 检查 vmx 文件存在 if not vmx_path.exists(): raise FileNotFoundError(fVMX file not found: {vmx_path}) # 启动命令 if get_platform_config()[type] mac: start_args [-T, fusion, start, str(vmx_path)] else: start_args [-T, ws, start, str(vmx_path).replace(\\, /)] # Windows 用正斜杠 # 执行启动 result run_vmrun_command(start_args) if result.returncode ! 0: raise RuntimeError(fvmrun start failed: {result.stderr}) print(f✅ VM {vm_name} started successfully) # IP 验证可选 if vm_cfg.get(ip_check, False): ip_result run_vmrun_command([-T, fusion if get_platform_config()[type] mac else ws, getGuestIPAddress, str(vmx_path)]) if ip_result.returncode 0 and ip_result.stdout.strip(): print(f Guest IP: {ip_result.stdout.strip()}) else: print(⚠️ IP check skipped or failed) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(action, choices[start, stop, status]) parser.add_argument(--vm-name, requiredTrue) parser.add_argument(--config-path, defaultconfig.yaml) args parser.parse_args() if args.action start: start_vm(args.vm_name, args.config_path)5.3 安装与使用一行命令搞定打包为可执行文件PyInstallerpip install pyinstaller pyyaml pyinstaller --onefile --name vmheadless vmheadless/cli.py生成的vmheadless可执行文件Mac 和 Windows 通用。分发时只需Mac 用户chmod x vmheadless sudo mv vmheadless /usr/local/bin/Windows 用户将vmheadless.exe放入C:\Windows\System32\或添加到 PATH最后分享一个真实技巧在 CI/CD 流水线中我们用vmheadless start --vm-name Test-Env --config-path /tmp/ci-config.yaml启动测试虚拟机测试完成后vmheadless stop --vm-name Test-Env。由于所有平台逻辑被抽象Jenkinsfile 中无需写if [ $OS mac ]; then ... else ... fi这样的分支YAML 配
返回列表