首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >有故障一定是运维的责任么?附文档撰写标准(下)

有故障一定是运维的责任么?附文档撰写标准(下)

作者头像
IT运维技术圈
发布2025-10-09 12:19:19
发布2025-10-09 12:19:19
1070
举报
文章被收录于专栏:IT运维技术圈IT运维技术圈

0. 写在前面:为什么你需要“神器”而非“常用命令

大家好,欢迎来到干货、技术、专业全方位遥遥领先的老杨的博客.

帮老杨点赞、转发、在看以及打开小星标哦

攒今世之功德,修来世之福报


背锅这个词咋来的?

老杨今天给各位补习一下这个看似没用,实则一点都用不着的知识点。

传说古代军中如果有人犯错,就会被降级去炊事班并且负责背着大锅行军。军队做大锅饭那个铸铁锅可不是一般的沉。而且这个锅到底有多重要,当年项羽要拼命了才下令破釜沉舟,也就是把锅砸了。

你背这玩意,而且要像初恋一样的保护它!

慢慢的这个岗位就被引申到了职场中。

蝙蝠侠、蜘蛛侠、闪电侠、背锅侠,这四个都是拯救苍生的英雄人物。唯一的区别大概只有背锅侠不戴面具了。

看老杨的文章涨知识吧!

进入今天的主题.

见过太多同行因为一些看似无关紧要的操作,最后成了大铁锅。

不对!是背锅侠。

有的是技术问题,有的是流程问题,但更多的是意识问题。

比如公司数据库崩了,老板直接问运维搞咋回事。结果查来查去,发现是开发改了个配置没通知,但最后还是运维背锅——"你们怎么不知道?监控呢?"

反正运维就别想跑,出了问题第一个被怀疑,背锅是常态。但有些锅其实可以避免。

系列文章:

有故障一定是运维的责任么?(上)

禁忌六:变更不通知,出问题才说"我改了配置"

运维做了变更不通知相关人员,出问题的时候才说:"哦,我刚改了个配置。" 这种情况下,即使不是你的问题,也会被认为是你引起的。

比如某网站访问慢,开发排查了半天找不到原因。最后发现是运维调整了Nginx的worker_connections参数,但没通知任何人。虽然这个调整本身是对的,但因为没有沟通,浪费了大家半天时间。

正确的变更通知流程:

代码语言:javascript
复制
#!/bin/bash
# 变更通知脚本

CHANGE_DESC="调整Nginx worker_connections从1024到4096"
AFFECTED_SERVICES="前端网站,API接口"
CHANGE_TIME=$(date'+%Y-%m-%d %H:%M:%S')
OPERATOR="老杨"

# 1. 记录变更信息到系统日志
cat >> /var/log/system_changes.log << EOF
=====================================
变更时间: $CHANGE_TIME  
操作人员: $OPERATOR
变更描述: $CHANGE_DESC
影响服务: $AFFECTED_SERVICES
变更前配置: worker_connections 1024;
变更后配置: worker_connections 4096;
=====================================
EOF

# 2. 发送企业微信通知
send_wework_message() {
    local message="📋 系统变更通知

🕒 变更时间: $CHANGE_TIME
👤 操作人员: $OPERATOR  
📝 变更内容: $CHANGE_DESC
🎯 影响服务: $AFFECTED_SERVICES

如有异常请及时联系运维团队"

    curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key" \
         -H "Content-Type: application/json" \
         -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
}

# 3. 发送邮件通知
send_email_notification() {
    echo"$message" | mail -s "【系统变更通知】$CHANGE_DESC" \
        dev-team@company.com,qa-team@company.com
}

echo"执行变更: $CHANGE_DESC"

# 4. 执行实际的配置变更
sed -i 's/worker_connections 1024;/worker_connections 4096;/g' /etc/nginx/nginx.conf

# 5. 验证配置
nginx -t
if [ $? -eq 0 ]; then
    nginx -s reload
    echo"配置变更成功"
    
    # 6. 发送通知
    send_wework_message
    send_email_notification
    
else
    echo"配置验证失败,回滚变更"
    sed -i 's/worker_connections 4096;/worker_connections 1024;/g' /etc/nginx/nginx.conf
    exit 1
fi

禁忌七:日志不收集,出问题两眼一抹黑

很多运维不重视日志收集,出问题的时候无法快速定位原因。老板问什么时候开始出问题的,影响了多少用户,你说不知道,这就是失职。

而且日志分散在各个服务器上,排查问题的时候要SSH到每台机器查看,效率低得要命。

正确的日志收集方案:

