作为一名Linux系统管理员,关机操作是最基础却最容易被忽视的技能。很多人认为关机不就是敲个命令的事?但真正在生产环境中,一个不当的关机操作可能导致数据损坏、服务中断甚至硬件故障。我曾在凌晨三点被叫起来处理因为误用poweroff命令导致的数据库损坏事故,从那以后就养成了对每个关机命令都刨根问底的习惯。
Linux系统提供了多种关机方式,每种都有其特定的使用场景和底层原理:
shutdown -h now配合手动服务停止脚本poweroff -f(但极度危险)halt命令确保所有CPU指令停止shutdown -h 22:00设置定时关机,并广播通知所有用户关键认知:关机不是简单断电,而是涉及runlevel切换、服务优雅终止、文件系统同步、硬件信号发送等一系列精密操作的流程。
shutdown是唯一能完整执行以下流程的命令:
典型使用场景:
bash复制# 立即关机(-h表示halt,也可以省略)
sudo shutdown -h now
# 10分钟后关机,并发送警告信息
sudo shutdown -h +10 "系统将于10分钟后维护关机,请保存工作!"
# 指定具体时间关机(24小时制)
sudo shutdown -h 23:30
# 取消已计划的关机
sudo shutdown -c
参数详解:
-r:重启而非关机-k:只发警告不实际关机(模拟演练时有用)--no-wall:不发送广播消息(静默关机)这两个命令常被混淆,但有着本质区别:
| 命令 | 执行动作 | 适用场景 | 危险等级 |
|---|---|---|---|
poweroff |
1. 停止所有进程 2. 直接切断电源 |
物理服务器立即断电 | ★★★★ |
halt |
1. 停止CPU工作 2. 保持电源供电 |
虚拟机暂停 硬件维护 |
★★ |
实测案例:
在KVM虚拟机上测试发现:
halt后虚拟机状态变为"Paused",可恢复运行poweroff会使虚拟机直接关闭,等同于拔电源bash复制# 标准重启(会执行完整关机流程)
sudo reboot
# 强制重启(跳过文件系统sync,危险!)
sudo reboot -f
# 关闭所有网络接口后重启(网络设备维护时使用)
sudo reboot -n
底层原理:
reboot最终会向内核发送LINUX_REBOOT_CMD_RESTART信号,触发以下流程:
通知阶段(提前至少30分钟)
bash复制wall "重要通知:系统将于30分钟后维护关机,请及时保存工作!"
服务停止(按依赖顺序)
bash复制# 停止应用服务
sudo systemctl stop nginx
sudo systemctl stop mysql
# 卸载网络存储
umount /mnt/nas
状态检查
bash复制# 检查没有用户登录
who
# 检查没有重要进程运行
ps aux | grep -E 'java|python|node'
执行关机
bash复制sudo shutdown -h +5 "最终警告:5分钟后关机!"
这是一个智能关机脚本,会在满足以下条件时自动关机:
bash复制#!/bin/bash
# 获取1分钟平均负载
load=$(cat /proc/loadavg | awk '{print $1}')
# 检查SSH连接数
ssh_conn=$(netstat -tnpa | grep 'ESTABLISHED.*sshd' | wc -l)
# 检查服务状态
nginx_status=$(systemctl is-active nginx)
mysql_status=$(systemctl is-active mysql)
if [[ $(echo "$load < 0.5" | bc) -eq 1 ]] && \
[[ $ssh_conn -eq 0 ]] && \
[[ $nginx_status == "inactive" ]] && \
[[ $mysql_status == "inactive" ]]; then
logger "满足自动关机条件,开始关机..."
shutdown -h now
else
logger "不满足关机条件:负载=$load, SSH连接=$ssh_conn, Nginx=$nginx_status, MySQL=$mysql_status"
exit 1
fi
通过cron实现工作日凌晨自动关机:
bash复制# 编辑root的crontab
sudo crontab -e
# 添加以下内容(周一至周五凌晨1点关机)
0 1 * * 1-5 /sbin/shutdown -h +5 "系统将在5分钟后自动关机,请保存工作!"
cron时间格式备忘:
code复制* * * * *
| | | | |
| | | | +----- 星期几 (0 - 6) (周日=0)
| | | +------- 月份 (1 - 12)
| | +--------- 日 (1 - 31)
| +----------- 小时 (0 - 23)
+------------- 分钟 (0 - 59)
对于文中提到的四台互相mount的Linux主机,必须按特定顺序关机:
确定依赖关系:
bash复制# 查看所有挂载点
mount | grep nfs
# 输出示例:server1:/data on /mnt/server1_data
编写协同关机脚本:
bash复制# 在挂载端执行(client)
umount /mnt/server1_data
ssh root@server1 "shutdown -h now"
# 等待server1确认关闭
ping -c 5 server1 > /dev/null || echo "Server1已关闭"
# 然后关闭本机
shutdown -h now
问题1:关机卡住无法完成
bash复制# 查看是否有僵尸进程
ps aux | grep 'Z'
# 检查磁盘IO等待
iostat -x 1
bash复制# 尝试强制切换到单用户模式
init 1
# 然后手动停止问题服务
kill -9 <PID>
问题2:关机后自动重启
bash复制# 查看当前配置
cat /proc/acpi/event
# 临时禁用(下次启动会恢复)
echo "disable" > /proc/acpi/event
bash复制# 编辑grub配置
sudo nano /etc/default/grub
# 在GRUB_CMDLINE_LINUX添加 reboot=acpi
sudo update-grub
在VMware/KVM环境中,建议:
先关闭虚拟机:
bash复制# VMware ESXi
vim-cmd vmsvc/power.off <vmid>
# KVM
virsh shutdown <domain>
等待30秒确认关闭:
bash复制virsh list --all | grep <domain>
如仍运行,强制关闭:
bash复制virsh destroy <domain>
通过sudoers限制:
bash复制# 允许特定用户组关机
%operators ALL=(root) /sbin/shutdown -h now
# 禁止其他用户
Defaults !shutdown
通过polkit规则(现代Linux发行版):
bash复制# 创建规则文件
sudo nano /etc/polkit-1/rules.d/80-disable-shutdown.rules
# 内容如下:
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.login1.power-off" ||
action.id == "org.freedesktop.login1.reboot") {
return subject.isInGroup("admins") ? polkit.Result.YES : polkit.Result.NO;
}
});
配置rsyslog记录所有关机事件:
bash复制# 在/etc/rsyslog.conf添加
auth,authpriv.* /var/log/shutdown.log
# 重启服务
systemctl restart rsyslog
使用auditd进行更详细审计:
bash复制# 添加审计规则
sudo auditctl -a exit,always -F arch=b64 -S kill -F a1=15 -k shutdown_signal
# 查看日志
ausearch -k shutdown_signal | aureport -i
对于有大量服务的系统,可以:
并行停止服务:
bash复制# 修改systemd配置
sudo systemctl edit --global
# 添加以下内容
[Manager]
DefaultTimeoutStopSec=10s
禁用不必要的服务:
bash复制# 查看启动时间长的服务
systemd-analyze blame
# 禁用非关键服务
sudo systemctl disable bluetooth.service
对于顽固进程:
使用组合信号:
bash复制# 先发SIGTERM(15)
kill -15 <PID>
# 等待5秒后发SIGKILL(9)
sleep 5
kill -9 <PID>
使用专用工具:
bash复制# 使用timeout命令
timeout -k 5 10s /path/to/stubborn_process
现代服务器通常有:
shutdown),长按强制断电建议配置:
bash复制# 禁用NMI按钮
echo 1 > /proc/sys/kernel/nmi_watchdog
# 设置电源按钮行为(改为休眠)
sudo nano /etc/systemd/logind.conf
# 设置 HandlePowerKey=hibernate
对于RAID系统:
关机前刷新缓存:
bash复制# 查看阵列状态
cat /proc/mdstat
# 手动刷新
echo check > /sys/block/md0/md/sync_action
正确关机顺序:
bash复制# 先停用阵列
mdadm --stop /dev/md0
# 再正常关机
shutdown -h now
优雅停止所有容器:
bash复制docker stop $(docker ps -q)
等待容器停止(最多30秒):
bash复制docker ps --filter "status=running" --format "{{.ID}}" | xargs -r docker wait
然后执行主机关机。
对于K8s节点:
标记节点不可调度:
bash复制kubectl cordon <node-name>
驱逐所有Pod:
bash复制kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
确认节点已清空:
bash复制kubectl get pods --all-namespaces -o wide | grep <node-name>
最后执行关机。