第三章 脚本之力:Shell与Python双剑合璧

3.1 为什么是双剑合璧?

说实话,我见过不少运维同行,要么只认Shell,要么只认Python。其实没必要这么极端。Shell和Python,就像螺丝刀和电钻——各有各的用武之地。

我个人习惯是:短平快的系统操作交给Shell,复杂逻辑和数据处理交给Python。你想想看,写个日志轮转,用Shell三五行就搞定;但要解析JSON格式的监控数据,Python的字典操作明显更顺手。

我在项目中遇到过一位同事,非要用Python写个简单的文件移动脚本,结果光处理路径转义就折腾了半天。嗯,这就是典型的「杀鸡用牛刀」。

3.2 第一个自动化脚本:日志轮转

日志轮转,说白了就是防止日志文件把磁盘撑爆。我刚开始做运维时,有台服务器因为没配轮转,/var/log 目录直接飙到 50GB,系统直接卡死。从那以后,轮转脚本就成了我的标配。

下面这个脚本,我用了好几年,稳定得很:

#!/bin/bash
# 日志轮转脚本 - log_rotate.sh
LOG_DIR="/var/log/myapp"
RETENTION_DAYS=7
ARCHIVE_DIR="/backup/logs/$(date +%Y%m)"

# 创建归档目录
mkdir -p $ARCHIVE_DIR

# 轮转逻辑:压缩并移动
for logfile in $(find $LOG_DIR -name "*.log" -mtime +1); do
    gzip $logfile
    mv $logfile.gz $ARCHIVE_DIR/
    echo "[$(date)] 已轮转: $logfile" >> /var/log/rotate.log
done

# 清理过期归档
find $ARCHIVE_DIR -name "*.gz" -mtime +$RETENTION_DAYS -delete
我的小技巧: 轮转时间建议选在凌晨3点,这时候业务流量最低。用crontab配置:0 3 * * * /usr/local/bin/log_rotate.sh

3.3 批量部署脚本

批量部署,是运维的日常操作。我曾经手动给100台服务器装过Agent,那叫一个酸爽。后来我写了这个脚本,把重复劳动变成了自动化流水线。

这里我用Python写,因为需要处理服务器列表、错误重试、结果汇总:

#!/usr/bin/env python3
# 批量部署脚本 - batch_deploy.py
import paramiko
import json
import sys
from concurrent.futures import ThreadPoolExecutor

def deploy_to_host(host, user, pkey_path, package_path):
    """单机部署函数"""
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host, username=user, key_filename=pkey_path)
        
        # 上传安装包
        sftp = ssh.open_sftp()
        sftp.put(package_path, "/tmp/deploy_pkg.tar.gz")
        sftp.close()
        
        # 执行安装
        stdin, stdout, stderr = ssh.exec_command(
            "cd /tmp && tar -xzf deploy_pkg.tar.gz && ./install.sh"
        )
        exit_code = stdout.channel.recv_exit_status()
        
        ssh.close()
        return {"host": host, "status": "success" if exit_code == 0 else "failed"}
    except Exception as e:
        return {"host": host, "status": "error", "msg": str(e)}

# 主逻辑
if __name__ == "__main__":
    with open("hosts.json") as f:
        hosts = json.load(f)
    
    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(
            lambda h: deploy_to_host(
                h["ip"], h["user"], h["key_path"], sys.argv[1]
            ), hosts
        ))
    
    # 输出结果
    success = [r for r in results if r["status"] == "success"]
    failed = [r for r in results if r["status"] != "success"]
    print(f"成功: {len(success)}, 失败: {len(failed)}")
    for f in failed:
        print(f"  {f['host']}: {f.get('msg', '部署失败')}")
避坑指南: 我曾经因为没加超时控制,导致脚本卡在一台宕机的服务器上,整个部署流程停了20分钟。建议给SSH连接加上timeout参数:ssh.connect(host, timeout=30)