代码语言:javascript
复制
# docker-compose.yml - ELK日志收集
version:'3.8'
services:
elasticsearch:
    image:docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    environment:
      -discovery.type=single-node
      -"ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ports:
      -"9200:9200"
    volumes:
      -es_data:/usr/share/elasticsearch/data

kibana:
    image:docker.elastic.co/kibana/kibana:7.17.0
    ports:
      -"5601:5601"
    environment:
      -ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      -elasticsearch

logstash:
    image:docker.elastic.co/logstash/logstash:7.17.0
    ports:
      -"5044:5044"
    volumes:
      -./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    depends_on:
      -elasticsearch

volumes:
  es_data:
代码语言:javascript
复制
# logstash.conf
input {
  beats {
    port => 5044
  }
}

filter {
if [fields][log_type] == "nginx" {
    grok {
      match => { 
        "message" => '%{IPORHOST:remote_ip} - %{DATA:user_name} \[%{HTTPDATE:access_time}\] "%{WORD:http_method} %{DATA:url} HTTP/%{NUMBER:http_version}" %{NUMBER:response_code} %{NUMBER:body_sent_bytes} "%{DATA:http_referer}" "%{DATA:http_user_agent}"'
      }
    }
    
    date {
      match => [ "access_time", "dd/MMM/yyyy:HH:mm:ss Z" ]
    }
    
    mutate {
      convert => { "response_code" => "integer" }
      convert => { "body_sent_bytes" => "integer" }
    }
  }

if [fields][log_type] == "application" {
    if [message] =~ /ERROR/ {
      mutate {
        add_tag => [ "error" ]
      }
    }
    
    if [message] =~ /FATAL/ {
      mutate {
        add_tag => [ "fatal" ]
      }
    }
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "logs-%{+YYYY.MM.dd}"
  }
}
代码语言:javascript
复制
# filebeat.yml - 在每台服务器部署
filebeat.inputs:
-type:log
enabled:true
paths:
    -/var/log/nginx/*.log
fields:
    log_type:nginx
    server:web-01
fields_under_root:true

-type:log
enabled:true
paths:
    -/var/log/app/*.log
fields:
    log_type:application
    server:web-01
fields_under_root:true
multiline.pattern:'^\d{4}-\d{2}-\d{2}'
multiline.negate:true
multiline.match:after

output.logstash:
hosts: ["logstash.internal.com:5044"]

processors:
-add_host_metadata:
    when.not.contains.tags: forwarded

这样设置后,所有日志都集中到Elasticsearch,可以在Kibana界面快速检索:

代码语言:javascript
复制
# 查询最近1小时的错误日志
GET logs-*/_search
{
"query": {
    "bool": {
      "must": [
        {
          "range": {
            "@timestamp": {
              "gte": "now-1h"
            }
          }
        },
        {
          "terms": {
            "tags": ["error", "fatal"]
          }
        }
      ]
    }
  },
"sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ]
}

禁忌八:容量规划不做,系统扛不住了才加机器

很多运维都是被动响应,系统慢了才想到扩容,用户投诉了才想到优化。这种情况下出问题,领导会质疑你的专业能力。

我见过一个电商网站,双11前没有做任何容量评估,结果活动开始后系统直接崩了。运维临时加机器,但配置和部署都需要时间,白白损失了几个小时的黄金销售时间。

正确的容量规划方法:

代码语言:javascript
复制
# 容量规划脚本 capacity_planning.py
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import psutil
import mysql.connector

