
1. 什么场景下需要ESXi 7.0定时关机——先看清需求再动手前阵子朋友所在的实验室找到我机柜限功率晚上八点以后必须把几台跑测试的服务器关掉第二天上班再开。这个需求听着小可真动起手来我发现有不少人卡在同一个地方ESXi 7.0的Web管理界面里你只能手动点关机或重新引导压根找不到一个像Windows任务计划那样直接设置每天23:30自动关机的入口。VMware ESXi 7.0定时关机这件事说难不算难但确实需要把ESXi的命令行机制和任务调度机制都摸明白再动手。先回答最核心的问题到底什么场景真的需要用这个功能我接触下来主要是这三类。第一类是实验室和办公测试环境。很多公司的测试服务器白天跑虚拟机晚上没人看风扇嗡嗡开一整夜电费白交还得担心散热和噪音。搭配一个定时关机让ESXi凌晨两点自动断电第二天早上再远程开机工作量少电费也能省下来。第二类是限功率机柜。老旧机房或者临时机房回路功率卡得特别死几台双路服务器同时满负荷跑晚上再加夜间空调配电箱就容易顶不住。在这种环境下定时关机就是刚需不是可选项。第三类是无人值守的远程站点。像分公司弱电间、门店后仓、边缘计算盒子白天有业务晚上没有与其让ESXi在无人状态下遭遇突然断电不如到点温和关机对虚拟机和底层文件系统的保护要好得多。不过我在这里要先打一个预防针ESXi 7.0虽然基于Linux派生出了一套命令行环境但它和你在Ubuntu、CentOS上操作的习惯有很大区别。ESXi没有systemd没有systemctl传统Linux上那一套timedatectl设置时间、systemctl start crond的思维在这里会碰壁。它用的是自己的init机制BusyBox工具集一些命令的路径和Linux发行版也不完全一样。这意味着你在网上搜到的大部分Linux定时关机教程不能直接照抄得先搞懂ESXi 7.0自己的底子否则很容易出现配置明明写了到点就是不动的怪现象。1.1 三个真实场景的具体需求拿实验室来说我接手过一台跑CI构建的ESXi 7.0虚拟机白天被开发团队频繁调用晚上十点以后基本没人碰。客户想让它每天23:50自动关机省电也降低设备损耗。这里要求的就是每天定时、单机、无需人工介入的纯自动流程。还有一个门店场景ESXi放在店里的弱电箱白天开店业务系统在虚拟机里跑晚上闭店后店里断电离开。门店负责人希望ESXi在22:30自动关闭给UPS留足余量避免深夜电压波动把阵列搞出坏道。这个场景对关机的可靠性要求很高因为没人值守出了问题要第二天才能发现。第三个场景是一个企业的灾备演练定期在周末凌晨对测试ESXi做关机演练验证虚拟机快照恢复流程。这种需求需要的是可指定星期几执行的灵活调度不是每天固定时间。这三个场景看起来不同但共同需求都是单机ESXi 7.0、没有外部控制服务器、希望ESXi自己在某个时间点触发关机动作。而ESXi 7.0恰恰没有提供GUI方式的定时关机配置所以只能从命令行层面解决。1.2 ESXi 7.0的“定时任务”底子跟Linux有什么不同ESXi 7.0底层是VMkernel和传统Linux内核完全两码事。但它为了运维方便保留了一个极简的BusyBox用户态环境。这个环境里有crontab命令有esxcli命令有vim-cmd命令甚至还有vi。然而它没有systemd服务管理靠的是/etc/init.d下的脚本加chkconfig它的根文件系统是只读的很多临时修改重启后会丢它的cron服务虽然叫crond但默认是否自启、默认PATH是否和我们习惯的Linux一致都需要实际验证。这些差异决定了配置定时关机时必须额外关注三件事服务有没有起来、任务是否持久化、脚本中的命令是否能被cron环境找到。2. 四条关机路线横向对比vCenter、PowerCLI、原生crond和带外管理在正式开搞之前我想先做个方案选型。ESXi 7.0定时关机实际上不止一条路我见过的大概有四条每条都有自己的适用面。用一个表格把它们的本质区别列出来会直观很多。方案外部依赖灵活度上手成本适用场景vCenter Scheduled Task必须部署vCenter中支持主机/虚拟机的常见电源操作低GUI向导多台ESXi、已有vCenter的集群环境PowerCLI脚本 外部任务计划一台Windows/Linux管理机高可写判断和循环中要维护脚本和凭据需要批量编排、精细控制、统一审计ESXi原生crond无中主要依赖Shell脚本中纯命令行单台ESXi、无vCenter、追求零依赖IPMI/Redfish带外管理服务器BMC管理口低一般只能整机电源操作中作为最后兜底ESXi崩溃也能关机2.1 各方案优缺点与适用场景先说vCenter Scheduled Task。如果你的环境已经部署了vCenter这是最省脑子的方案图形界面上新建一个计划任务指定主机、指定时间、指定电源操作保存就完事。它还能记录每次执行的历史在vCenter的近期任务里看得清清楚楚。但它的先决条件很硬vCenter本身必须在线。如果你这台vCenter正好跑在这些ESXi上的某一台虚拟机里而计划时间点vCenter还没启动那任务根本不会触发。这种循环依赖在企业里见得太多了不得不防。再看PowerCLI。这是VMware官方的PowerShell模块通过它连到ESXi或vCenter执行Shutdown-VMHost配合Windows任务计划程序或Linux的cron就能实现任意复杂的定时关机流程。它最大的优点是可以写判断先循环关闭所有虚拟机等虚拟机都Power off之后再关主机某个虚拟机超过N分钟没关报警还是跳过都由你说了算。缺点是要额外维护一台管理机还要处理脚本里的凭据和权限问题。然后是ESXi原生crond这也是我在这类需求里最常用的方案。ESXi自带crond服务crontab语法和Linux几乎一致你只需要SSH到主机上写一条cron表达再放一个关机脚本任务就挂上了。没有任何外部依赖哪怕vCenter、管理机全挂了它也能到点执行。这也是为什么很多单机环境、实验室环境选它。缺点是要熟悉命令行而且ESXi的只读文件系统让持久化这个动作需要多留个心眼。最后是IPMI/Redfish带外管理。服务器主板上一般都有BMC管理口通过IPMI或Redfish协议即使ESXi系统早就死机了你依然能从硬件层发送Power Off指令。它可以作为其他方案的兜底假设ESXi上crond配置失败或者关机脚本中途卡死BMC总能立刻把机器拉掉。但它不太适合做精细的定时任务因为BMC通常不提供本地cron想定时还得靠外部脚本去调BMC接口配置成本反而更高。2.2 为什么常规场景下我会首选crond把四条路摆在台面上后答案其实很清楚了。如果你只是单台ESXi 7.0没有vCenter也不想折腾管理机那ESXi原生crond几乎是唯一既轻量又可靠的选择。它不需要网络上的第三方依赖不需要额外花钱不依赖任何一台常开电脑。只要ESXi自己能启动crond服务、能读取crontab、关机脚本路径放对了到点必然触发。作为一个运维老手我特别偏爱这种把逻辑放在系统内部的做法因为外部依赖越少排错的时候就越省心。哪怕你的环境已经上有vCenter我仍然建议在每台ESXi上保留crond兜底任务作为vCenter计划任务失效时的最后防线。3. 关机原语拆解esxcli system shutdown poweroff到底做了什么定时关机的核心是关机动作本身。ESXi 7.0的命令行关机入口主要有两个一个是我们已经提到的esxcli system shutdown poweroff另一个是针对虚拟机的vim-cmd vmsvc/power.shutdown。这两个命令一字之差行为完全不同必须先分开讲。3.1 命令参数与行为说明esxcli system shutdown poweroff是ESXi主机级的关机命令。完整格式是esxcli system shutdown poweroff -d 10 -r scheduled poweroff-d参数是延迟执行的秒数范围从0到86400。为什么要延迟因为直接延迟几秒会给当前正在运行的进程和虚拟机一个缓冲时间尤其当你通过SSH远程执行时你总不想让命令一敲下去自己就断线吧。-r参数是关机原因这个字符串会写进系统日志方便事后追溯。还有一个对应的重启命令esxcli system shutdown reboot -d 30 -r reboot after maintenance如果只执行esxcli system shutdown poweroff不管虚拟机会发生什么这取决于ESXi上配置的虚拟机启动/关闭策略。在vSphere Client中你可以进入主机配置的虚拟机启动/关闭里设置ESXi关机时是否向运行中的虚拟机发送优雅关机信号。如果没配置过ESXi默认直接断电虚拟机里的数据可能还没来得及落盘Windows虚拟机还可能出现系统损坏。所以我们要么提前配置好那些策略要么在关机脚本里先主动优雅关闭所有虚拟机。3.2 虚拟机优雅关机与强制断电的取舍涉及虚拟机自身常用的命令是vim-cmd vmsvc。先获取所有虚拟机的列表和VMIDvim-cmd vmsvc/getallvms输出里第一列就是VMID后面是名称和数据存储路径。拿到VMID后可以用vim-cmd vmsvc/power.shutdown VMID优雅关闭它。这个命令会调用虚拟机内的VMware Tools向Guest OS发出标准关机信号相当于你手动去操作系统里点了关机Windows和Linux都能正常保存状态。但如果虚拟机没有安装VMware Tools系统收不到信号这个优雅关机就会失败虚拟机一直保持Power On状态。备选方案是vim-cmd vmsvc/power.off VMID直接强制断电。区别类似于你点了一下系统关机菜单和你直接拔了电源线。生产环境能不用强制断电就不用但万一有虚拟机死活不关定时关机脚本总得有个最后的兜底动作否则主机永远等不到关机时机。3.3 一个可直接套用的关机脚本我把上面这些思路整合成了一个实用脚本你可以在ESXi上直接使用。脚本做的事情是先遍历所有虚拟机逐个触发优雅关机然后每5秒检查一次最多等120秒等所有虚拟机都Power off后跳出检查循环最后延迟30秒关闭主机。为了防止某个虚拟机始终关不掉拖死整个关机流程我特意设计成等待超时也继续往下走因为定时关机场景下主机比虚拟机更优先。#!/bin/sh export PATH/sbin:/bin:/usr/sbin:/usr/bin # 关闭所有虚拟机 for vmid in $(vim-cmd vmsvc/getallvms | awk NR1{print $1}) do state$(vim-cmd vmsvc/power.getstate $vmid 2/dev/null | grep -i Powered on) if [ -n $state ]; then vim-cmd vmsvc/power.shutdown $vmid fi done # 等待最多120秒确认虚拟机全部关机 i0 while [ $i -lt 24 ] do sleep 5 i$((i1)) still_running0 for vmid in $(vim-cmd vmsvc/getallvms | awk NR1{print $1}) do state$(vim-cmd vmsvc/power.getstate $vmid 2/dev/null | grep -i Powered on) if [ -n $state ]; then still_running1 break fi done if [ $still_running -eq 0 ]; then break fi done # 延迟30秒后关闭主机 esxcli system shutdown poweroff -d 30 -r scheduled poweroff by crontab这个脚本在ESXi 7.0上实测可用。要注意的是脚本开头必须写export PATH因为crond执行脚本时的PATH环境变量极其精简不主动声明的话awk、grep、vim-cmd这些命令可能找不到。另外脚本应该放在持久化数据存储如/vmfs/volumes/datastore1/scripts/下而不是放在/tmp或/root这种临时目录。4. 原生crond定时关机完整落地SSH、crontab与持久化现在进入操作核心把上面的关机脚本挂到ESXi自带的crond上。整个落地过程分五步每一步都有要注意的细节。4.1 开启SSH并确认crond守候进程第一步开启SSH服务。ESXi 7.0默认不开放SSH需要手动启用。可以在vSphere Client的主机-配置-服务里找到SSH点击启动同时把与其他主机一起启动/停止打开这样ESXi重启后SSH会自动随系统启动。也可以在DCUI界面按F2进入系统定制找到Troubleshooting Options开启SSH。如果在Web界面不方便直接用命令行vim-cmd hostsvc/enable_ssh vim-cmd hostsvc/start_ssh第二步SSH登录后确认crond服务状态。很多时候定时任务不执行根因就是crond压根没起来。检查命令/etc/init.d/crond status chkconfig --list | grep crond如果服务没跑启动它并设置开机自启/etc/init.d/crond start chkconfig crond on这步虽然简单但实在太容易被跳过了。ESXi的一些精简镜像里crond可能不是默认自启的你不确认就直接写crontab到点自然没有反应。4.2 写入定时任务crontab语法与路径规划第三步编辑root用户的crontab表。ESXi上直接执行crontab -e进入的是BusyBox自带的vi编辑器操作方法和Linux上的vi基本一致。我习惯用EDITORvi crontab -e指定编辑器。往里写入这样一行30 23 * * * /bin/sh /vmfs/volumes/datastore1/scripts/esxi-poweroff.sh /vmfs/volumes/datastore1/scripts/poweroff.log 21这一行表示每天23点30分执行关机脚本并把标准输出和标准错误都追加到日志文件。cron的五个字段依次是分、时、日、月、周和Linux完全一致。如果你想工作日关机可以写30 23 * * 1-5只留周日跑就写30 23 * * 0。保存退出后用crontab -l确认任务已经写入。还有一点值得注意cron触发时会使用root身份所以不需要担心权限问题但正因为是root关机脚本一旦写错后果也更严重。4.3 验证任务与持久化策略第四步验证。我强烈建议不要直接等第二天看结果而是先手动执行一遍关机脚本但把脚本里真正关主机的esxcli system shutdown poweroff那行注释掉先验证关闭虚拟机等待的逻辑是否正常。确认虚拟机都能正常关闭后再放开关机命令并把cron触发时间临时改成两分钟后做一次完整的定时触发测试。测试通过后再改回真实计划时间。第五步也是最容易翻车的持久化问题。ESXi的根文件系统本质是只读的运行时修改会落在内存叠加层里。这就让很多人担心crontab -e写入的任务会不会重启后消失。根据实际测试ESXi 7.0的crontab表项会持久化到配置分区重启后依然保留我验证过多次。但为了万无一失每次重启后我都建议执行一次crontab -l检查。如果真的要额外加固可以把重建crontab的命令写进/etc/rc.local#!/bin/sh echo 30 23 * * * /bin/sh /vmfs/volumes/datastore1/scripts/esxi-poweroff.sh /vmfs/volumes/datastore1/scripts/poweroff.log 21 | crontab -这样ESXi每次开机都会自动重建定时任务相当于上了一道双保险。/etc/rc.local本身在ESXi 7.0中是持久化配置文件的一部分修改后会保留。5. 踩坑实录定时关机没触发的排查链路定时任务最让人头疼的就是到点没反应。我在这上面翻过车也给不少朋友排过把最常见的问题按排查链路整理出来。5.1 第一道坎系统时区与NTP同步第一个要排查的是系统时间和时区。cron按系统时钟触发系统时间不对任务必然错乱。ESXi默认可能没有配置NTP时间会越走越偏更隐蔽的是时区问题。ESXi默认的时区可能是UTC如果你在中国期望的本地时间23:30触发系统却认为23:30是UTC时间那就是第二天早上7:30了。先用这两条命令确认esxcli system time get esxcli system timezone get如果时区不对改成Asia/Shanghaiesxcli system timezone set -z Asia/Shanghai然后配置NTP并启动同步esxcli system ntp set --serverntp.aliyun.com esxcli system ntp start配置完再用esxcli system time get确认时间已经正确。这一步极其关键很多定时关机没执行的案例查到最后都是时区差几个小时。5.2 crond服务状态与crontab表丢失第二道坎crond服务状态和crontab表内容。ESXi重启后crond服务可能没有自启或者crontab表项意外丢失。排查时依次看/etc/init.d/crond status crontab -l如果服务没起来按上一节的方法启动并设自启如果表项丢了重新写入或依赖/etc/rc.local自动重建。我见过不少人在ESXi断电重启后发现之前配的crontab消失了就是因为底层的持久化分区出了问题或是在升级ESXi时配置被重置。所以排查时别想当然一定要实际看一眼。5.3 cron环境变量差异与日志取证第三道坎cron环境与交互终端环境的差异。你在SSH里手动执行脚本好好的挂在cron里却报错大概率是环境变量问题。cron任务执行时PATH非常精简不主动声明就可能找不到命令。这也是我在开头脚本里写export PATH/sbin:/bin:/usr/sbin:/usr/bin的原因。此外脚本里所有依赖相对路径的操作都要改成绝对路径特别是日志文件、脚本自身路径。排查问题时日志是最好的证人。ESXi上cron任务的执行记录可以从/var/log/cron里看关机相关动作看/var/log/syslog和/vmkernel.log。常用取证命令grep poweroff /var/log/syslog grep cron /var/log/cron | tail -20如果cron执行了但关机失败日志里会留下明确报错如果cron连触发的痕迹都没有那就要回到时间和服务状态上找原因。5.4 一次真实故障复盘分享一个现实里的排查过程。有个朋友的实验室给ESXi 7.0配了每天早上凌晨1点自动关机结果第二天发现机器晚上没关直到当天上午9点左右才自己关掉。他还是第二天到实验室看到的整个人一脸懵。我让他先做两件事第一esxcli system time get看系统时间第二grep cron /var/log/cron | tail -20看cron日志。结果发现ESXi系统时区是UTC系统时间为UTC 01:00时确实执行了关机脚本但换算成北京时间就是上午9:00。他在配置时按本地时间写cron却忘了ESXi默认使用UTC所以时间整整差了8小时。我们把时区改成Asia/Shanghai、配置好NTP之后第二天凌晨1点关机就完全正常了。这个案例也印证了5.1节的重要性——时间与时区问题是ESXi定时任务故障里最高频的原因没有之一。6. 有vCenter时的进阶玩法Scheduled Task与PowerCLI自动化如果你的ESXi环境不止一台还部署了vCenter那我建议再往上走一层把定时关机纳入统一管理。毕竟在每台ESXi上配一遍crond虽然可靠但管理和审计都不够便捷。6.1 vCenter计划任务配置步骤与局限vCenter的Scheduled Task是个正经的GUI功能。登录vSphere Client在主机和集群界面选中要关机的ESXi主机进入配置页签找到计划任务新建一个。向导里会要求选任务类型选择电源或电源操作再设定具体的执行时间比如每天23:30然后指定操作是关闭还是重新引导。保存后vCenter会在指定时间自动调用API执行操作在近期任务里能看到执行结果。但要注意vCenter计划任务只是到点发指令至于虚拟机的处理策略依然取决于ESXi主机的虚拟机启动/关闭配置。如果你没有提前配置虚拟机关机策略vCenter同样可能直接强制断电虚拟机。所以使用之前我建议在主机配置里把虚拟机启动/关闭里的关机延迟调大给Windows虚拟机足够时间优雅退出。vCenter计划任务还有一个局限一旦vCenter本身不可用任务就不执行。这也是为什么我始终强调要在每台ESXi上留一个crond兜底。6.2 PowerCLI批量关机脚本与外部调度PowerCLI方案适合想写更复杂编排的运维。你可以在任何一台Windows管理机上安装VMware PowerCLI模块写一个脚本先连到vCenter查出来需要关机的所有主机然后遍历执行关机。下面是一个最小示例Import-Module VMware.PowerCLI -ErrorAction Stop Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false Connect-VIServer -Server vc.example.local -User admin -Password Pssw0rd $targetHosts (esxi-01, esxi-02) foreach ($hostName in $targetHosts) { $vmList Get-VMHost -Name $hostName | Get-VM # 优雅关闭该主机下所有虚拟机 $vmList | Shutdown-VMGuest -Confirm:$false Wait-Tools -VM $vmList -TimeoutSeconds 120 -ErrorAction SilentlyContinue # 关闭主机 Shutdown-VMHost -Host $hostName -Force -Confirm:$false } Disconnect-VIServer -Server * -Confirm:$false然后用Windows的任务计划程序设定每天23:30调用powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\shutdown-esxi.ps1这套方案最大的优点是编排自由度高你可以写如果所有虚拟机都关不掉就发邮件也可以写这次只关指定标签的虚拟机。不过要记住PowerCLI脚本里如果直接暴露了管理员密码生产环境是很危险的做法。建议改用vCenter的API Token或Windows凭据管理器至少不要让明文密码出现在ps1文件里。而且这个方案依赖管理机在线一旦管理机休眠整个调度就断了。所以PowerCLI更适合作为补充和批处理工具而不是唯一依赖。最后说点自己的习惯我在给真实环境落地ESXi定时关机时一般会同时铺两条线vCenter的Scheduled Task作为日常主入口负责统一管理和审计每台ESXi上的原生crond任务作为兜底层保证即使vCenter或管理机出现问题物理机到点也能自己关。两个方案互不冲突反而互补。最后分享两个小习惯第一所有定时关机脚本统一放在/vmfs/volumes/datastore1/scripts/目录日志也放同一个目录方便集中查看第二每次部署前先在测试环境跑一次完整流程确认关机脚本能正常关闭虚拟机、crond能按时触发、ESXi关机后能正常重启这三个关键点再上生产。定时关机这个需求本身不复杂但一旦漏掉其中一环深夜被报警电话叫醒的滋味可不好受。