晚上十一点接到电话,说虚拟机开机失败,直接卡在一个黑色控制台上。等我赶回机房,图形客户端连不上,网页管理端也转圈,最后是一行一行敲指令把虚拟机捞回来的。玩VMware这两年,类似的场面不止一次,命令行操作虚拟机不是炫技,是真正的保命技能。这篇文章把我在VMware平台里常用的指令整理一遍,讲清楚每条指令的作用、调用时机和坑,给需要折腾虚拟机的朋友一个能直接照抄的清单。
1. 指令操作在VMware里的真实地位:GUI替不了的那几件活
很多人一听到“虚拟机指令操作”,第一反应是“有图形界面为什么还要敲命令”。这个想法我一开始也有,直到有一次批量处理几十台虚拟机,在图形界面里一台台右键、关机、打快照,忙活到凌晨才意识到自己干了一件多蠢的事。图形界面适合单台、低频、人眼确认的场景,一旦涉及到批量、定时、无人值守,或者网络断开、控制台失效这些极端情况,指令操作的价值立刻体现出来。
VMware的指令操作,实际上分成几个层次,最容易被搞混的是:vmrun、vim-cmd、esxcli,以及后面延伸出来的PowerCLI。这四个东西经常被人放在一起说,但它们的宿主环境、授权模型和用途完全不同。
| 指令工具 | 运行位置 | 主要用途 | 典型场景 |
|---|---|---|---|
| vmrun | VMware Workstation / Fusion 主机 | 控制单台虚拟机,如开关机、快照、克隆 | 本地开发机、实验室环境 |
| vim-cmd | ESXi 宿主机 Shell | 管理宿主机上的虚拟机,如电源状态、注册虚拟化清单 | SSH 登录 ESXi 后管理虚拟机 |
| esxcli | ESXi 宿主机 Shell | 宿主机级运维,含 VM 进程管理、网络、存储 | 查进程、杀进程、网络与存储维护 |
| PowerCLI | 任意安装了 PowerShell 的机器 | 基于 vSphere API 的远程管理 | 批量规划、自动化脚本、报表 |
这套区别你看懂之后就明白,没有哪一条命令是“万能钥匙”。vmrun 管的是 Workstation 里跑着的 VM,vim-cmd 管的是 ESXi 这台物理机上注册的 VM,esxcli 更倾向于宿主机系统本身。很多新手拿 vmrun 去连 ESXi,命令根本不认识,就是因为没有分清对象。
还有一个反直觉的事实:在 GUI 完全瘫痪的时候,命令行是最后一道防线。图形客户端需要网络、需要服务端组件正常运转,而 SSH 或者本地控制台只需要一个能用的 Shell。我有一次遇到管理服务异常,Web 界面一直转圈,但 SSH 登录后 vim-cmd 依然能用,虚拟机一台没少。所以,指令操作对虚拟化管理员来说,不是“进阶技巧”,而是基本生存能力。
2. vmrun 指令实操:开关机、快照、克隆一次讲透
2.1 先找到 vmrun 这个工具
vmrun 是随 VMware Workstation 和 Fusion 一起发布的命令行工具,它不会自动加入你的 PATH,需要手动指定路径。在 Windows 主机上,典型位置在:
C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe在 Linux 主机的 Workstation 里,通常装完就在:
/usr/bin/vmrun我习惯先给 vmrun 设置一个别名,省得每次敲全路径。Windows 用户可以直接把这个目录加进系统环境变量,Linux 用户可以用软链或者 alias。配置好后,先执行vmrun list看看当前有哪些虚拟机在运行,这一步既是测试工具是否可用,也是熟悉命令输出的过程。
vmrun list如果输出类似Total number of running guests: 2以及两台虚拟机的.vmx路径,说明工具正常。注意,vmrun 操作的是 .vmx 配置文件路径,不是虚拟机名称,这一点和后面要说的 vim-cmd 完全不同。
2.2 开关机、挂起这几个最基础的指令
vmrun 对单台虚拟机的日常控制命令非常直白,最常用的就是 start、stop、suspend、reset:
# 启动虚拟机(加 nogui 参数,不弹出 Workstation 窗口) vmrun start "/path/to/your.vmx" nogui # 正常关机 vmrun stop "/path/to/your.vmx" soft # 强制断电(类似拔电源,危险但必要时有用) vmrun stop "/path/to/your.vmx" hard # 挂起虚拟机 vmrun suspend "/path/to/your.vmx" # 重启 vmrun reset "/path/to/your.vmx" softsoft是我用得最多的参数,它代表“优雅地关闭”,会先通知客户机操作系统执行正常关机流程。hard就是模拟硬断电,不到万不得已不碰,因为可能损坏文件系统。对于不需要弹出窗口的无人值守场景,start 后面加nogui可以避免启动一个完整的图形界面,节省资源。
2.3 快照操作:回滚时间的保险丝
快照管理是 vmrun 的强项。在开发环境里,我经常需要在某个状态点随时回滚,比如安装软件前先打个快照,装出问题就 revert。常用指令:
# 创建快照 vmrun snapshot "/path/to/your.vmx" "before-install" # 回滚到指定快照 vmrun revertToSnapshot "/path/to/your.vmx" "before-install" # 删除快照 vmrun deleteSnapshot "/path/to/your.vmx" "before-install"这里有个极为重要的细节:快照名如果带空格,必须用双引号包起来。比如"snap 2025-01-15"这种名字,执行时引号写错一个,vmrun 会把它当成两个参数,命令要么报错要么建出一个奇怪名字的快照。我建议干脆养成习惯,快照名里不用空格,统一用连字符或日期格式,比如snap-20250115,可以省掉很多低级问题。
快照数量也要控制。很多人不知道,快照不是无限存的,每个快照都会占用磁盘空间,快照层级越深,虚拟磁盘的性能就越差,尤其对数据库虚拟机影响巨大。我见过一个人给一台机器挂了十几个快照,磁盘占用比系统本身还大。生产环境中,保留两三个关键节点足矣,用完及时删除。
2.4 克隆虚拟机:不再需要图形界面点来点去
vmrun 的 clone 指令可以基于当前状态创建链接克隆或完整克隆:
# 完整克隆 vmrun clone "/path/to/source.vmx" "/path/to/dest.vmx" full # 链接克隆(指定克隆来源快照) vmrun clone "/path/to/source.vmx" "/path/to/dest.vmx" linked -snapshot="base-snapshot"相同情况下,我推荐做完整克隆,因为链接克隆依赖源虚拟机存在,源一旦挪动或删除,链接克隆就变成孤魂野鬼。克隆之前务必确认源虚拟机关机,不然文件处于写入状态,克隆出来的机器容易损坏。
还有一件事很多人踩过坑:克隆出来的虚拟机和你原来的机器拥有相同的网卡 MAC 地址吗?VMware 在克隆时会自动生成新的 UUID 和 MAC,但如果你用纯文件拷贝方式复制虚拟磁盘,MAC 可能冲突,导致克隆出来的机器在网络里和别人抢地址。如果出现这种情况,可以在 .vmx 配置文件里删除 ethernet0.generatedAddress 等项,让 VMware 重新生成。
3. ESXi 宿主视角:vim-cmd 与 esxcli 的指令路线
3.1 先摸清虚拟机的身份编号再说
在 ESXi 宿主机上,最常用的管理指令是 vim-cmd。它跟 vmrun 最大的区别是:vim-cmd 用虚拟机编号 vmid 来定位虚拟机,而不是用 .vmx 路径。所以第一步永远是查编号:
vim-cmd vmsvc/getallvms输出大概是这样的格式:
Vmid Name File Guest OS Version 1 web-test [datastore1] web-test/web-test.vmx linuxGuest 8 2 db-prod [datastore1] db-prod/db-prod.vmx linuxGuest 8第一列是 vmid,后面的 Name 是显示名,真正操作时全部用第一列的数字。比如查看某台虚拟机的电源状态:
vim-cmd vmsvc/power.getstate 1会返回Retrieved runtime info后面跟着状态,取最后一行是Powered on或Powered off。查状态这件事日常非常高频,我一般会写一个短命令直接过滤:
vim-cmd vmsvc/power.getstate 1 | tail -1启动、关机的指令也在这一层:
# 开机 vim-cmd vmsvc/power.on 1 # 正常关机(要求客户机装有 VMware Tools) vim-cmd vmsvc/power.shutdown 1 # 强制断电(类似拔插头) vim-cmd vmsvc/power.off 13.2 电源操作里的“优雅”与“暴力”之别
这里有一个必须搞清楚的概念:power.shutdown和power.off是两回事。power.shutdown是告诉客户机操作系统“请正常关机”,只有安装了 VMware Tools 或 open-vm-tools 才能生效,过程需要几十秒。power.off是直接从虚拟机管理层面切断电源,数据丢失风险极大。
实际运维里,我见过太多人把power.off当成“关机”来用,然后虚拟机里的数据库启动时报一堆文件系统错误。优雅关机不是每次都能成功,如果客户机假死、Tools 无响应,power.shutdown就会卡住。顺序应该是这样:先power.shutdown,等一两分钟查状态,没关掉再power.off兜底。
3.3 esxcli vm process:从进程角度掌控虚拟机
如果说 vim-cmd 是从“VMware 虚拟化平台”的视角管理虚拟机,那么 esxcli vm process 就是从“ESXi 操作系统进程”的视角来管理。非常常用的场景是:某台虚拟机卡死,vim-cmd 关机关不掉,这时用 esxcli 直接看进程并终结:
esxcli vm process list这条命令会列出每台虚拟机的 World ID 和 Process ID。注意,这里的 ID 和 vmid 不是一回事,esxcli 里的 ID 是宿主机系统级的进程标识。kill 的时候指定的是这个进程号:
# 优雅关闭(相当于向客户机发起关机请求) esxcli vm process kill --type=soft --world-id=12345 # 强制断电 esxcli vm process kill --type=hard --world-id=12345 # 系统级强杀(慎用中的慎用) esxcli vm process kill --type=force --world-id=12345三种 type 的递进关系就是温和到粗暴。soft是首选;hard等效于拔电源;force是直接把 VMX 进程从宿主机里杀掉,连虚拟化管理层的状态都来不及同步,能不用就不用。我在实际环境中通常用到hard就到头了,force只在虚拟机彻底卡死连指令都无响应时才会考虑。
3.4 vim-cmd 与 esxcli 的区分
很多人会把这两条工具混用,其实它们解决的问题不同。简单说:
- 查虚拟机列表、电源状态、快照操作、注册/注销虚拟机,用 vim-cmd。
- 查进程、杀进程、查看宿主机服务状态,用 esxcli。
esxcli 里还有大量存储和网络管理命令,比如esxcli network nic list、esxcli storage vmfs extent list。这些指令对虚拟机本身的操作没有那么直接,但在排查宿主机可靠性问题时经常用到。排查虚拟机卡顿,先看esxcli network看网络丢包,再看esxcli storage看存储延迟,定位思路会清晰很多。
4. 批量运维场景:用指令把虚拟机管理串成脚本
指令操作真正让我感到“值回票价”的瞬间,是批量操作六七十台虚拟机的时候。图形界面点几十次右键的操作量,在脚本里就是一次循环。
4.1 批量生成虚拟机清单
在 ESXi 上做批量操作,第一步是拿到虚拟机的 ID 列表。vim-cmd vmsvc/getallvms第一列是 ID,tail -1过滤掉标题行,就可以作为循环的列表基础:
vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}'这个命令输出的是所有虚拟机的 vmid,一个一行。拿到这个清单,后续的批处理就简单了。比如批量查看全部虚拟机的电源状态:
#!/bin/bash IDS=$(vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}') for id in $IDS; do state=$(vim-cmd vmsvc/power.getstate "$id" | tail -1) echo "虚拟机 ID: $id 状态: $state" done如果你想要更丰富的清单信息,比如名称与 ID 一起输出,可以参考这个写法:
vim-cmd vmsvc/getallvms | awk 'NR>1 {print "ID="$1, "名称="$2}'注意,名称里如果带空格,第二列就只取到第一个空格前的部分,想要完整名称就得用别的分隔方式。这里我不展开,只需要记住:批量操作时优先用 ID,不要用名称,因为 ID 是唯一的数字,不会带空格,不会因为名称变化导致脚本失效。
4.2 批量关机与批量打快照示例
批量关机时,我个人不会对所有虚拟机一刀切power.off。稳妥的做法是先用power.getstate判断状态,只处理开机中的虚拟机,然后先尝试power.shutdown,过一会儿再复查,没关掉的单独标记出来:
#!/bin/bash IDS=$(vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}') for id in $IDS; do state=$(vim-cmd vmsvc/power.getstate "$id" | tail -1) if [ "$state" = "Powered on" ]; then echo "正在关闭虚拟机 ID: $id" vim-cmd vmsvc/power.shutdown "$id" fi done批量打快照也是运维高频需求,比如升级前给一批虚拟机打统一快照。快照名可以用日期变量来保证唯一性:
#!/bin/bash SNAPNAME="snap-$(date +%Y%m%d%H%M)" IDS=$(vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}') for id in $IDS; do vim-cmd vmsvc/snapshot.create "$id" "$SNAPNAME" "before-upgrade" echo "虚拟机 ID: $id 快照已创建: $SNAPNAME" done这里补充一个 vim-cmd 快照指令的三个参数顺序:vmid、快照名、快照描述。描述可以很简短,自己看得懂就行。打完快照建议立刻用vim-cmd vmsvc/snapshot.get验证一下是否生成成功。
4.3 定时任务和远程执行
在 ESXi 上写 cron 需要小心,因为默认情况下 ESXi 的 cron 配置可能不持久,重启后丢失。我通常的做法是:在独立的 Linux 管理机上写脚本,通过 SSH 远程执行 ESXi 指令。这样脚本集中在管理机上,不依赖单台 ESXi 的本地配置。
管理机上的 crontab 示例,每天凌晨两点检查虚拟机状态并写入日志:
0 2 * * * sshpass -p 'ESXi密码' ssh root@esxi-ip "vim-cmd vmsvc/getallvms | wc -l" >> /var/log/vm-count.log把远程指令嵌入脚本时,就把整个 ESXi 指令当成一个字符串传给 SSH 即可。ESXi 的 Shell 环境较精简,很多 Linux 命令如 curl 不一定有,但 vim-cmd、esxcli、awk、grep 这些常用工具都在,写脚本没什么阻碍。
有人可能会问:PowerCLI 不香吗?香,但它需要单独装模块、熟悉 PowerShell 语法、有网络到 vSphere 管理服务。在很多底层运维场景,SSH 加 esxcli 更直接。PowerCLI 适合做更复杂的规划,比如跨集群批量部署、复杂条件判断,而 esxcli 和 vim-cmd 更适合“手边有台 SSH 终端,快速解决问题”。
5. 我踩过的指令坑:命令行操作虚拟机避坑清单
5.1 路径里的空格,让引号和转义成了第一道考题
虚拟机存放路径常常包含空格,尤其是默认创建的虚拟机路径,例如:
/vmfs/volumes/datastore1/测试 虚拟机/测试 虚拟机.vmx直接用裸路径执行vim-cmd vmsvc/getallvms倒没什么,一旦要注册或操作虚拟磁盘相关文件,路径里的空格就会报“File not found”。我自己踩过最惨的一次是在脚本里拼接路径时,忘了加双引号,命令把路径拆成两段,ESXi 直接提示找不到文件,而那台虚拟机的注册信息被搞乱了,最后手动重新注册才恢复。
vmrun也一样,所有带路径参数的指令,一律用双引号包住路径:
vmrun start "/vmfs/volumes/My Storage/my vm.vmx" nogui写脚本时还要额外小心变量本身的引号,比如这样就会出错:
# 错误示范 vmrun start $VM_PATH nogui # 正确写法 vmrun start "$VM_PATH" nogui5.2 命令装了好好的却提示 command not found
这是个很迷惑人的问题。明明在 ESXi 上敲vim-cmd时还能用,换了一个 SSH 会话就提示找不到。原因多半是 ESXi 的 Shell 环境里 PATH 变量没有包含/bin目录,或者用的是受限 Shell。解决办法是显式使用完整路径:
/bin/vim-cmd vmsvc/getallvms /bin/esxcli vm process list另外,ESXi 自带的 Shell 与标准 Linux 有差异,有些 GNU 工具不支持某些参数,比如tail -1这种管道用法在 ESXi 的 BusyBox 环境里有细微差别。真遇到奇怪的报错,加上完整路径、逐段用echo调试,通常能定位到问题。
5.3 克隆前后忽略客户机设置,导致一堆连锁问题
克隆出来的虚拟机如果出现网络冲突、主机名重复、UUID 混乱等问题,根源往往不是 VMware 指令本身,而是客户机操作系统层面的准备没做好。先说时间:克隆的机器时间如果和源机一致,在需要时间准确的业务里就会出现“闹鬼”现象,比如日志时间线错乱。再有就是克隆后的虚拟机 UUID,VMware 会自动生成,但如果虚拟机是通过纯文件复制方式迁移,旧 UUID 不删除,就可能出现 vCenter 里识别异常。
稳妥的步骤是:克隆前先关机源虚拟机,克隆后进入客户机重新配置主机名和 IP,确认 open-vm-tools 或 VMware Tools 版本一致。对于 Windows 客户机,熟悉系统的人会先做 sysprep,把 SID 重置。很多人跳过了这一步,批量克隆几十台机器,结果所有机器在网络邻居里长得一模一样,排查起来费劲。
5.4 快照空间被悄悄吃满
快照是增量存储,删除快照时如果虚拟机仍在运行,VMware 会先把快照差异合并到基础磁盘,这个过程需要足够的磁盘空间。在磁盘紧张的环境里执行删除快照,很可能删到一半提示“no space left on device”,虚拟机就挂在那个状态里。
我的经验是:打快照前先看一眼数据存储剩余空间,用df -h或者esxcli storage filesystem list,估算快照磁盘增长量。如果剩余空间小于虚拟机虚拟磁盘实际使用量的 30%,我不建议强行删除快照,宁可延后。另外,不要在虚拟机运行期间频繁创建和删除快照,IO 压力会被放大,生产环境尤其明显。
5.5 授权和权限边界:root 也不是万能的
很多人默认登录 ESXi 的 root 账户就能为所欲为,但实际还有很多边界。比如某些 vim-cmd 操作在集群环境下需要连接到 vCenter 的权限,如果只是主机级 root,操作范围受限;又比如在通过 SSH 执行命令时,ESXi 的默认账户没有完全等同于本地控制台的权限。
我习惯在每个指令前先想一个问题:这条命令是只影响这一台宿主机,还是会影响整个虚拟化集群?像esxcli vm process kill只影响单台机器,风险可控;但某些esxcli network或存储相关的操作,一旦误操作就是宿主机级故障。所以指令化运维的前提是先划分环境,测试环境随便折腾,生产环境先小范围验证再铺开。
每次操作前还要确认一下当前目录。ESXi Shell 不像 Linux 那样有完整的工作目录概念,很多人习惯在/下执行指令,问题不大,但如果把工作目录切到一个不存在的路径,再执行相对路径参数就会很有意思地报错。把这些细碎的问题提前规避,能少熬夜排查很多次。
兜兜转转还是那句话:指令操作不是把简单的事情变麻烦,而是把操作路径缩短到极致的办法。上面这些经验,都是我在一次次救场和踩坑中攒回来的。下次你再碰到图形界面瘫了、虚拟机起不来、几十台机器要批量处理那种情况,希望这份清单能帮你少走几步弯路。