classCapacityPlanner:
    def__init__(self):
        self.metrics = []
        
    defcollect_metrics(self):
        """收集系统指标"""
        # CPU使用率
        cpu_percent = psutil.cpu_percent(interval=1)
        
        # 内存使用率  
        memory = psutil.virtual_memory()
        memory_percent = memory.percent
        
        # 磁盘使用率
        disk = psutil.disk_usage('/')
        disk_percent = (disk.used / disk.total) * 100
        
        # 网络流量
        net_io = psutil.net_io_counters()
        
        # 数据库连接数
        db_connections = self.get_db_connections()
        
        metrics = {
            'timestamp': datetime.now(),
            'cpu_percent': cpu_percent,
            'memory_percent': memory_percent, 
            'disk_percent': disk_percent,
            'network_bytes_sent': net_io.bytes_sent,
            'network_bytes_recv': net_io.bytes_recv,
            'db_connections': db_connections
        }
        
        self.metrics.append(metrics)
        return metrics
        
    defget_db_connections(self):
        """获取数据库连接数"""
        try:
            conn = mysql.connector.connect(
                host='localhost',
                user='monitor',
                password='password'
            )
            cursor = conn.cursor()
            cursor.execute("SHOW STATUS LIKE 'Threads_connected'")
            result = cursor.fetchone()
            returnint(result[1]) if result else0
        except:
            return0
        finally:
            if'conn'inlocals():
                conn.close()
                
    defpredict_capacity(self, days_ahead=30):
        """预测未来容量需求"""
        iflen(self.metrics) < 24:  # 至少需要24小时数据
            print("数据不足,无法进行预测")
            return
            
        df = pd.DataFrame(self.metrics)
        
        # 计算增长趋势
        cpu_trend = np.polyfit(range(len(df)), df['cpu_percent'], 1)[0]
        memory_trend = np.polyfit(range(len(df)), df['memory_percent'], 1)[0]
        db_trend = np.polyfit(range(len(df)), df['db_connections'], 1)[0]
        
        # 预测未来值
        future_cpu = df['cpu_percent'].iloc[-1] + cpu_trend * days_ahead * 24
        future_memory = df['memory_percent'].iloc[-1] + memory_trend * days_ahead * 24
        future_db = df['db_connections'].iloc[-1] + db_trend * days_ahead * 24
        
        print(f"=== {days_ahead}天后容量预测 ===")
        print(f"CPU使用率: {future_cpu:.1f}% (当前: {df['cpu_percent'].iloc[-1]:.1f}%)")
        print(f"内存使用率: {future_memory:.1f}% (当前: {df['memory_percent'].iloc[-1]:.1f}%)")
        print(f"数据库连接数: {int(future_db)} (当前: {df['db_connections'].iloc[-1]})")
        
        # 容量建议
        if future_cpu > 80:
            print("⚠️  预警:CPU使用率将超过80%,建议增加计算资源")
        if future_memory > 80:
            print("⚠️  预警:内存使用率将超过80%,建议增加内存")
        if future_db > 100:
            print("⚠️  预警:数据库连接数过高,建议优化连接池或增加数据库节点")
            
        return {
            'cpu_prediction': future_cpu,
            'memory_prediction': future_memory,
            'db_prediction': future_db
        }
        
    defgenerate_report(self):
        """生成容量报告"""
        ifnotself.metrics:
            print("没有收集到监控数据")
            return
            
        df = pd.DataFrame(self.metrics)
        
        # 生成趋势图
        fig, axes = plt.subplots(2, 2, figsize=(12, 8))
        
        # CPU趋势
        axes[0,0].plot(df['timestamp'], df['cpu_percent'])
        axes[0,0].set_title('CPU使用率趋势')
        axes[0,0].set_ylabel('CPU %')
        
        # 内存趋势
        axes[0,1].plot(df['timestamp'], df['memory_percent'])
        axes[0,1].set_title('内存使用率趋势')
        axes[0,1].set_ylabel('Memory %')
        
        # 磁盘趋势
        axes[1,0].plot(df['timestamp'], df['disk_percent'])
        axes[1,0].set_title('磁盘使用率趋势')
        axes[1,0].set_ylabel('Disk %')
        
        # 数据库连接数趋势
        axes[1,1].plot(df['timestamp'], df['db_connections'])

