运维人如何用 Python 自动化提升 10 倍效率

一、引言

作为一名运维工程师,你是否也经常遇到这些场景:

  • 每天重复检查几十台服务器的状态
  • 手动分析几百 MB 的日志文件
  • 半夜被告警电话叫醒,手动处理故障
  • 花几个小时部署新版本

我曾经也是这样,直到我开始用 Python 写自动化脚本。今天分享 5 个我工作中最常用的自动化脚本,帮你从重复劳动中解放出来。


二、5 个实用自动化脚本

1. 日志自动分析脚本

场景: 每天需要分析 Nginx 日志,找出访问异常的 IP 和 URL

传统做法:grepawk 手动分析,花 30 分钟

自动化方案:

python 复制代码
#!/usr/bin/env python3
"""
Nginx 日志分析脚本
功能:提取访问 TOP10 的 IP、URL,识别异常请求
"""
import re
from collections import Counter
from datetime import datetime

def analyze_nginx_log(log_file, top_n=10):
    """分析 Nginx 日志"""
    
    # 正则表达式匹配日志行
    log_pattern = r'(\d+\.\d+\.\d+\.\d+).*?"(GET|POST|PUT|DELETE)\s+([^\s]+).*?"\s+(\d{3})'
    
    ip_counter = Counter()
    url_counter = Counter()
    error_requests = []
    
    with open(log_file, 'r', encoding='utf-8') as f:
        for line in f:
            match = re.search(log_pattern, line)
            if match:
                ip, method, url, status = match.groups()
                ip_counter[ip] += 1
                url_counter[url] += 1
                
                # 记录错误请求(4xx 和 5xx)
                if status.startswith(('4', '5')):
                    error_requests.append({
                        'ip': ip,
                        'method': method,
                        'url': url,
                        'status': status,
                        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    })
    
    # 输出结果
    print("=" * 60)
    print(f"📊 Nginx 日志分析报告")
    print("=" * 60)
    
    print(f"\n🔝 访问 TOP{top_n} IP:")
    for ip, count in ip_counter.most_common(top_n):
        print(f"  {ip}: {count} 次")
    
    print(f"\n🔝 访问 TOP{top_n} URL:")
    for url, count in url_counter.most_common(top_n):
        print(f"  {url}: {count} 次")
    
    print(f"\n⚠️  错误请求数:{len(error_requests)}")
    if error_requests:
        print("\n最近 5 条错误请求:")
        for req in error_requests[:5]:
            print(f"  [{req['status']}] {req['method']} {req['url']} (IP: {req['ip']})")
    
    return {
        'top_ips': ip_counter.most_common(top_n),
        'top_urls': url_counter.most_common(top_n),
        'error_count': len(error_requests),
        'errors': error_requests
    }

if __name__ == '__main__':
    analyze_nginx_log('/var/log/nginx/access.log')

效果: 30 秒出报告,效率提升 60 倍

进阶用法:

  • 定时执行(cron 每天凌晨 2 点)
  • 邮件发送报告
  • 异常 IP 自动封禁

2. 服务器健康检查脚本

场景: 管理 50+ 台服务器,每天需要检查 CPU、内存、磁盘

传统做法: 登录每台服务器执行 topdf 命令

自动化方案:

python 复制代码
#!/usr/bin/env python3
"""
服务器健康检查脚本
功能:批量检查服务器资源使用情况,自动告警
"""
import paramiko
import json
from datetime import datetime

# 服务器列表
SERVERS = [
    {'host': '192.168.1.10', 'username': 'root', 'password': 'xxx'},
    {'host': '192.168.1.11', 'username': 'root', 'password': 'xxx'},
    # ... 更多服务器
]

# 告警阈值
THRESHOLDS = {
    'cpu': 80,      # CPU 使用率 > 80% 告警
    'memory': 85,   # 内存使用率 > 85% 告警
    'disk': 90      # 磁盘使用率 > 90% 告警
}

def check_server(server):
    """检查单台服务器"""
    try:
        # SSH 连接
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(
            hostname=server['host'],
            username=server['username'],
            password=server['password'],
            timeout=5
        )
        
        # 执行检查命令
        commands = {
            'cpu': "top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}'",
            'memory': "free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100}'",
            'disk': "df -h / | tail -1 | awk '{print $5}' | tr -d '%'"
        }
        
        result = {'host': server['host'], 'status': 'OK', 'alerts': []}
        
        for metric, cmd in commands.items():
            stdin, stdout, stderr = client.exec_command(cmd)
            value = float(stdout.read().decode().strip())
            result[metric] = value
            
            # 检查是否超过阈值
            if value > THRESHOLDS[metric]:
                result['alerts'].append(f"{metric.upper()} 使用率过高:{value}%")
                result['status'] = 'WARNING'
        
        client.close()
        return result
        
    except Exception as e:
        return {
            'host': server['host'],
            'status': 'ERROR',
            'error': str(e)
        }

