运维提效利器:实战自动化脚本分享,告别重复造轮子

在现代IT运维体系中,面对动辄成百上千的服务器节点,纯手工操作不仅效率低下,且极易因人为疏忽引发线上事故。自动化运维不仅是技术的升级,更是运维理念的蜕变。将高频、低创的重复性工作交给脚本,让运维人员将精力聚焦于架构优化与故障排查,才是破局之道。

本文将分享三个在日常运维工作中高频使用的实战脚本,涵盖日志清理、服务自愈与数据备份,均经过生产环境检验,希望能为大家的自动化工具箱添砖加瓦。


一、 Shell脚本:智能日志清理与轮转工具

痛点:业务服务运行久了,日志文件动辄几十GB,不仅消耗大量磁盘空间,还导致排查问题时grep极度缓慢。手动清理容易误删,且难以做到按时间精准保留。

解决方案:以下脚本实现了按目录遍历、按时间过滤、按大小兜底的安全清理机制。


#!/bin/bash
# 脚本名称: log_cleaner.sh
# 功能: 清理指定目录下超过指定天数的日志,并对超大文件进行截断

LOG_DIR="/data/app/logs"
DAYS_TO_KEEP=7
MAX_SIZE_MB=500 # 超过此大小的活跃日志将被截断而非删除

echo "===== 开始清理日志: $(date) ====="

# 1. 清理超过N天的旧日志或归档日志(.gz等)
find ${LOG_DIR} -type f \( -name "*.log.*" -o -name "*.gz" \) -mtime +${DAYS_TO_KEEP} -exec rm -f {} \;
echo "已清理 ${DAYS_TO_KEEP} 天前的归档日志"

# 2. 处理当前活跃的大日志文件(避免直接删除导致程序句柄未释放丢失输出)
for log_file in $(find ${LOG_DIR} -type f -name "*.log"); do
    file_size_mb=$(du -m "$log_file" | cut -f1)
    if [ "$file_size_mb" -gt "$MAX_SIZE_MB" ]; then
        echo "警告: ${log_file} 超过 ${MAX_SIZE_MB}MB,执行截断操作"
        # 保留最后1000行用于排查,清空原文件
        tail -n 1000 "$log_file" > "${log_file}.tmp"
        cat "${log_file}.tmp" > "$log_file"
        rm -f "${log_file}.tmp"
    fi
done

echo "===== 日志清理完毕: $(date) ====="

运维心法:对活跃日志直接rm是运维大忌,即使文件被删,只要进程句柄未释放,磁盘空间依旧不会释放。此脚本采用tail + 覆写的方式截断大文件,既释放了空间,又保留了最新的日志上下文,避免了进程重启。


二、 Python脚本:服务健康检查与自愈守护

痛点:某些边缘服务或老旧服务偶尔会因为网络抖动、内存泄漏等原因僵死。部署复杂的K8s或Supervisor成本过高,需要轻量级的守护方案。

解决方案:使用Python脚本定期探测服务端口与API,一旦发现异常,先尝试平滑重启,并接入企业微信/钉钉告警。


#!/usr/bin/env python3
# 脚本名称: service_watcher.py
# 功能: 监控服务健康度,异常时自愈并告警

import requests
import subprocess
import time
import smtplib
from datetime import datetime

# 配置项
SERVICE_NAME = "order-service"
CHECK_URL = "http://127.0.0.1:8080/actuator/health"
RESTART_CMD = "sudo systemctl restart order-service"
WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"

def send_alert(msg):
    """发送钉钉/企业微信告警"""
    payload = {"msgtype": "text", "text": {"content": f"【自愈告警】{msg}"}}
    try:
        requests.post(WEBHOOK_URL, json=payload, timeout=5)
    except Exception as e:
        print(f"告警发送失败: {e}")

def check_and_heal():
    try:
        # 设定超时为3秒,期望HTTP 200
        resp = requests.get(CHECK_URL, timeout=3)
        if resp.status_code == 200 and resp.json().get('status') == 'UP':
            print(f"{datetime.now()} - 服务正常")
            return
    except Exception as e:
        print(f"{datetime.now()} - 探测失败: {e}")

    # 探测失败,触发自愈
    print(f"{datetime.now()} - 服务异常,尝试重启...")
    send_alert(f"{SERVICE_NAME} 健康检查失败,正在尝试自愈重启!")
    
    try:
        # 执行重启命令
        subprocess.run(RESTART_CMD, shell=True, check=True, timeout=30)
        time.sleep(5) # 等待5秒让服务启动
        
        # 二次探测
        resp = requests.get(CHECK_URL, timeout=3)
        if resp.status_code == 200:
            send_alert(f"{SERVICE_NAME} 自愈成功!")
        else:
            send_alert(f"{SERVICE_NAME} 自愈失败,请人工介入!")
    except Exception as e:
        send_alert(f"{SERVICE_NAME} 重启过程出错: {e},请人工介入!")

if __name__ == "__main__":
    check_and_heal()

运维心法:自愈脚本的核心在于幂等性兜底机制。脚本必须保证在服务已经挂掉的情况下,重启操作不会引发次生灾害(如端口冲突起不来)。同时,自愈动作必须伴随告警,"静默自愈"是排查问题的黑洞,必须让运维人员知晓自愈事件的发生。


三、 Shell脚本:MySQL安全备份与异地推送

痛点:数据是公司的生命线,但数据库备份常面临三大坑:1. 密码明文写在脚本里不安全;2. 大库直接dump导致磁盘打满或IO飙高;3. 备份文件堆积在本地,一旦宿主机宕机,备份也随之丢失。

解决方案:结合my.cnf免密登录、管道压缩与rclone云存储同步,实现安全、轻量、异地的备份闭环。


#!/bin/bash
# 脚本名称: mysql_backup.sh
# 功能: 安全备份数据库并推送到云存储

DB_NAME="production_db"
BACKUP_DIR="/data/backups/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"
CLOUD_REMOTE="oss-backup:mysql-daily/"

# 1. 环境准备
mkdir -p ${BACKUP_DIR}

# 2. 执行备份 (注意:不使用 -p 参数,密码配置在 ~/.my.cnf 中)
# 使用管道直接压缩输出,大幅减少磁盘暂存空间占用
echo "开始备份数据库: ${DB_NAME}..."
mysqldump --defaults-extra-file=~/.my.cnf --single-transaction --routines --triggers ${DB_NAME} | gzip > ${BACKUP_FILE}

if [ $? -ne 0 ]; then
    echo "备份失败!"
    exit 1
fi

echo "备份成功,文件大小: $(du -h ${BACKUP_FILE} | cut -f1)"

# 3. 推送至云存储 (如阿里云OSS/AWS S3,需提前配置rclone)
echo "推送至云存储..."
rclone copy ${BACKUP_FILE} ${CLOUD_REMOTE} --progress

# 4. 清理本地超过7天的备份
find ${BACKUP_DIR} -