```python
        # 数据库连接数趋势
        axes[1,1].plot(df['timestamp'], df['db_connections'])
        axes[1,1].set_title('数据库连接数趋势')
        axes[1,1].set_ylabel('Connections')
        
        plt.tight_layout()
        plt.savefig('/tmp/capacity_report.png', dpi=300, bbox_inches='tight')
        print("容量报告已生成: /tmp/capacity_report.png")

# 使用示例
if __name__ == "__main__":
    planner = CapacityPlanner()
    
    # 模拟收集24小时数据
    for i inrange(24):
        metrics = planner.collect_metrics()
        print(f"收集第{i+1}小时数据: CPU {metrics['cpu_percent']}%, 内存 {metrics['memory_percent']}%")
        time.sleep(3600)  # 实际使用中每小时收集一次
    
    # 生成预测报告
    planner.predict_capacity(30)
    planner.generate_report()

而且要建立容量告警机制:

代码语言:javascript
复制
#!/bin/bash
# 容量预警脚本 capacity_alert.sh

# 获取当前资源使用情况
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | awk -F% '{print $1}')
MEMORY_USAGE=$(free | grep Mem | awk '{printf("%.2f", $3/$2 * 100.0)}')
DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//')

# 数据库连接数
DB_CONNECTIONS=$(mysql -N -e "SHOW STATUS LIKE 'Threads_connected'" | awk '{print $2}')

echo"当前资源使用情况:"
echo"CPU: ${CPU_USAGE}%"
echo"内存: ${MEMORY_USAGE}%"
echo"磁盘: ${DISK_USAGE}%"
echo"数据库连接: ${DB_CONNECTIONS}"

# 容量预警阈值
CPU_WARN_THRESHOLD=70
CPU_CRIT_THRESHOLD=85
MEMORY_WARN_THRESHOLD=75
MEMORY_CRIT_THRESHOLD=90
DISK_WARN_THRESHOLD=80
DISK_CRIT_THRESHOLD=95

send_alert() {
    local level=$1
    local message=$2
    local emoji=""
    
    case$levelin
        "WARNING") emoji="⚠️" ;;
        "CRITICAL") emoji="🚨" ;;
    esac
    
    # 发送企业微信告警
    curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key" \
         -H "Content-Type: application/json" \
         -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$emoji 容量预警 $emoji\n\n$message\n\n时间: $(date)\n服务器: $(hostname)\"}}"
}

# 检查CPU
if (( $(echo "$CPU_USAGE > $CPU_CRIT_THRESHOLD" | bc -l) )); then
    send_alert "CRITICAL""CPU使用率达到${CPU_USAGE}%,超过临界阈值${CPU_CRIT_THRESHOLD}%,请立即处理!"
elif (( $(echo "$CPU_USAGE > $CPU_WARN_THRESHOLD" | bc -l) )); then
    send_alert "WARNING""CPU使用率达到${CPU_USAGE}%,超过预警阈值${CPU_WARN_THRESHOLD}%,请关注"
fi

# 检查内存
if (( $(echo "$MEMORY_USAGE > $MEMORY_CRIT_THRESHOLD" | bc -l) )); then
    send_alert "CRITICAL""内存使用率达到${MEMORY_USAGE}%,超过临界阈值${MEMORY_CRIT_THRESHOLD}%,请立即处理!"
elif (( $(echo "$MEMORY_USAGE > $MEMORY_WARN_THRESHOLD" | bc -l) )); then
    send_alert "WARNING""内存使用率达到${MEMORY_USAGE}%,超过预警阈值${MEMORY_WARN_THRESHOLD}%,请关注"
fi

# 检查磁盘
if [ "$DISK_USAGE" -gt "$DISK_CRIT_THRESHOLD" ]; then
    send_alert "CRITICAL""磁盘使用率达到${DISK_USAGE}%,超过临界阈值${DISK_CRIT_THRESHOLD}%,请立即清理!"
elif [ "$DISK_USAGE" -gt "$DISK_WARN_THRESHOLD" ]; then
    send_alert "WARNING""磁盘使用率达到${DISK_USAGE}%,超过预警阈值${DISK_WARN_THRESHOLD}%,请关注"
fi

禁忌九:安全漏洞不修补,被攻击了才知道系统有洞

很多运维觉得内网系统很安全,不重视安全补丁的更新。等系统被攻击了,发现用的还是几年前的老版本,到处都是已知漏洞。

前年我见过一个案例,某公司用的还是Apache Struts 2.3版本,早就有远程代码执行漏洞了。黑客直接通过这个漏洞拿到了服务器权限,删除了大量数据。事后调查发现,这个漏洞早在3年前就被公开了,官方也发布了补丁,但运维一直没有更新。

正确的安全管理流程:

代码语言:javascript
复制
#!/bin/bash
# 安全漏洞扫描脚本 security_scan.sh

echo"开始系统安全扫描..."
echo"扫描时间: $(date)"
echo"================================"

# 1. 检查系统版本和补丁状态
echo"1. 系统版本信息:"
cat /etc/os-release
echo""

echo"2. 检查可用更新:"
ifcommand -v yum >/dev/null 2>&1; then
    yum check-update | grep -E "(kernel|glibc|openssl|openssh)" || echo"核心组件暂无可用更新"
elifcommand -v apt >/dev/null 2>&1; then
    apt list --upgradable 2>/dev/null | grep -E "(kernel|libc|openssl|openssh)" || echo"核心组件暂无可用更新"
fi
echo""

# 2. 检查已安装软件版本
echo"3. 关键软件版本检查:"
check_version() {
    local software=$1
    local current_version=""
    
    case$softwarein
        "apache")
            ifcommand -v httpd >/dev/null 2>&1; then
                current_version=$(httpd -v | grep "Apache" | awk '{print $3}')
                echo"Apache版本: $current_version"
                # 检查是否存在已知漏洞
                if [[ "$current_version" < "Apache/2.4.41" ]]; then
                    echo"⚠️  警告: Apache版本过低,存在安全风险"
                fi
            fi
            ;;
        "nginx")
            ifcommand -v nginx >/dev/null 2>&1; then
                current_version=$(nginx -v 2>&1 | awk -F/ '{print $2}')
                echo"Nginx版本: $current_version"
                if [[ "$current_version" < "1.18.0" ]]; then
                    echo"⚠️  警告: Nginx版本过低,建议升级"
                fi
            fi
            ;;
        "mysql")
            ifcommand -v mysql >/dev/null 2>&1; then
                current_version=$(mysql --version | awk '{print $5}' | awk -F, '{print $1}')
                echo"MySQL版本: $current_version"
            fi
            ;;
        "php")
            ifcommand -v php >/dev/null 2>&1; then
                current_version=$(php -v | head -n1 | awk '{print $2}')
                echo"PHP版本: $current_version"
                if [[ "$current_version" < "7.4" ]]; then
                    echo"🚨 严重: PHP版本过低,存在重大安全风险!"
                fi
            fi
            ;;
    esac
}

check_version "apache"
check_version "nginx"
check_version "mysql"
check_version "php"
echo""

# 3. 检查SSH配置安全性
echo"4. SSH安全配置检查:"
ssh_config="/etc/ssh/sshd_config"

if [ -f "$ssh_config" ]; then
    echo"检查SSH配置文件: $ssh_config"
    
    # 检查root登录
    root_login=$(grep "^PermitRootLogin"$ssh_config | awk '{print $2}')
    if [ "$root_login" != "no" ]; then
        echo"⚠️  建议: 禁用root SSH登录 (PermitRootLogin no)"
    else
        echo"✓ SSH root登录已禁用"
    fi
    
    # 检查密码认证
    password_auth=$(grep "^PasswordAuthentication"$ssh_config | awk '{print $2}')
    if [ "$password_auth" != "no" ]; then
        echo"⚠️  建议: 禁用密码认证,使用密钥登录 (PasswordAuthentication no)"
    else
        echo"✓ SSH密码认证已禁用"
    fi
    
    # 检查SSH协议版本
    protocol=$(grep "^Protocol"$ssh_config | awk '{print $2}')
    if [ "$protocol" != "2" ] && [ -n "$protocol" ]; then
        echo"⚠️  建议: 使用SSH协议版本2 (Protocol 2)"
    else
        echo"✓ SSH协议配置正确"
    fi
fi
echo""

# 4. 检查防火墙状态
echo"5. 防火墙状态检查:"
ifcommand -v ufw >/dev/null 2>&1; then
    ufw_status=$(ufw status | head -n1 | awk '{print $2}')
    echo"UFW防火墙状态: $ufw_status"
    if [ "$ufw_status" != "active" ]; then
        echo"⚠️  建议: 启用防火墙保护"
    fi
elifcommand -v firewall-cmd >/dev/null 2>&1; then
    firewalld_status=$(systemctl is-active firewalld)
    echo"Firewalld状态: $firewalld_status"
    if [ "$firewalld_status" != "active" ]; then
        echo"⚠️  建议: 启用防火墙保护"
    fi
elifcommand -v iptables >/dev/null 2>&1; then
    iptables_rules=$(iptables -L | wc -l)
    echo"Iptables规则数: $iptables_rules"
    if [ "$iptables_rules" -lt 10 ]; then
        echo"⚠️  建议: 配置防火墙规则"
    fi
fi
echo""

# 5. 检查异常登录
echo"6. 异常登录检查:"
echo"最近10次登录记录:"
last -n 10 | grep -v "reboot"

echo""
echo"失败登录尝试:"
lastb -n 5 2>/dev/null | head -n 5 || echo"暂无失败登录记录"
echo""

# 6. 检查可疑进程
echo"7. 系统进程检查:"
echo"高CPU占用进程:"
ps aux --sort=-%cpu | head -n 6

echo""
echo"高内存占用进程:"
ps aux --sort=-%mem | head -n 6
echo""

# 7. 检查网络连接
echo"8. 网络连接检查:"
echo"监听端口:"
netstat -tlnp | grep LISTEN | head -n 10

echo""
echo"外部连接:"
netstat -tn | grep ESTABLISHED | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | head -n 5
echo""

# 8. 生成安全评分
security_score=100
issues=0

# 根据发现的问题扣分
if [[ "$root_login" != "no" ]]; then
    security_score=$((security_score - 15))
    issues=$((issues + 1))
fi

if [[ "$password_auth" != "no" ]]; then
    security_score=$((security_score - 10))  
    issues=$((issues + 1))
fi

ifcommand -v php >/dev/null 2>&1; then
    php_version=$(php -v | head -n1 | awk '{print $2}')
    if [[ "$php_version" < "7.4" ]]; then
        security_score=$((security_score - 20))
        issues=$((issues + 1))
    fi
fi

echo"================================"
echo"安全评估结果:"
echo"发现问题: $issues 个"
echo"安全评分: $security_score/100"

if [ $security_score -ge 90 ]; then
    echo"✅ 安全状态: 良好"
elif [ $security_score -ge 70 ]; then
    echo"⚠️  安全状态: 一般,建议改进"
else
    echo"🚨 安全状态: 危险,请立即处理!"
fi

echo""
echo "扫描完成时间: $(date)"

定期更新系统补丁:

代码语言:javascript
复制
#!/bin/bash
# 自动化补丁更新脚本 patch_update.sh

LOG_FILE="/var/log/patch_update.log"
BACKUP_DIR="/backup/system_backup"

log_message() {
    echo"[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

log_message "开始系统补丁更新流程"

# 1. 系统备份
log_message "创建系统备份..."
mkdir -p $BACKUP_DIR/$(date +%Y%m%d)

# 备份关键配置文件
tar -czf $BACKUP_DIR/$(date +%Y%m%d)/system_config.tar.gz \
    /etc/nginx/ \
    /etc/apache2/ \
    /etc/mysql/ \
    /etc/ssh/sshd_config \
    /etc/crontab \
    /etc/fstab \
    2>/dev/null

log_message "系统配置备份完成"

# 2. 更新软件包列表
ifcommand -v apt >/dev/null 2>&1; then
    log_message "更新APT软件包列表..."
    apt update >> $LOG_FILE 2>&1
    
    # 检查可用更新
    UPDATES=$(apt list --upgradable 2>/dev/null | wc -l)
    log_message "发现 $((UPDATES-1)) 个可用更新"
    
    if [ $UPDATES -gt 1 ]; then
        # 更新安全补丁
        log_message "安装安全更新..."
        apt upgrade -y >> $LOG_FILE 2>&1
        
        # 更新内核(如果需要)
        if apt list --upgradable 2>/dev/null | grep -q linux-image; then
            log_message "发现内核更新,安装中..."
            apt install -y linux-image-generic >> $LOG_FILE 2>&1
            echo"需要重启系统以应用内核更新" | tee -a $LOG_FILE
        fi
    fi
    
elifcommand -v yum >/dev/null 2>&1; then
    log_message "更新YUM软件包..."
    yum check-update >> $LOG_FILE 2>&1
    
    # 只更新安全补丁
    log_message "安装安全更新..."
    yum update -y --security >> $LOG_FILE 2>&1
    
    # 检查内核更新
    if yum check-update kernel 2>/dev/null | grep -q kernel; then
        log_message "发现内核更新,安装中..."
        yum update -y kernel >> $LOG_FILE 2>&1
        echo"需要重启系统以应用内核更新" | tee -a $LOG_FILE
    fi
fi

# 3. 清理旧的软件包
log_message "清理系统缓存..."
ifcommand -v apt >/dev/null 2>&1; then
    apt autoremove -y >> $LOG_FILE 2>&1
    apt autoclean >> $LOG_FILE 2>&1
elifcommand -v yum >/dev/null 2>&1; then
    yum autoremove -y >> $LOG_FILE 2>&1
    yum clean all >> $LOG_FILE 2>&1
fi

# 4. 验证关键服务状态
log_message "验证服务状态..."
services=("nginx""apache2""mysql""ssh")

for service in"${services[@]}"; do
    if systemctl is-active --quiet $service; then
        log_message "✓ $service 服务运行正常"
    elif systemctl is-enabled --quiet $service; then
        log_message "⚠️  $service 服务已启用但未运行,尝试重启..."
        systemctl restart $service
        if systemctl is-active --quiet $service; then
            log_message "✓ $service 服务重启成功"
        else
            log_message "❌ $service 服务重启失败,需要人工处理"
        fi
    fi
done

# 5. 发送更新报告
UPDATED_PACKAGES=$(grep "upgraded"$LOG_FILE | tail -n 10)
RESTART_REQUIRED=$([ -f /var/run/reboot-required ] && echo"是" || echo"否")

cat > /tmp/patch_report.txt << EOF
系统补丁更新报告

更新时间: $(date)
服务器: $(hostname)
操作系统: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)

更新摘要:
$(echo "$UPDATED_PACKAGES" | head -n 5)

需要重启: $RESTART_REQUIRED

详细日志请查看: $LOG_FILE
EOF

# 发送企业微信通知
curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key" \
     -H "Content-Type: application/json" \
     -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"📋 系统补丁更新完成\n\n$(cat /tmp/patch_report.txt)\"}}"

log_message "补丁更新流程完成"

rm -f /tmp/patch_report.txt

禁忌十:文档不写,知识全在脑子里

很多运维觉得写文档浪费时间,所有的操作步骤、配置细节都记在脑子里。等你请假或者离职了,其他人接手就抓瞎了。出了问题没人能处理,最后还是要找你背锅。

我见过一个运维,负责公司的核心业务系统,从来不写文档。有次他生病住院一周,期间系统出了个小问题,其他同事完全不知道怎么处理,只能等他出院。老板很不满意:"怎么离了一个人系统就维护不了?"

正确的文档管理方式:

代码语言:javascript
复制
# 系统运维手册

## 1. 系统架构概览

### 1.1 服务器清单
| 服务器名称 | IP地址 | 角色 | 配置 | 负责人 |
|-----------|--------|------|------|--------|
| web-prod-01 | 192.168.1.10 | Web服务器 | 8C16G | 老杨 |
| web-prod-02 | 192.168.1.11 | Web服务器 | 8C16G | 老杨 |
| db-prod-01 | 192.168.1.20 | MySQL主库 | 16C32G | 老杨 |
| db-prod-02 | 192.168.1.21 | MySQL从库 | 16C32G | 小张 |

### 1.2 网络拓扑

Internet ↓ [负载均衡器 F5] ↓ [Web服务器集群] ↓ [数据库集群]

代码语言:javascript
复制

### 1.3 监控系统
- Zabbix: http://monitor.internal.com
- Grafana: http://grafana.internal.com  
- 日志系统: http://logs.internal.com

## 2. 常见故障处理

### 2.1 网站无法访问

**症状**: 用户反馈网站打不开,返回502错误

**排查步骤**:
1. 检查负载均衡器状态
   ```bash
   curl -I http://192.168.1.10
   # 预期结果: HTTP/1.1 200 OK