def health_check_all():
    """检查所有服务器"""
    print("=" * 60)
    print(f"🏥 服务器健康检查报告 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    results = []
    for server in SERVERS:
        result = check_server(server)
        results.append(result)
        
        # 打印结果
        status_icon = {'OK': '✅', 'WARNING': '⚠️', 'ERROR': '❌'}
        print(f"\n{status_icon.get(result['status'], '❓')} {result['host']}")
        
        if result['status'] == 'OK':
            print(f"  CPU: {result.get('cpu', 'N/A')}% | 内存:{result.get('memory', 'N/A')}% | 磁盘:{result.get('disk', 'N/A')}%")
        elif result['status'] == 'WARNING':
            for alert in result['alerts']:
                print(f"  ⚠️  {alert}")
        else:
            print(f"  错误:{result.get('error', '未知错误')}")
    
    # 统计
    ok_count = sum(1 for r in results if r['status'] == 'OK')
    warning_count = sum(1 for r in results if r['status'] == 'WARNING')
    error_count = sum(1 for r in results if r['status'] == 'ERROR')
    
    print(f"\n📊 汇总:✅ {ok_count} 正常 | ⚠️  {warning_count} 告警 | ❌ {error_count} 错误")
    
    return results

if __name__ == '__main__':
    health_check_all()

效果: 5 分钟检查完 50 台服务器,自动生成报告

依赖安装:

bash 复制代码
pip install paramiko

3. 批量部署脚本

场景: 需要同时更新 20 台服务器上的应用

传统做法: 一台一台登录、拉代码、重启服务

自动化方案:

python 复制代码
#!/usr/bin/env python3
"""
批量部署脚本
功能:同时在多台服务器上部署应用,支持回滚
"""
import paramiko
import time
from datetime import datetime

SERVERS = [
    {'host': '192.168.1.10', 'username': 'root', 'password': 'xxx'},
    {'host': '192.168.1.11', 'username': 'root', 'password': 'xxx'},
]

DEPLOY_CONFIG = {
    'app_dir': '/opt/myapp',
    'git_repo': 'git@github.com:myorg/myapp.git',
    'branch': 'main',
    'service_name': 'myapp'
}

def deploy_server(server, config):
    """在单台服务器上部署"""
    try:
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(**server, timeout=10)
        
        commands = [
            f"cd {config['app_dir']}",
            "git fetch",
            f"git checkout {config['branch']}",
            "git pull",
            "pip install -r requirements.txt",
            f"systemctl restart {config['service_name']}",
            f"systemctl status {config['service_name']} --no-pager"
        ]
        
        print(f"\n🚀 开始部署 {server['host']}...")
        
        for cmd in commands:
            stdin, stdout, stderr = client.exec_command(cmd)
            exit_status = stdout.channel.recv_exit_status()
            
            if exit_status != 0:
                error_msg = stderr.read().decode()
                print(f"  ❌ 命令失败:{cmd}")
                print(f"  错误:{error_msg}")
                client.close()
                return False
            
            time.sleep(1)  # 避免命令执行过快
        
        print(f"  ✅ {server['host']} 部署成功")
        client.close()
        return True
        
    except Exception as e:
        print(f"  ❌ {server['host']} 部署失败:{str(e)}")
        return False

def rolling_deploy():
    """滚动部署(一次一台,避免服务中断)"""
    print("=" * 60)
    print(f"🚀 滚动部署开始 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    success_count = 0
    for i, server in enumerate(SERVERS, 1):
        print(f"\n[{i}/{len(SERVERS)}] 部署第 {i} 台服务器")
        if deploy_server(server, DEPLOY_CONFIG):
            success_count += 1
            print(f"  ⏳ 等待 30 秒观察服务状态...")
            time.sleep(30)  # 观察服务是否正常
        else:
            print(f"  ⚠️  部署失败,暂停后续部署")
            break
    
    print(f"\n📊 部署完成:成功 {success_count}/{len(SERVERS)} 台")
    return success_count == len(SERVERS)

if __name__ == '__main__':
    success = rolling_deploy()
    exit(0 if success else 1)

效果: 部署时间从 2 小时缩短到 15 分钟


4. 数据库备份脚本

场景: 每天需要备份 MySQL 数据库,并上传到云存储

自动化方案:

python 复制代码
#!/usr/bin/env python3
"""
数据库自动备份脚本
功能:备份 MySQL 数据库,压缩并上传到 OSS/S3
"""
import subprocess
import os
from datetime import datetime
import boto3  # AWS S3

# 配置
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': 'your_password',
    'databases': ['db1', 'db2', 'db3']
}

BACKUP_DIR = '/backup/mysql'
S3_BUCKET = 'my-backup-bucket'
RETENTION_DAYS = 30  # 保留 30 天

def backup_database(db_name):
    """备份单个数据库"""
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    filename = f"{db_name}_{timestamp}.sql.gz"
    filepath = os.path.join(BACKUP_DIR, filename)
    
    # 确保备份目录存在
    os.makedirs(BACKUP_DIR, exist_ok=True)
    
    # 执行备份命令
    cmd = f"mysqldump -h{DB_CONFIG['host']} -u{DB_CONFIG['user']} -p{DB_CONFIG['password']} {db_name} | gzip > {filepath}"
    
    try:
        subprocess.run(cmd, shell=True, check=True)
        print(f" {db_name} 备份完成:{filename}")
        return filename
    except subprocess.CalledProcessError as e:
        print(f"db_name} 备份失败:{e}")
        return None

def upload_to_s3(filepath, bucket):
    """上传到 S3"""
    s3 = boto3.client('s3',
        aws_access_key_id='YOUR_KEY',
        aws_secret_access_key='YOUR_SECRET'
    )
    
    filename = os.path.basename(filepath)
    s3.upload_file(filepath, bucket, f"mysql/{filename}")
    print(f"☁️  已上传到 S3: {bucket}/mysql/{filename}")

def cleanup_old_backups():
    """清理过期备份"""
    cutoff_date = datetime.now().timestamp() - (RETENTION_DAYS * 86400)
    
    for filename in os.listdir(BACKUP_DIR):
        filepath = os.path.join(BACKUP_DIR, filename)
        if os.path.getmtime(filepath) < cutoff_date:
            os.remove(filepath)
            print(f"🗑️  已删除过期备份:{filename}")

def main():
    print("=" * 60)
    print(f"💾 数据库备份开始 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    for db_name in DB_CONFIG['databases']:
        filename = backup_database(db_name)
        if filename:
            filepath = os.path.join(BACKUP_DIR, filename)
            upload_to_s3(filepath, S3_BUCKET)
    
    cleanup_old_backups()
    
    print("\n 所有备份完成")

if __name__ == '__main__':
    main()

依赖安装:

bash 复制代码
pip install boto3

配置 cron 定时任务:

bash 复制代码
# 每天凌晨 2 点备份
0 2 * * * /usr/bin/python3 /opt/scripts/backup_mysql.py >> /var/log/backup.log 2>&1

5. SSL 证书到期提醒脚本

场景: 管理多个域名,需要监控 SSL 证书到期时间

自动化方案:

python 复制代码
#!/usr/bin/env python3
"""
SSL 证书监控脚本
功能:检查证书到期时间,提前 30 天邮件提醒
"""
import ssl
import socket
import smtplib
from datetime import datetime
from email.mime.text import MIMEText
from email.header import Header

# 域名列表
DOMAINS = [
    'example.com',
    'api.example.com',
    'www.example.com'
]

# 邮件配置
EMAIL_CONFIG = {
    'smtp_server': 'smtp.qq.com',
    'smtp_port': 465,
    'from_addr': 'alert@example.com',
    'password': 'your_password',
    'to_addrs': ['admin@example.com']
}

def check_ssl_cert(domain, port=443):
    """检查 SSL 证书"""
    context = ssl.create_default_context()
    
    with socket.create_connection((domain, port)) as sock:
        with context.wrap_socket(sock, server_hostname=domain) as ssock:
            cert = ssock.getpeercert()
            not_after = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y GMT')
            
            days_left = (not_after - datetime.utcnow()).days
            
            return {
                'domain': domain,
                'expire_date': not_after,
                'days_left': days_left,
                'status': 'OK' if days_left > 30 else 'WARNING'
            }

def send_alert_email(cert_info):
    """发送告警邮件"""
    subject = f"⚠️ SSL 证书即将到期 - {cert_info['domain']}"
    
    body = f"""
尊敬的运维团队:

域名 {cert_info['domain']} 的 SSL 证书即将到期!

📅 到期时间:{cert_info['expire_date'].strftime('%Y-%m-%d')}
⏰ 剩余天数:{cert_info['days_left']} 天

请尽快续期,避免服务中断!

---
自动化监控系统
{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
"""
    
    msg = MIMEText(body, 'plain', 'utf-8')
    msg['From'] = Header("SSL 监控", 'utf-8')
    msg['To'] = Header("运维团队", 'utf-8')
    msg['Subject'] = Header(subject, 'utf-8')
    
    with smtplib.SMTP_SSL(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
        server.login(EMAIL_CONFIG['from_addr'], EMAIL_CONFIG['password'])
        server.sendmail(
            EMAIL_CONFIG['from_addr'],
            EMAIL_CONFIG['to_addrs'],
            msg.as_string()
        )
    
    print(f"📧 已发送告警邮件到 {EMAIL_CONFIG['to_addrs']}")

def main():
    print("=" * 60)
    print(f"🔒 SSL 证书检查 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    for domain in DOMAINS:
        try:
            cert_info = check_ssl_cert(domain)
            
            status_icon = {'OK': '!', 'WARNING': '!!'}
            print(f"\n{status_icon.get(cert_info['status'], '❓')} {domain}")
            print(f"  到期时间:{cert_info['expire_date'].strftime('%Y-%m-%d')}")
            print(f"  剩余天数:{cert_info['days_left']} 天")
            
            if cert_info['status'] == 'WARNING':
                send_alert_email(cert_info)
                
        except Exception as e:
            print(f"\n X {domain} 检查失败:{e}")
    
    print("\n ! 检查完成")

if __name__ == '__main__':
    main()

效果: 避免证书过期导致的服务中断


三、进阶:定时任务管理

脚本写好了,如何定时执行?

方案 1:Cron(简单任务)

bash 复制代码
# 编辑 crontab
crontab -e

# 示例:每天早上 8 点检查服务器健康
0 8 * * * /usr/bin/python3 /opt/scripts/health_check.py >> /var/log/health.log 2>&1

# 每天凌晨 2 点备份数据库
0 2 * * * /usr/bin/python3 /opt/scripts/backup_mysql.py

方案 2:APScheduler(Python 内置)

python 复制代码
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime

from my_scripts import health_check, backup_database

scheduler = BlockingScheduler()

# 每天早上 8 点执行健康检查
scheduler.add_job(health_check, 'cron', hour=8, minute=0)

# 每天凌晨 2 点备份数据库
scheduler.add_job(backup_database, 'cron', hour=2, minute=0)

# 每周一上午 9 点发送周报
scheduler.add_job(send_weekly_report, 'cron', day_of_week='mon', hour=9)

print("⏰ 调度器启动...")
scheduler.start()

安装:

bash 复制代码
pip install apscheduler

四、最佳实践建议

1. 脚本管理

  • 统一存放在 /opt/scripts/ 目录
  • 使用 Git 版本控制
  • 添加详细的注释和文档

2. 日志记录

python 复制代码
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='/var/log/my_script.log'
)

logging.info("脚本执行成功")
logging.error("发生错误")

3. 错误处理

python 复制代码
try:
    # 执行操作
    pass
except Exception as e:
    logging.error(f"操作失败:{e}")
    # 发送告警
    send_alert(f"脚本执行失败:{e}")
    exit(1)

4. 安全性

  • 敏感信息使用环境变量
  • 脚本权限设置为 700
  • 定期更新依赖包
python 复制代码
import os

# 从环境变量读取密码
db_password = os.getenv('DB_PASSWORD')

五、总结

自动化是运维的核心竞争力之一。这 5 个脚本是我工作中最常用的,希望能帮你:

  1. 节省时间 - 从重复劳动中解放
  2. 减少错误 - 避免人为失误
  3. 提升价值 - 把时间花在更有意义的事情上

最后送大家一句话:

好的运维不是救火英雄,而是让火灾永远不会发生的人。

自动化,就是预防火灾的最好方式。


相关资源:

欢迎关注我,获取更多运维自动化实战技巧!


本文首发于掘金,转载请联系作者

相关推荐
AI-小柒3 小时前
OpenClaw技术深度解析:从智能助手到自动化引擎的范式革命(附DataEyes实战)
大数据·运维·开发语言·人工智能·python·http·自动化
所谓伊人,在水一方3333 小时前
【Python数据可视化精通】第1讲 | 数据可视化的本质与认知心理学基础
开发语言·python·信息可视化·matplotlib
ding_zhikai3 小时前
【Web应用开发笔记】Django笔记9:Django部署注意事项补充
笔记·后端·python·django
所谓伊人,在水一方3333 小时前
【Python数据科学实战之路】第18章 | 大模型与数据科学:LLM赋能数据分析新时代
开发语言·python·深度学习·神经网络·数据分析·tensorflow
吃吃喝喝小朋友3 小时前
Django Admin后台系统
后端·python·django
赵谨言3 小时前
摘要本研究旨在构建一套基于OpenCV与CNN融合技术的银行卡号自动识别系统,重点解决不同银行卡号字体格式差异、倾斜污损等复杂场景下的识别难题
大数据·开发语言·经验分享·python
怪侠_岭南一只猿3 小时前
爬虫阶段一实战练习题:爬取豆瓣电影 Top250 复盘
css·经验分享·爬虫·python·学习·正则表达式
郭龙_Jack3 小时前
TensorFlow GPU 优化配置手册
人工智能·python·tensorflow