运维利器:实战自动化脚本分享,告别“人肉运维”

在IT运维的日常工作中,面对成百上千台服务器和繁杂重复的任务,纯靠“人肉运维”不仅效率低下,且极易因人为疏忽导致线上事故。自动化运维不仅是提升效率的利器,更是保障系统稳定性的关键。

本文将结合实际工作场景,分享几款经过实战检验的Shell与Python自动化脚本,涵盖日志清理、服务自愈、资产巡检与数据备份,帮助大家从繁琐的机械操作中解放出来。


一、 Shell脚本:按天轮转与清理历史日志

磁盘空间告警是运维常遇的痛点,尤其是应用服务产生的日志文件,若不加以清理极易撑爆磁盘。手动清理费时费力,下面这个Shell脚本通过find命令结合时间戳,实现日志的自动压缩与清理。


#!/bin/bash
# 描述:自动压缩指定天数前的日志,并删除指定天数前的压缩包
# 作者:运维自动化系列

LOG_DIR="/data/app/logs"
# 7天前的日志进行压缩
COMPRESS_DAYS=7
# 30天前的压缩包进行删除
DELETE_DAYS=30

echo "===== 开始执行日志清理任务: $(date '+%Y-%m-%d %H:%M:%S') ====="

# 1. 压缩7天前的.log文件
find ${LOG_DIR} -name "*.log" -type f -mtime +${COMPRESS_DAYS} -exec gzip {} \;
echo "已压缩超过 ${COMPRESS_DAYS} 天的日志文件。"

# 2. 删除30天前的.gz压缩包
find ${LOG_DIR} -name "*.gz" -type f -mtime +${DELETE_DAYS} -exec rm -f {} \;
echo "已删除超过 ${DELETE_DAYS} 天的压缩日志。"

echo "===== 日志清理任务执行完毕 ====="

实战解析:

此脚本巧妙运用了find命令的-mtime参数。+7表示查找修改时间在7天之前的文件。先压缩再删除的策略,既释放了近期磁盘空间,又保留了相对久远的日志以备查,在空间与安全之间取得了平衡。建议配合Crontab每日凌晨执行。


二、 Shell脚本:核心服务健康检查与自愈

服务假死或异常宕机是另一大运维噩梦。对于未部署专业监控自愈系统(如K8s)的传统服务,可以通过定时脚本探测端口存活状态,一旦发现异常立即重启并告警。


#!/bin/bash
# 描述:监控服务端口,异常时自动重启并触发告警

SERVICE_NAME="my-core-service"
PORT=8080
WEBHOOK_URL="https://hooks.example.com/alert"

# 检测端口是否存活
check_port() {
    /usr/sbin/ss -tlnp | grep -q ":${PORT} "
    return $?
}

# 发送告警
send_alert() {
    curl -s -X POST "${WEBHOOK_URL}" \
         -H 'Content-Type: application/json' \
         -d "{\"content\": \"【严重告警】${SERVICE_NAME} 端口 ${PORT} 异常,已尝试自动重启!\"}" > /dev/null
}

# 主逻辑
if ! check_port; then
    echo "$(date): ${SERVICE_NAME} 端口 ${PORT} 不通,尝试重启..." >> /var/log/service_monitor.log
    systemctl restart ${SERVICE_NAME}
    sleep 5  # 等待5秒让服务启动
    
    if ! check_port; then
        echo "$(date): ${SERVICE_NAME} 重启失败,需人工介入!" >> /var/log/service_monitor.log
        send_alert
    else
        echo "$(date): ${SERVICE_NAME} 重启成功,端口恢复。" >> /var/log/service_monitor.log
    fi
fi

实战解析:

脚本使用ss命令检测端口,比netstat更高效。发现异常后先执行systemctl restart,休眠5秒后再次检测,若依然失败则通过Webhook(如钉钉/企微机器人)发送告警。这种“先自愈,后告警”的思路,能在大半夜帮你挡掉80%的非业务逻辑级故障。


三、 Python脚本:基于psutil的系统资产巡检

当服务器数量增多,手动登录每台机器执行topdf查看资源变得不现实。Python的psutil库是跨平台的系统监控利器,能轻松采集CPU、内存、磁盘等核心指标。


#!/usr/bin/env python3
# 描述:采集系统核心资源指标并输出JSON格式,便于对接CMDB或监控系统

import psutil
import json
from datetime import datetime

def get_system_info():
    info = {
        "timestamp": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        "cpu": {
            "logical_count": psutil.cpu_count(logical=True),
            "usage_percent": psutil.cpu_percent(interval=1)
        },
        "memory": {
            "total_gb": round(psutil.virtual_memory().total / (1024**3), 2),
            "used_gb": round(psutil.virtual_memory().used / (1024**3), 2),
            "usage_percent": psutil.virtual_memory().percent
        },
        "disk": []
    }

    # 采集磁盘使用率(仅采集挂载点)
    for part in psutil.disk_partitions():
        if 'cdrom' in part.opts or part.fstype == '':
            continue
        usage = psutil.disk_usage(part.mountpoint)
        info["disk"].append({
            "mountpoint": part.mountpoint,
            "total_gb": round(usage.total / (1024**3), 2),
            "used_percent": usage.percent
        })
    
    return info

if __name__ == "__main__":
    system_info = get_system_info()
    # 以JSON格式输出,方便后续程序解析
    print(json.dumps(system_info, indent=4, ensure_ascii=False))

实战解析:

相比于Shell的awk/grep拼凑,Python代码具备极强的可读性和扩展性。输出标准化JSON格式,使得该脚本不仅能单机运行,还能作为Agent被Ansible或SSH批量调用,将结果汇总至中央数据库,构建轻量级CMDB巡检系统。


四、 Python脚本:MySQL定时逻辑备份与空间轮转

数据库是公司的生命线,备份重于泰山。虽然物理备份(XtraBackup)更受欢迎,但对于中小型库,逻辑备份依然简单有效。以下脚本实现数据库Dump、压缩及旧备份清理。


#!/usr/bin/env python3
# 描述:MySQL逻辑备份,压缩存储并清理过期备份

import os
import subprocess
import datetime
import glob

# 配置项
DB_HOST = "127.0.0.1"
DB_USER = "backup_user"
DB_PASS = "YourStrongPassword"  # 建议从环境变量或Vault读取
BACKUP_DIR = "/data/backups/mysql"
KEEP_DAYS = 7

def perform_backup():
    # 确保备份目录存在
    os.makedirs(BACKUP_DIR, exist_ok=True)
    
    date_str = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    sql_file = os.path.join(BACKUP_DIR, f"all_dbs_{date_str}.sql")
    gz_file = f"{sql_file}.gz"

    # 执行mysqldump
    dump_cmd = f"mysqldump -h{DB_HOST} -u{DB_USER} -p{DB_PASS} --all-databases --single-transaction > {sql_file}"
    try:
        subprocess.run(dump_cmd, shell=True, check=True, stderr=subprocess.PIPE)
        
        # 压缩备份文件
        subprocess.run(f"gzip {sql_file}", shell=True, check=True)
        print(f"备份并压缩成功: {gz_file}")
        
        # 清理KEEP_DAYS前的备份
        cutoff_time = datetime.datetime.now() - datetime.timedelta(days=KEEP_DAYS)