2. 检查Web服务器状态

代码语言:javascript
复制
systemctl status nginx
# 预期结果: Active: active (running)

3. 检查应用程序状态

代码语言:javascript
复制
ps aux | grep php-fpm
# 应该看到php-fpm进程运行

4. 查看错误日志

代码语言:javascript
复制
tail -f /var/log/nginx/error.log
tail -f /var/log/php7.4-fpm.log

常见原因及解决方案:

  • • Nginx配置错误: 检查配置文件语法 nginx -t
  • • PHP-FPM停止: 重启服务 systemctl restart php7.4-fpm
  • • 磁盘空间满: 清理日志文件
  • • 数据库连接失败: 检查数据库状态

2.2 数据库连接异常

症状: 应用程序报"Database connection failed"错误

排查步骤:

1. 检查MySQL服务状态

代码语言:javascript
复制
systemctl status mysql
mysqladmin -u root -p ping

2. 检查连接数

代码语言:javascript
复制
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';

3. 检查磁盘空间

代码语言:javascript
复制
df -h /var/lib/mysql

4. 检查错误日志

代码语言:javascript
复制
tail -f /var/log/mysql/error.log

解决方案:

  • • 连接数过多: 优化应用程序连接池,或增加max_connections
  • • 磁盘空间不足: 清理binlog或扩容
  • • InnoDB崩溃: 设置innodb_force_recovery尝试恢复