3.4 健康检查脚本

健康检查,是运维的「听诊器」。我习惯用Shell写快速检查,用Python写详细报告。下面这个脚本,是我每天巡检的标配:

#!/bin/bash
# 健康检查脚本 - health_check.sh

echo "=== 系统健康检查报告 ==="
echo "时间: $(date)"
echo ""

# CPU检查
CPU_LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1)
echo "CPU负载: $CPU_LOAD"
if (( $(echo "$CPU_LOAD > 5.0" | bc -l) )); then
    echo "  ⚠️ CPU负载过高"
fi

# 内存检查
MEM_TOTAL=$(free -m | awk '/Mem:/ {print $2}')
MEM_USED=$(free -m | awk '/Mem:/ {print $3}')
MEM_PERCENT=$(( MEM_USED * 100 / MEM_TOTAL ))
echo "内存使用: ${MEM_USED}MB / ${MEM_TOTAL}MB (${MEM_PERCENT}%)"
if [ $MEM_PERCENT -gt 90 ]; then
    echo "  ⚠️ 内存使用超过90%"
fi

# 磁盘检查
echo "磁盘使用:"
df -h | grep -E '^/dev/' | awk '{print $5, $6}'

Python版本更擅长做数据汇总和告警:

#!/usr/bin/env python3
# 健康检查报告 - health_report.py
import psutil
import json
from datetime import datetime

def check_system():
    report = {
        "timestamp": datetime.now().isoformat(),
        "cpu": {
            "percent": psutil.cpu_percent(interval=1),
            "load_avg": psutil.getloadavg()
        },
        "memory": {
            "total": psutil.virtual_memory().total,
            "available": psutil.virtual_memory().available,
            "percent": psutil.virtual_memory().percent
        },
        "disk": []
    }
    
    for part in psutil.disk_partitions():
        if part.fstype:
            usage = psutil.disk_usage(part.mountpoint)
            report["disk"].append({
                "mount": part.mountpoint,
                "total": usage.total,
                "used": usage.used,
                "percent": usage.percent
            })
    
    return report

if __name__ == "__main__":
    result = check_system()
    print(json.dumps(result, indent=2))
    
    # 告警逻辑
    if result["cpu"]["percent"] > 90:
        print("⚠️ CPU使用率超过90%")
    if result["memory"]["percent"] > 90:
        print("⚠️ 内存使用率超过90%")

3.5 核心逻辑流程图

下面这张图,是我梳理的自动化脚本核心逻辑。说白了,就是三个步骤:检查→执行→报告

自动化脚本核心逻辑 开始执行 检查阶段 CPU/内存/磁盘/日志大小 是否触发阈值? 执行阶段 轮转/部署/告警 报告阶段 输出日志/发送通知

3.6 脚本整合与最佳实践

这三个脚本,我建议你放在 /usr/local/bin/ 目录下,加上执行权限。然后通过一个主调度脚本来统一管理:

#!/bin/bash
# 主调度脚本 - auto_ops.sh
# 用法: ./auto_ops.sh [rotate|deploy|check]

case "$1" in
    rotate)
        /usr/local/bin/log_rotate.sh
        ;;
    deploy)
        /usr/local/bin/batch_deploy.py /path/to/package.tar.gz
        ;;
    check)
        /usr/local/bin/health_check.sh
        /usr/local/bin/health_report.py
        ;;
    *)
        echo "用法: $0 {rotate|deploy|check}"
        exit 1
        ;;
esac
核心要点:
  • Shell适合系统级操作,Python适合复杂逻辑
  • 所有脚本必须加错误处理,别裸奔
  • 日志输出要规范,方便事后排查
  • 用crontab做定时调度,别手动跑

嗯,这三个脚本,基本覆盖了日常运维的80%场景。你拿去改改,就能直接用在生产环境。记住一点:脚本写出来只是开始,持续优化才是关键

专注资料整理