Appearance
日常运维操作规范
运维操作的风险不在命令本身,在命令执行的范围、对象和有没有退路。同样的 rm,删一个临时文件和删整个数据目录,后果完全不一样。这篇文章整理日常操作流程里几个关键节点:操作分级、变更前确认、回滚准备、危险命令控制和操作留痕。
一、操作分级:不是所有事都需要同样流程
查一条日志和重启核心数据库,风险不一样,流程也应该不一样。按影响面和可逆程度,大致可以分几类:
| 类型 | 例子 | 处理方式 |
|---|---|---|
| 只读操作 | tail -f、systemctl status、cat 配置文件 | 影响小,但要防误进入编辑模式——vim 里不小心按了 dd 这种 |
| 低风险变更 | 修改日志级别、调整监控阈值、加一条非关键的 cron | 记录改了什么、怎么退回来 |
| 中风险变更 | 重启单个业务实例、发布非核心服务 | 选业务低峰窗口、确认影响范围、准备回滚命令 |
| 高风险变更 | 数据库结构变更、批量删除、防火墙策略调整、核心服务重启 | 工单驱动、审批确认、双人复核、回滚方案事先演练 |
| 应急操作 | 线上故障、服务中断 | 以恢复服务为第一优先级,操作过程尽量留痕,恢复后补复盘 |
一个操作如果带"批量"和"删除"这两个属性,风险等级要往上提一档。单机的一条危险命令,在批量循环里可能变成一次小规模事故。
二、操作前:确认操作对象是对的
连上机器后第一件事不是动手,是确认对象。尤其在多窗口、多标签页、堡垒机同时开着几台机器的时候:
bash
hostname
hostname -I
whoami
pwd四条命令,两秒钟,能挡住连错机器、用错账号、进错目录这种低级但常见的问题。
变更前把这几件事想清楚:
| 确认什么 | 为什么 |
|---|---|
| 机器身份 | 主机名、IP、哪个环境(测试/预发/生产)、在集群中的角色 |
| 当前状态 | 服务是否正常、有没有未处理的告警、是否正在被其他变更占用 |
| 操作账号 | 是不是该用的用户、会不会不小心用了 root |
| 影响范围 | 单机、单可用区、还是全集群 |
| 上下游依赖 | 上面谁在调用、下面依赖哪个数据库/队列/缓存 |
| 回滚方式 | 配置回退的备份在哪、版本回退的命令、数据恢复的方式和时间 |
| 观察指标 | 改完后看哪几个监控、哪段日志 |
操作前看服务当前是否正常:
bash
systemctl status nginx --no-pager
journalctl -u nginx -n 50 --no-pager--no-pager 避免输出停在 less 里——脚本里或远程批量执行时,卡在分页器等于卡死整条流程。
看当前监听和连接数:
bash
ss -lntp
ss -antp | grep ':80'如果准备改 Nginx 配置,要先知道它现在是否正常监听、当前有多少连接。服务本来就异常了,改完配置后的行为不能简单归因于这次变更。
三、操作窗口:不只是"人少的时候"
选操作窗口要看的不只是业务低峰:
| 项目 | 说明 |
|---|---|
| 业务低峰 | 减少对用户的直接影响 |
| 有人能响应 | 出了事不是孤军奋战 |
| 上下游有人 | 网络、DB、应用、业务方能在同一段时间内响应 |
| 监控正常 | 改完能观察到指标变化,不会因为监控本身挂了而漏掉问题 |
| 避开并发变更 | 多个变更同时进行,出了问题哪个导致的都分不清 |
数据库结构变更、网络策略收敛、批量重启这类操作,不适合卡在下班前做——做完了人都走了,没人观察。第二天再发现问题,现场信息已经少了很多。高风险变更放在"人都在、业务相对低峰"的时间,比单纯追求半夜更安全——半夜人困、反应慢、能帮忙的人也少。
四、回滚方案:能说清楚步骤才算有
只说"支持回滚"等于没说。要能真的写出回滚命令。
配置变更前,备份原文件:
bash
cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%F-%H%M%S).bakcp -a 保留原文件的权限、时间戳和链接属性。配置回退时这些信息有用。
修改之后先检查语法,确认通过再加载:
bash
nginx -t
systemctl reload nginx回滚时同样要先检查语法:
bash
cp -a /etc/nginx/nginx.conf.2026-05-21-230000.bak /etc/nginx/nginx.conf
nginx -t # 旧配置≠一定正确,期间环境可能已经变了
systemctl reload nginx应用发布如果用软链接切版本,回滚比覆盖式发布清晰得多:
text
/opt/myapp/releases/
├── 20260521-2100/
├── 20260521-2230/
└── current -> /opt/myapp/releases/20260521-2230切回旧版本只需更新软链接:
bash
ln -sfn /opt/myapp/releases/20260521-2100 /opt/myapp/current
systemctl restart myappln -sfn 中的 -n 很重要——如果 current 已经是一个指向目录的软链接,不加 -n 会在原目录内部创建链接,而非替换 current 本身。
数据库变更的回滚最复杂。DDL、数据修复、批量删除——靠"备份恢复"四个字是不够的。需要知道恢复要多久、会不会覆盖新数据、业务能不能等这么久。操作前就评估清楚,而不是出了问题再想。
五、双人确认:不是陪看屏幕,是复核关键事实
另一个人站在旁边看着屏幕,和真正的双人确认是两回事。双人确认是让另一个人独立审视关键事实,不是"帮我看下这个命令写得对不对"。
需要双人确认的操作:
| 操作 | 复核人要看什么 |
|---|---|
| 批量删除 | 目录对不对、匹配条件对不对、有备份吗 |
| 数据库变更 | 库名、表名、WHERE 条件、字段、有没有先备份 |
| 防火墙调整 | 源地址、目标端口、会不会把自己挡在外面、有回滚入口吗 |
| 生产重启 | 剩余实例数、流量是否已摘除、健康检查是否正常 |
| 权限开通 | 用户是谁、资产范围、账号级别、有效期到了没有 |
确认时要说明意图,不只是把命令贴过去让人看。比如:
text
准备删除 /data/app/tmp 下 7 天前的临时文件。
不涉及 /data/app/upload。
已确认备份不依赖 tmp 目录的内容。
先执行 find -print 看范围,确认后再执行删除。完整的意图描述比裸贴一条命令更容易让人发现问题——对方可能会想到你没想到的东西,比如"tmp 里是不是有一周的部署回滚包"。
六、几类危险命令的防护
rm
删除前先用 find -print 看将要操作的范围:
bash
find /data/app/tmp -type f -mtime +7 -print确认文件列表符合预期,再删除:
bash
find /data/app/tmp -type f -mtime +7 -deleterm -rf 配合变量使用时风险很高:
bash
rm -rf $dir/*如果 $dir 因为什么原因变成了空字符串,这条命令实际执行的可能是 rm -rf /* 或者 rm -rf /some/default/*。脚本里至少要有变量检查:
bash
target_dir="${1:-}"
if [ -z "$target_dir" ] || [ "$target_dir" = "/" ]; then
echo "invalid target dir: $target_dir" >&2
exit 1
fi
rm -rf -- "$target_dir"/*-- 告诉命令"后面的参数都是路径,不是选项"——防止文件名如果以 - 开头(比如有人创建了 -rf 文件),被命令当成选项参数处理。
rsync --delete
预演是必须的步骤,不是可选的:
bash
rsync -avh --delete --dry-run /srv/app/dist/ web@192.168.10.30:/var/www/app/--delete 本身没有问题,问题出在源路径和目标路径写错。路径写错时,rsync 会很认真地把写错的那个目录删干净。
chmod 和 chown
递归改权限前,先确认范围和当前状态:
bash
find /opt/myapp -maxdepth 2 -printf '%m %u:%g %p\n' | head再执行:
bash
chown -R app:app /opt/myapp
chmod -R u=rwX,go=rX /opt/myappX(大写)表示只给目录和原本就有执行位的文件加执行权限。和 chmod -R 755 的区别是:X 不会给普通数据文件(.conf、.html、.log)加上执行权限。应用目录里适合用 X,而不是无差别地给所有文件加执行位。
在系统目录做递归权限修改的破坏性极大:
bash
chmod -R 777 /var # 把权限体系打穿遇到权限问题时,应该定位具体的文件和进程用户来做针对性的调整,而不是用全局放开来解决一个局部问题。
kill
先从正常停止开始:
bash
systemctl stop nginx再考虑发信号:
bash
kill -TERM <pid> # 请求进程正常退出:关闭连接、清理临时文件、写日志
kill -KILL <pid> # 强制终止:不给进程任何清理机会kill -9(等于 kill -KILL)只是把进程的存在抹掉,不代表服务状态恢复,也不给进程清理连接和文件状态的机会。数据库进程被 kill -9 后,恢复时可能要做 crash recovery,比正常关闭后再启动慢很多。
七、批量操作:控制范围和节奏
全量批量操作把"一条命令的影响"放大了 N 倍:
bash
for host in $(cat hosts.txt); do
ssh "$host" 'systemctl restart myapp'
done安全的做法是先单台验证,再分批推进:
bash
# 第一步:只挑一台验证
head -n 1 hosts.txt | while read -r host; do
ssh "$host" 'hostname; systemctl restart myapp; systemctl is-active myapp'
done
# 第二步:确认单台没问题后,串行分批
while read -r host; do
echo "restart $host"
ssh "$host" '
set -e
systemctl restart myapp
systemctl is-active --quiet myapp
'
sleep 10 # 给监控和负载均衡观察和摘除的时间
done < hosts.txt串行分批虽然慢,但每一步都可控。生产环境的批量操作不追求速度,追求失败时影响范围最小。
需要并发时,用 xargs -P 限制并发数:
bash
cat hosts.txt | xargs -I{} -P 5 sh -c '
host="$1"
echo "restart $host"
ssh "$host" "systemctl restart myapp && systemctl is-active --quiet myapp"
' sh {}-P 5 限制最多同时跑 5 个。并发数要结合服务容量和负载均衡摘除策略来定——比如 5 个实例同时重启,剩下的是否能扛住全部流量。
八、操作留痕
操作过程需要能被追溯。至少记录这些:
| 内容 | 具体是什么 |
|---|---|
| 操作人 | 堡垒机用户、目标系统用户 |
| 时间 | 开始时间和结束时间 |
| 目标 | 主机、服务、数据库、集群 |
| 关键命令 | 执行了什么命令,用的哪个版本的脚本 |
| 结果 | 成功还是失败;如果失败,有没有回滚,回滚是否成功 |
| 证据 | 日志片段、监控截图、工单链接 |
用 script 记录整个终端会话:
bash
script -a /var/log/ops/$(date +%F-%H%M%S)-change.log退出记录时输入 exit。
单条脚本用 tee 留日志:
bash
./deploy.sh 2>&1 | tee deploy-$(date +%F-%H%M%S).log堡垒机的审计是系统侧的记录,适合事后追溯和合规检查。自己留的操作日志更适合复盘和交接——哪些步骤顺利、哪里卡住了、下次遇到类似情况要注意什么。
九、变更后的观察和确认
变更完成不等于结束,要确认变更生效且没有引入新问题。
| 检查项 | 怎么确认 |
|---|---|
| 服务是否正常 | systemctl status service --no-pager |
| 有没有新报错 | journalctl -u service -n 100 --no-pager |
| 端口是否监听 | ss -lntp |
| 健康检查 | curl -fsS http://127.0.0.1:8080/healthz |
| 业务指标 | QPS、错误率、延迟和变更前对比 |
| 系统指标 | CPU、内存、磁盘、网络是否有异常波动 |
curl -fsS 的判断逻辑:-f 在 HTTP 4xx/5xx 时返回非 0,脚本里可以直接用退出码判断健康检查是否通过。如果用浏览器打开页面,状态码 500 和 200 在视觉上可能看不出差别。
多实例的变更,只看单机健康不够——还要看负载均衡有没有把流量正确分发、服务发现有没有摘掉异常实例、整体错误率有没有上升。单实例健康不等于业务健康。
十、应急操作:故障中的底线
故障中节奏会变快,压力会变大,但有几条底线要守住:
| 底线 | 为什么 |
|---|---|
| 以恢复服务为第一优先级 | 降级、摘流量、扩容、回滚——先让业务恢复,再研究根因 |
| 少做不可逆操作 | 删数据、清日志、重建集群——这些动作可能让故障升级成事故 |
| 保留现场 | 关键日志、错误信息、时间点——事后复盘需要这些 |
| 单点指挥 | 避免多人同时改同一系统,状态越改越乱,最后连哪个动作产生了效果都不知道 |
| 事后补齐记录 | 应急时来不及写,恢复后立即补上操作步骤和时间线 |
故障时的基本现场保存:
bash
mkdir -p /tmp/incident-$(date +%F-%H%M%S)
cd /tmp/incident-*
hostname > host.txt
date > date.txt
ip addr > ip-addr.txt
ip route > ip-route.txt
ss -antp > ss-antp.txt
journalctl -n 500 --no-pager > journal-last-500.txt这只是最基础的现场快照,不是完整的故障诊断流程。内容可能包含敏感信息(IP 地址、连接信息),保存和使用时注意。对于某些严格环境,这些采集命令本身也需要纳入操作审批。
十一、一个简单的操作记录模板
text
变更名称:
操作人:
操作时间:
目标环境:
目标主机:
变更内容:
影响范围:
回滚方案:
操作前状态:
执行命令:
操作后验证:
异常与处理:模板的作用不是把流程变复杂,而是让自己第二天打开还能看懂:当时为什么做这件事、做了什么、结果怎样、出了问题怎么退。