2.3 系统负载过高

症状: 系统响应慢,load average > 10

排查步骤:

1. 查看系统负载

代码语言:javascript
复制
uptime
top -c
htop  # 如果安装了

2. 查看IO情况

代码语言:javascript
复制
iostat -x 1
iotop  # 查看哪个进程IO最高

3. 查看内存使用

代码语言:javascript
复制
free -h
ps aux --sort=-%mem | head -20

4. 查看网络连接

代码语言:javascript
复制
netstat -ant | wc -l
ss -s

3. 日常维护操作

3.1 每日检查清单

代码语言:javascript
复制
#!/bin/bash
# daily_check.sh - 每日系统检查脚本

echo"=== 每日系统检查 $(date) ==="

# 1. 系统负载
echo"1. 系统负载:"
uptime

# 2. 磁盘空间
echo"2. 磁盘使用率:"
df -h | grep -E "(Filesystem|/dev/)"

# 3. 内存使用
echo"3. 内存使用情况:"
free -h

# 4. 服务状态
echo"4. 关键服务状态:"
services=("nginx""mysql""php7.4-fpm""redis")
for service in"${services[@]}"; do
    if systemctl is-active --quiet $service; then
        echo"✓ $service: 运行正常"
    else
        echo"❌ $service: 异常"
    fi
