1. 需求场景与整体思路
一台ESXi 7.0主机放在机房里,白天业务跑着,晚上十点以后基本没人用,可机器还在那里嗡嗡转。电费倒是其次,风扇积灰、噪音干扰、硬件损耗,加上一些低负载服务其实根本不需要24小时在线——很多人这时候就想要一个定时关机功能。你打开vSphere Client翻了一圈,图形界面里愣是找不到“计划任务关机”这个按钮,于是就来搜VMware ESXi 7.0定时关机了。
先说结论:ESXi本身不是一个完整意义上的Linux发行版,它没有systemd、没有cronie,也不像Windows那样在图形界面里给你一个“任务计划程序”。但它保留了cron机制和esxcli命令行体系,所以我们可以通过编辑/etc/crontab,让主机在指定时间自动执行关机动作。这个方法我在多个版本上都实测过,从ESXi 6.7到7.0 U3都适用,核心思路完全一致。
这篇文章适合谁看?如果你是机房管理员、实验室负责人、家庭虚拟化玩家,或者公司有一台ESXi只跑非关键业务测试机,那这套方案可以直接抄作业。它解决的问题很具体:人不在现场,机器到点自己关,不依赖额外服务器,不依赖vCenter,不依赖物理定时插座。
我把整体思路先摆出来,后面按步骤拆:
- 先处理虚拟机,再关主机。直接拔电或强制poweroff主机,ESXi会尝试恢复VMFS锁,严重时虚拟机文件可能损坏。
- 用esxcli命令关闭ESXi宿主机,不用shutdown命令,也不建议写init 0,因为esxcli才是ESXi官方支持的电源管理入口。
- 把上述动作写成一个sh脚本,存到datastore上。
- 在/etc/crontab里加一行定时规则,让系统在指定时间调用脚本。
- 做完持久化处理,防止ESXi重启后配置丢失。
这套流程零依赖,ESXi只要能联网、能跑SSH就行。而且有一个很大的好处:关机前可以把虚拟机先优雅关机或挂起,下次开机恢复速度比冷启动快得多。
2. 关机前的关键动作:先处理虚拟机
2.1 为什么不能直接关ESXi主机
ESXi主机相当于一个虚拟机监视器,它上面跑的每一台虚拟机都有内存状态、存储I/O、网络连接。如果直接给宿主机断电,虚拟机相当于“物理机突然拔电”,guest OS里的文件系统缓存来不及落盘,数据库可能直接损坏。即便某些应用有日志恢复机制,这种非正常断电的恢复过程也相当耗时。
更麻烦的是ESXi本身的存储层。VMFS是共享文件系统,突然断电后卷锁可能残留,主机重启时会进入锁恢复流程。磁盘越多、虚拟机越多,恢复时间越长。我自己遇到过一次,四块盘RAID5的机器,直接拉闸后ESXi启动花了将近二十分钟做卷检查,最后还有一台Windows虚拟机引导失败,只能进恢复模式修引导记录。
所以定时关机脚本里,第一步永远是把所有运行中的虚拟机关闭或挂起。
2.2 获取虚拟机列表和电源状态
先用一个命令拿到所有虚拟机的ID:
vim-cmd vmsvc/getallvms输出格式类似这样:
Vmid Name File Guest OS Version Annotation 10 windows-server-01 [datastore1] windows-server-01/windows-server-01.vmx windows9Guest vmx-15 14 ubuntu-nginx [datastore1] ubuntu-nginx/ubuntu-nginx.vmx ubuntu64Guest vmx-19第一列Vmid就是虚拟机ID,后面脚本里要反复用到。注意这个ID每次主机重启后可能变化,所以脚本里不能写死,必须动态获取。
查询某一台虚拟机的电源状态用:
vim-cmd vmsvc/power.getstate 10输出一般是“Powered on”或者“Powered off”。
2.3 优雅关机与强制关机的取舍
关闭虚拟机我有两个选择:
# 优雅关机,相当于在虚拟机里执行正常关机流程 vim-cmd vmsvc/power.shutdown 10 # 强制断电,相当于长按电源键或拔插头 vim-cmd vmsvc/power.off 10生产环境优先考虑power.shutdown,这个命令会向虚拟机发送ACPI关机信号,要求guest OS里的VMware Tools配合执行正常关机。只要虚拟机装了VMware Tools,并且操作系统开启了ACPI电源管理,绝大多数Linux和Windows都能在一分钟内正常关掉。
但power.shutdown有个明显的坑:如果虚拟机里VMware Tools没装、或者系统卡死,ACPI信号发了也没人响应,命令会一直卡在那里,没有任何报错。所以脚本里不能只调用一次shutdown就完事,必须做超时检查。
我的做法是给每台虚拟机发shutdown信号,然后sleep 90秒,再轮询电源状态。还开着的虚拟机,说明guest OS已经失去响应,这时候只能走power.off强制断电。这个“先优雅、后强制”的策略,既能保证绝大多数虚机干净关闭,又能避免脚本卡死导致宿主机无法按时关机。
2.4 另一个选项:挂起而不是关机
如果你不追求完全关机,只是想省电,那挂起是比关机更合适的方案。挂起相当于把虚拟机的内存状态完整保存到vmx文件所在的目录,下次启动只需几十秒就能恢复到挂起前的桌面状态,所有打开的窗口、未保存的文档都在。
vim-cmd vmsvc/power.suspend 10挂起同样要求VMware Tools配合。如果Tools异常,挂起操作也会失败。但相比关机,挂起基本不涉及文件系统层面的风险,因为内存状态是VMware自己管理的,guest OS并不知道自己被“暂停”了。
我的个人建议是:对于开发测试虚拟机,优先挂起;对于生产业务虚拟机,按正常关机流程走。
#!/bin/sh # ESXi定时关机脚本 # 放到 /vmfs/volumes/datastore1/scripts/poweroff.sh # 1. 优雅关闭所有虚拟机 VMS=$(vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}') for VM in $VMS; do PWR=$(vim-cmd vmsvc/power.getstate $VM | tail -1) if [ "$PWR" == "Powered on" ]; then vim-cmd vmsvc/power.shutdown $VM >/dev/null 2>&1 fi done # 2. 等待90秒,给虚拟机足够时间完成关机 sleep 90 # 3. 检查还在运行的虚拟机,强制断电 for VM in $VMS; do PWR=$(vim-cmd vmsvc/power.getstate $VM | tail -1) if [ "$PWR" == "Powered on" ]; then vim-cmd vmsvc/power.off $VM >/dev/null 2>&1 fi done # 4. 延迟10秒后关闭ESXi宿主机,避免误操作 esxcli system shutdown poweroff -d 10 -r "scheduled shutdown by crontab"这个脚本的逻辑很直白,但有几个地方必须解释一下:
awk 'NR>1 {print $1}'用来跳过getallvms输出的第一行表头,只取虚拟机ID。tail -1是因为power.getstate的输出有两行,第一行是VMid,最后一行才是电源状态。- sleep 90不是拍脑袋定的,一般Windows虚拟机启动关机流程到完全断电需要30到50秒,Linux更快,90秒是个比较平衡的超时值。如果你机器比较老,可以拉到120秒。
- esxcli system shutdown poweroff后面的-d 10表示延迟10秒再关机,这10秒是为了让脚本有足够时间回写日志、释放SSH会话。
3. crontab定时任务实操
3.1 ESXi的cron机制
ESXi的cron和Linux的cron本质上是一回事,配置文件都在/etc/crontab。你可以用root账户通过SSH登录ESXi,直接查看、编辑这个文件。
ESXi默认的/etc/crontab里面已经有一堆系统任务,比如日志轮转、健康检查、性能数据采集。可以参考一下这些系统自带条目的写法,它们就是ESXi官方认可的cron格式:
# 分 时 日 月 周 用户 命令 0 2 * * * /usr/lib/vmware/vmksummary/log-event.sh */5 * * * * /sbin/auto-backup.shESXi里所有cron条目都以root身份运行,用户字段留空即可,不需要也不建议指定其他用户。
3.2 写crontab条目
假设我把刚才那个poweroff.sh脚本放在了/vmfs/volumes/datastore1/scripts/目录下,先给它加执行权限:
chmod +x /vmfs/volumes/datastore1/scripts/poweroff.sh然后编辑crontab:
vi /etc/crontab在文件末尾加入一行:
0 23 * * * /vmfs/volumes/datastore1/scripts/poweroff.sh这行的含义是:每天23点00分执行一次poweroff.sh脚本。cron的五个时间字段分别是分钟、小时、日期、月份、星期,这里*表示不限制。
改完保存,重启cron服务让配置生效:
/etc/init.d/cron restart注意重启cron服务不会影响系统其他服务,这个操作很安全,可以放心执行。
3.3 一个非常容易踩的时区坑
ESXi默认的时区是UTC,不是北京时间。如果你配置的是0 23 * * *,在中国大陆的服务器上,实际触发时间是UTC 23点,也就是北京时间第二天早上7点。很多人配完发现第二天早上机器自己关了,就是栽在这个时区问题上。
处理办法有两个:
第一种,设置ESXi时区为Asia/Shanghai:
esxcli system timezone set -z Asia/Shanghai设置完用date确认时间显示正确,然后用esxcli system time get看系统时间是否已经同步。改完时区后,cron就会按照本地时间触发。
第二种,不换时区,手动换算时间。如果你是UTC+8,想在北京时间23点关机,cron里要写0 15 * * *。这个方法不推荐,因为等到夏令时切换(虽然中国没有夏令时,但搞海外服务器的人会遇到)换算会乱套。
我建议直接用esxcli system timezone set -z Asia/Shanghai命令改时区。ESXi 7.0支持标准的tzdata城市名,Asia/Shanghai是非常稳妥的写法。
3.4 验证cron有没有真正生效
配置完成之后,最怕的就是看着一切正常,到点不执行。我常用的验证方法有三个:
先查看crontab内容确认条目写进去了:
cat /etc/crontab再看cron日志确认服务在跑:
tail -f /var/log/cron手动执行一次脚本,验证脚本本身没有问题:
/bin/sh /vmfs/volumes/datastore1/scripts/poweroff.sh如果你不想真关机,可以先把脚本最后一行esxcli system shutdown poweroff注释掉,手动执行只验证虚拟机关闭逻辑,等确认无误再恢复注释。
另外提一句测试技巧:cron最小精度是分钟,所以测试时间配置不要写“几天后的某个点”,直接把时间设成当前时间后两分钟,比如当前14:35,就写37 14 * * *,等两分钟看是否触发,这样效率最高。
4. 持久化与扩展任务
4.1 重启后crontab配置会丢吗
ESXi的根文件系统是内存盘+只读镜像的组合,不是标准的可写磁盘。你在/etc/crontab里的修改,理论上会保存在内存盘里,一旦重启主机,这些修改可能全部丢失。
有人会说“我改完后重启了没丢啊”,这是因为ESXi有节点持久化机制,会自动把/etc目录下部分关键配置备份到bootbank。但crontab这种文件能不能被自动备份,跟ESXi版本和补丁级别有关系,不能赌。
最稳的方案是把脚本放在datastore上,同时把crontab的追加操作写进开机启动脚本。ESXi每次启动时会执行/etc/rc.local.d/local.sh,这个脚本本身受系统持久化保护,不会丢。
在local.sh里追加这样几行:
#!/bin/sh # 开机时把定时关机任务写入crontab if ! grep -q "poweroff.sh" /etc/crontab; then echo "0 23 * * * /vmfs/volumes/datastore1/scripts/poweroff.sh" >> /etc/crontab /etc/init.d/cron restart fi这里用了grep -q判断,防止同一行内容被重复追加。local.sh需要可执行权限:
chmod +x /etc/rc.local.d/local.sh这样即使ESXi重启,开机后也会自动恢复定时任务,不需要人工干预。
4.2 定时开机怎么配
定时关机解决了,很多人紧接着问定时开机。ESXi自身没有直接的“定时开机”命令,因为宿主机的电源管理在硬件层,操作系统还没起来的阶段,什么软件都跑不了。但可以分两种情况处理:
如果你的服务器主板支持RTC Wake(实时时钟唤醒),进BIOS里找“Resume by RTC Alarm”或者“Wake on RTC Alarm”选项,设置每天的唤醒时间。这个功能不依赖操作系统,ESXi关机状态下也能用,是纯硬件的定时开机方案。
如果服务器有带外管理模块,比如iLO、iDRAC、BMC之类,也可以通过带外管理界面配置定时开机或远程开机。这个比BIOS里的RTC Wake更灵活,还可以设置每天、每月的周期规律。
最实用的组合拳是:晚上23点ESXi定时关机,早上8点BIOS的RTC Wake定时开机,全程不需要人工参与。
4.3 定时挂起与定时重启
如果不想真正关机,可以把脚本改成定时挂起:
#!/bin/sh VMS=$(vim-cmd vmsvc/getallvms | awk 'NR>1 {print $1}') for VM in $VMS; do PWR=$(vim-cmd vmsvc/power.getstate $VM | tail -1) if [ "$PWR" == "Powered on" ]; then vim-cmd vmsvc/power.suspend $VM >/dev/null 2>&1 fi done sleep 10 esxcli system shutdown poweroff -d 0 -r "suspend all vms and poweroff"注意挂起不需要等那么久,每台虚拟机几秒钟就能完成状态保存,sleep 10足够。
定时重启就是把最后一行改成:
esxcli system shutdown reboot -d 10 -r "scheduled reboot"esxcli system shutdown支持poweroff和reboot两个操作,参数完全一致,改起来非常方便。
5. 常见问题与排查技巧
5.1 到了时间机器没关机
这是最常见的故障。排查顺序按优先级来:
第一,检查crontab是否真的写进去了。用cat /etc/crontab看有没有那条记录,特别要注意是不是编辑完忘了重启cron服务。
第二,检查系统时间是不是对的。用date命令看当前时间,用esxcli system time get看系统时间。ESXi自己有NTP配置,但如果NTP服务没启动,时间可能慢慢漂移,导致到点不触发。
第三,手动执行一次脚本,看脚本输出什么报错。重点看路径问题,在ESXi里/vmfs/volumes/datastore1/是实际存储路径,如果datastore名称带空格或者不是datastore1,路径就会错。
第四,查看/var/log/cron日志。如果cron触发过但脚本执行失败,日志里会有记录。
5.2 虚拟机长时间无法关机
power.shutdown发的是ACPI关机信号,如果虚拟机里VMware Tools没装、Tools服务没启动、或者操作系统处于死机状态,这个信号就相当于敲了一扇没有人的门。
解决思路只有一个:在脚本里把超时机制做强。我前面那版脚本sleep 90之后强制power.off,就是兜底手段。如果你有某台虚拟机特别慢,可以把sleep拉长,或者单独对慢机子做特判。
另外提一点,强制power.off的虚拟机,下次启动时会进入文件系统检查流程。Linux一般自动修复,Windows可能进入启动修复界面,这都是正常现象,不用慌。
5.3 vim-cmd命令报错“Unable to connect”
在SSH里手动执行vim-cmd遇到“Unable to connect to socket”之类的报错,一般是hostd服务异常。先检查hostd状态:
/etc/init.d/hostd status如果hostd挂了,重启一下:
/etc/init.d/hostd restart注意hostd是ESXi的核心管理服务,vSphere Client、vim-cmd都依赖它,这个服务重启期间,虚拟机会正常运行,但管理操作会短暂中断几秒到几十秒。
5.4 问题排查速查表
| 症状 | 可能原因 | 解决动作 |
|---|---|---|
| 到点不关机 | crontab没生效 | 修改后执行/etc/init.d/cron restart |
| 到点不关机 | 系统时间不对 | 检查date、配置NTP或esxcli timezone |
| ESXi关机了虚拟机没关 | grep匹配失败 | 检查Vmid是否变化,改用动态获取 |
| 虚拟机一直关不掉 | VMware Tools未安装 | 改用vim-cmd vmsvc/power.off |
| 脚本执行报错 | 路径不对 | 用完整路径,少用相对路径 |
| 重启后定时任务丢失 | crontab未持久化 | 写入/etc/rc.local.d/local.sh |
| 关机时间差8小时 | 时区默认UTC | esxcli system timezone set -z Asia/Shanghai |
5.5 我踩过的几个坑
我最早配定时关机是直接在/etc/crontab里面写了一个调用远程脚本的命令,结果脚本放在NFS共享上,ESXi开机时NFS还没挂载好,cron执行直接找不到文件。后来所有脚本一律放本地datastore,问题再没出现过。
还有一个教训是:别用init 0关ESXi。在ESXi 7.0里,init 0的行为不是标准Linux关机流程,有时会跳过一些VMkernel的清理步骤。官方支持的关机命令就是esxcli system shutdown poweroff,没有之一。
最后关于sleep时间的把握,我见过有人把sleep 90改成sleep 3,觉得虚拟机们都关得很快,结果有台虚拟机50秒才完成关机流程,强制power.off直接导致Windows作系统文件检查。这个时间宁可长一点,也不要短。
6. 一些个人经验
做这套定时关机配置,最核心的收获是:ESXi虽然看起来是个封闭的虚拟化系统,但它保留了足够的命令行接口和任务调度能力,稍微花点时间,就能在官方图形界面之外实现很多自动化运维场景。定时关机只是其中一个例子,同样的思路可以扩展到定时挂起、定时重启、定时备份虚拟机快照。
我个人在配置过程中的体验是,把脚本放在datastore上,再通过local.sh自动恢复crontab条目,这套双保险非常靠谱。机器重启几次都不会掉配置。而且手动执行脚本的验证方式,让我能在正式设定时任务前把所有问题都暴露掉,避免第二天一早到机房发现机器没关、白花一夜电费。
如果你只是想在特定时间让虚拟机不耗电,挂起方案其实是体验最好的;如果需要彻底关机断电,那就按本文的完整方案走。配置过程中如果遇到vim-cmd的各种输出格式变化,记住一点:先手动执行看输出,再写进脚本,永远不要凭记忆猜命令输出格式。