done

# 5. 数据库状态
echo"5. 数据库连接数:"
mysql -N -e "SHOW STATUS LIKE 'Threads_connected'" | awk '{print "当前连接数: " $2}'

# 6. 备份状态
echo"6. 昨日备份检查:"
YESTERDAY=$(date -d "yesterday" +%Y%m%d)
if [ -f "/backup/mysql/db_${YESTERDAY}.sql.gz" ]; then
    BACKUP_SIZE=$(stat -c%s "/backup/mysql/db_${YESTERDAY}.sql.gz")
    echo"✓ 数据库备份存在,大小: $(($BACKUP_SIZE / 1024 / 1024))MB"
else
    echo"❌ 数据库备份不存在"
fi

echo "=== 检查完成 ==="

3.2 每周维护任务

代码语言:javascript
复制
#!/bin/bash
# weekly_maintenance.sh - 每周维护任务

echo"开始每周维护任务..."

# 1. 清理旧日志
find /var/log -name "*.log.*" -mtime +7 -delete
find /var/log -name "*.[0-9].gz" -mtime +7 -delete

# 2. 清理临时文件
find /tmp -type f -mtime +3 -delete

# 3. 更新系统软件包列表
apt update

# 4. 检查可用更新
apt list --upgradable > /tmp/available_updates.txt

# 5. 清理Docker镜像(如果使用)
ifcommand -v docker >/dev/null 2>&1; then
    docker system prune -f
fi

# 6. 检查磁盘碎片(ext4文件系统)
for partition in $(df -t ext4 --output=source | grep -v "Filesystem"); do
    echo"检查分区 $partition 的碎片率..."
    e2fsck -fn $partition 2>&1 | grep "non-contiguous"
done

echo "每周维护任务完成"

4. 应急联系方式

角色

姓名

电话

微信

邮箱

运维主管

老杨

138-0000-0000

yang_devops

yang@company.com

运维工程师

小张

139-0000-0000

zhang_ops

zhang@company.com

DBA

小李

137-0000-0000

li_dba

li@company.com

开发负责人

小王

136-0000-0000

wang_dev

wang@company.com

5. 重要系统密码

⚠️ 注意: 密码信息存储在密码管理系统中,具体位置:

  • • 1Password企业账户: ops-team@company.com
  • • Vault地址: https://vault.internal.com
  • • 紧急情况联系运维主管获取

6. 版本更新记录

版本

日期

修改人

修改内容

v1.0

2024-01-01

老杨

初始版本

v1.1

2024-02-01

老杨

增加Docker维护步骤

v1.2

2024-03-01

小张

更新联系方式

代码语言:javascript
复制

而且要建立知识分享机制:

```bash
#!/bin/bash
# knowledge_share.sh - 知识分享脚本,记录每次操作

KNOWLEDGE_DB="/var/log/ops_knowledge.md"

add_knowledge() {
    local category=$1
    local title=$2  
    local content=$3
    local operator=${4:-$(whoami)}
    
    cat >> $KNOWLEDGE_DB << EOF

## $category - $title

**时间**: $(date)  
**操作人**: $operator

### 问题描述
$content

### 解决步骤
\`\`\`bash
# 在这里记录具体的操作命令
\`\`\`

### 经验总结
- 
- 

---

EOF

    echo "知识条目已添加到 $KNOWLEDGE_DB"
}

# 使用示例
# add_knowledge "故障处理" "MySQL主从同步延迟" "发现主从延迟超过100秒,影响数据一致性"

这样做的好处是,任何人都能快速上手系统维护,不会因为某个人不在就无法处理问题。而且新人入职时,有完整的文档可以参考,能快速熟悉系统。

老杨时间

这里老杨先声明一下,日常生活中大家都叫老杨波哥,跟辈分没关系,主要是岁数大了.就一个代称而已. 老杨的00后小同事老杨喊都是带哥的.张哥,李哥的. 但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适. 比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“ 这个氛围配这个称呼在互联网这行来讲就有点对不齐! 每次遇到这个情况老杨就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.老杨干了,你们随意!” 所以以后咱们改叫老杨,即市井又低调.还挺亲切,老杨觉得挺好.

运维X档案系列文章:

从告警到CTO:一个P0故障的11小时生死时速

企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)

看完别走.修行在于点赞、转发、在看.攒今世之功德,修来世之福报

老杨AI的号: 98dev

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-09-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT运维技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 禁忌六:变更不通知,出问题才说"我改了配置"
  • 禁忌七:日志不收集,出问题两眼一抹黑
  • 禁忌八:容量规划不做,系统扛不住了才加机器
  • 禁忌九:安全漏洞不修补,被攻击了才知道系统有洞
  • 禁忌十:文档不写,知识全在脑子里
    • 2.2 数据库连接异常
    • 2.3 系统负载过高
  • 3. 日常维护操作
    • 3.1 每日检查清单
    • 3.2 每周维护任务
  • 4. 应急联系方式
  • 5. 重要系统密码
  • 6. 版本更新记录
  • 老杨时间
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档