引言:告别重复劳动,拥抱自动化运维
作为运维工程师,您是否经常面临这样的情况:每天重复执行相同的检查命令、手动部署应用到多台服务器、凌晨收到告警后匆忙登录服务器排查问题?这些重复性工作不仅耗费大量时间和精力,还容易因人为失误导致故障。自动化运维脚本是解决这些问题的关键。结合FinalShell强大的终端能力和命令片段管理功能,您可以轻松编写和管理各类自动化运维脚本,让机器替代人工完成重复劳动。
一、Shell脚本基础与FinalShell集成
1.1 在FinalShell中编写脚本
FinalShell提供了多种方式来编写和管理Shell脚本:
- 内置编辑器:通过SFTP文件管理器双击远程脚本文件,直接在FinalShell内置编辑器中编辑
- 命令片段:将常用脚本保存为命令片段,随时一键执行
- 本地编辑+上传:在本地IDE中编写脚本,通过SFTP上传到服务器
1.2 脚本模板规范
编写高质量脚本的基础模板:
#!/bin/bash
# ============================================================
# 脚本名称: script_name.sh
# 功能描述: 脚本功能的简要描述
# 作者: Your Name
# 创建日期: 2026-03-15
# 版本: v1.0
# ============================================================
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 日志函数
log_info() { echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }
# 检查root权限
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "此脚本需要root权限运行"
exit 1
fi
}
# 主函数
main() {
log_info "脚本开始执行..."
# 在这里编写核心逻辑
log_info "脚本执行完成"
}
main "$@"
在FinalShell中编写和测试Shell自动化脚本
二、服务器自动巡检脚本
2.1 全面巡检脚本
每日自动巡检是运维的基本功,以下脚本覆盖了服务器健康检查的关键维度:
#!/bin/bash
# 服务器自动巡检脚本
REPORT_FILE="/var/log/inspection/$(date +%Y%m%d_%H%M%S).html"
HOSTNAME=$(hostname)
IP_ADDR=$(hostname -I | awk '{print $1}')
mkdir -p /var/log/inspection
generate_report() {
cat > $REPORT_FILE << 'HEADER'
<html><head><title>服务器巡检报告</title>
<style>body{font-family:sans-serif;margin:20px}
table{border-collapse:collapse;width:100%}
td,th{border:1px solid #ddd;padding:8px;text-align:left}
th{background:#4a90d9;color:#fff}
.warn{color:#f39c12}.error{color:#e74c3c}.ok{color:#27ae60}
</style></head><body>
HEADER
echo "<h1>服务器巡检报告</h1>" >> $REPORT_FILE
echo "<p>主机名: $HOSTNAME | IP: $IP_ADDR | 时间: $(date)</p>" >> $REPORT_FILE
# CPU检查
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f", $2+$4}')
echo "<h2>CPU状态</h2>" >> $REPORT_FILE
echo "<p>CPU使用率: ${CPU_USAGE}%</p>" >> $REPORT_FILE
# 内存检查
MEM_TOTAL=$(free -m | awk '/Mem:/{print $2}')
MEM_USED=$(free -m | awk '/Mem:/{print $3}')
MEM_PERCENT=$((MEM_USED * 100 / MEM_TOTAL))
echo "<h2>内存状态</h2>" >> $REPORT_FILE
echo "<p>内存使用: ${MEM_USED}MB / ${MEM_TOTAL}MB (${MEM_PERCENT}%)</p>" >> $REPORT_FILE
# 磁盘检查
echo "<h2>磁盘状态</h2><table><tr><th>挂载点</th><th>使用率</th><th>状态</th></tr>" >> $REPORT_FILE
df -h | grep "^/dev" | while read line; do
MOUNT=$(echo $line | awk '{print $6}')
USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
STATUS="ok"
[[ $USAGE -ge 80 ]] && STATUS="warn"
[[ $USAGE -ge 90 ]] && STATUS="error"
echo "<tr><td>${MOUNT}</td><td>${USAGE}%</td><td class='${STATUS}'>${STATUS}</td></tr>" >> $REPORT_FILE
done
echo "</table>" >> $REPORT_FILE
# 关键服务检查
echo "<h2>服务状态</h2><table><tr><th>服务</th><th>状态</th></tr>" >> $REPORT_FILE
for svc in nginx mysql docker redis; do
if systemctl is-active --quiet $svc 2>/dev/null; then
echo "<tr><td>${svc}</td><td class='ok'>运行中</td></tr>" >> $REPORT_FILE
else
echo "<tr><td>${svc}</td><td class='error'>已停止</td></tr>" >> $REPORT_FILE
fi
done
echo "</table></body></html>" >> $REPORT_FILE
echo "巡检报告已生成: $REPORT_FILE"
}
generate_report
2.2 将巡检脚本加入FinalShell命令片段
在FinalShell中将巡检脚本保存为命令片段,实现一键巡检:
- 打开命令片段管理器
- 新建片段,命名为"服务器日常巡检"
- 粘贴脚本内容或输入脚本路径
- 设置快捷键(如Ctrl+Shift+I)
- 使用同步输入功能可同时在多台服务器执行巡检
三、自动化部署脚本
3.1 Java应用自动部署
#!/bin/bash
# Java应用自动部署脚本
APP_NAME="myapp"
APP_DIR="/opt/apps/${APP_NAME}"
BACKUP_DIR="/opt/backup/${APP_NAME}"
JAR_FILE="${APP_NAME}.jar"
LOG_FILE="/var/log/${APP_NAME}/deploy.log"
PID_FILE="${APP_DIR}/${APP_NAME}.pid"
deploy() {
log_info "开始部署 ${APP_NAME}..."
# 1. 创建备份
if [[ -f "${APP_DIR}/${JAR_FILE}" ]]; then
BACKUP_NAME="${JAR_FILE}.$(date +%Y%m%d%H%M%S).bak"
mkdir -p ${BACKUP_DIR}
cp "${APP_DIR}/${JAR_FILE}" "${BACKUP_DIR}/${BACKUP_NAME}"
log_info "已备份旧版本: ${BACKUP_NAME}"
fi
# 2. 停止旧进程
if [[ -f "${PID_FILE}" ]]; then
OLD_PID=$(cat ${PID_FILE})
if kill -0 ${OLD_PID} 2>/dev/null; then
log_info "停止旧进程 PID: ${OLD_PID}"
kill ${OLD_PID}
sleep 5
# 如果进程仍未退出,强制终止
kill -0 ${OLD_PID} 2>/dev/null && kill -9 ${OLD_PID}
fi
fi
# 3. 部署新版本(假设新包已通过SFTP上传到/tmp目录)
cp /tmp/${JAR_FILE} ${APP_DIR}/${JAR_FILE}
chmod +x ${APP_DIR}/${JAR_FILE}
log_info "新版本已部署"
# 4. 启动应用
cd ${APP_DIR}
nohup java -Xms512m -Xmx1024m \
-jar ${JAR_FILE} \
--spring.profiles.active=prod \
> /var/log/${APP_NAME}/stdout.log 2>&1 &
echo $! > ${PID_FILE}
log_info "应用已启动,PID: $(cat ${PID_FILE})"
# 5. 健康检查
sleep 10
for i in {1..6}; do
if curl -sf http://localhost:8080/actuator/health > /dev/null 2>&1; then
log_info "健康检查通过,部署成功!"
return 0
fi
log_warn "等待应用启动... (${i}/6)"
sleep 5
done
log_error "健康检查失败,准备回滚..."
rollback
return 1
}
rollback() {
log_warn "开始回滚..."
LATEST_BACKUP=$(ls -t ${BACKUP_DIR}/*.bak 2>/dev/null | head -1)
if [[ -n "${LATEST_BACKUP}" ]]; then
# 停止当前进程
[[ -f "${PID_FILE}" ]] && kill $(cat ${PID_FILE}) 2>/dev/null
sleep 3
# 恢复备份
cp "${LATEST_BACKUP}" "${APP_DIR}/${JAR_FILE}"
# 重新启动
cd ${APP_DIR}
nohup java -Xms512m -Xmx1024m -jar ${JAR_FILE} --spring.profiles.active=prod > /var/log/${APP_NAME}/stdout.log 2>&1 &
echo $! > ${PID_FILE}
log_info "回滚完成,PID: $(cat ${PID_FILE})"
else
log_error "没有找到可用的备份文件"
fi
}
deploy
通过FinalShell执行自动化部署,支持一键回滚
3.2 前端应用部署脚本
#!/bin/bash
# 前端应用自动部署脚本
WEB_ROOT="/var/www/myapp"
BACKUP_DIR="/var/www/backup"
NGINX_CONF="/etc/nginx/conf.d/myapp.conf"
deploy_frontend() {
log_info "开始部署前端应用..."
# 备份当前版本
BACKUP_NAME="myapp_$(date +%Y%m%d%H%M%S)"
mkdir -p ${BACKUP_DIR}
tar czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" -C /var/www myapp/
log_info "当前版本已备份"
# 解压新版本(假设已上传到/tmp)
rm -rf ${WEB_ROOT}/*
tar xzf /tmp/dist.tar.gz -C ${WEB_ROOT}/
log_info "新版本已解压"
# 设置正确的文件权限
chown -R nginx:nginx ${WEB_ROOT}
chmod -R 755 ${WEB_ROOT}
# 测试Nginx配置
nginx -t
if [[ $? -eq 0 ]]; then
nginx -s reload
log_info "Nginx配置已重载,部署成功!"
else
log_error "Nginx配置测试失败"
# 回滚
tar xzf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" -C /var/www/
nginx -s reload
log_warn "已回滚到上一版本"
fi
# 清理30天前的备份
find ${BACKUP_DIR} -name "myapp_*.tar.gz" -mtime +30 -delete
}
deploy_frontend
四、日志分析与监控脚本
4.1 Nginx日志分析脚本
#!/bin/bash
# Nginx访问日志实时分析脚本
LOG_FILE="/var/log/nginx/access.log"
echo "===== Nginx日志分析报告 ====="
echo "分析时间: $(date)"
echo ""
# 今日请求总量
TODAY=$(date +%d/%b/%Y)
TOTAL=$(grep "${TODAY}" ${LOG_FILE} | wc -l)
echo "今日请求总量: ${TOTAL}"
# TOP 10 访问IP
echo ""
echo "===== TOP 10 访问IP ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $1}' | sort | uniq -c | sort -rn | head -10 | \
while read count ip; do
printf " %-16s %6d 次\n" "$ip" "$count"
done
# TOP 10 请求URL
echo ""
echo "===== TOP 10 请求URL ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $7}' | sort | uniq -c | sort -rn | head -10 | \
while read count url; do
printf " %-40s %6d 次\n" "$url" "$count"
done
# HTTP状态码统计
echo ""
echo "===== HTTP状态码分布 ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $9}' | sort | uniq -c | sort -rn | \
while read count code; do
printf " HTTP %s: %6d 次\n" "$code" "$count"
done
# 错误请求(4xx/5xx)
ERROR_COUNT=$(grep "${TODAY}" ${LOG_FILE} | awk '$9 >= 400 {print $0}' | wc -l)
echo ""
echo "错误请求总数(4xx+5xx): ${ERROR_COUNT}"
# 带宽统计
BANDWIDTH=$(grep "${TODAY}" ${LOG_FILE} | awk '{sum+=$10} END {printf "%.2f MB", sum/1024/1024}')
echo "今日带宽消耗: ${BANDWIDTH}"
4.2 异常告警脚本
#!/bin/bash
# 系统异常实时告警脚本
ALERT_LOG="/var/log/alert.log"
CHECK_INTERVAL=60
monitor_system() {
while true; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 检查CPU使用率
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.0f", $2+$4}')
if [[ $CPU -gt 80 ]]; then
echo "[${TIMESTAMP}] ALERT: CPU使用率过高 ${CPU}%" | tee -a $ALERT_LOG
fi
# 检查内存使用率
MEM=$(free | awk '/Mem:/{printf "%.0f", $3/$2*100}')
if [[ $MEM -gt 85 ]]; then
echo "[${TIMESTAMP}] ALERT: 内存使用率过高 ${MEM}%" | tee -a $ALERT_LOG
fi
# 检查磁盘使用率
df -h | grep "^/dev" | while read line; do
USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
MOUNT=$(echo $line | awk '{print $6}')
if [[ $USAGE -gt 90 ]]; then
echo "[${TIMESTAMP}] CRITICAL: 磁盘 ${MOUNT} 使用率 ${USAGE}%" | tee -a $ALERT_LOG
fi
done
# 检查关键服务
for svc in nginx mysql redis; do
if ! systemctl is-active --quiet $svc 2>/dev/null; then
echo "[${TIMESTAMP}] CRITICAL: 服务 ${svc} 已停止!尝试重启..." | tee -a $ALERT_LOG
systemctl restart $svc
sleep 3
if systemctl is-active --quiet $svc; then
echo "[${TIMESTAMP}] INFO: 服务 ${svc} 已成功重启" | tee -a $ALERT_LOG
else
echo "[${TIMESTAMP}] FATAL: 服务 ${svc} 重启失败!" | tee -a $ALERT_LOG
fi
fi
done
sleep $CHECK_INTERVAL
done
}
monitor_system
通过自动化脚本实现日志分析与异常实时告警
五、定时任务管理
5.1 Crontab配置模板
通过FinalShell编辑crontab,设置定时自动执行脚本:
# 编辑定时任务
crontab -e
# ============ 定时任务配置 ============
# 每日凌晨2点执行服务器巡检
0 2 * * * /opt/scripts/inspection.sh >> /var/log/cron/inspection.log 2>&1
# 每6小时执行一次数据库备份
0 */6 * * * /opt/scripts/db_backup.sh >> /var/log/cron/backup.log 2>&1
# 每天凌晨3点清理过期日志
0 3 * * * /opt/scripts/log_cleanup.sh >> /var/log/cron/cleanup.log 2>&1
# 每5分钟执行一次系统监控
*/5 * * * * /opt/scripts/monitor.sh >> /var/log/cron/monitor.log 2>&1
# 每周日凌晨执行全量备份
0 1 * * 0 /opt/scripts/full_backup.sh >> /var/log/cron/full_backup.log 2>&1
# 每月1号生成月度报告
0 8 1 * * /opt/scripts/monthly_report.sh >> /var/log/cron/report.log 2>&1
5.2 日志清理脚本
#!/bin/bash
# 自动日志清理脚本
LOG_DIRS=(
"/var/log/nginx"
"/var/log/mysql"
"/var/log/myapp"
"/var/log/inspection"
)
RETENTION_DAYS=30
for dir in "${LOG_DIRS[@]}"; do
if [[ -d "$dir" ]]; then
COUNT=$(find "$dir" -type f -name "*.log" -mtime +${RETENTION_DAYS} | wc -l)
if [[ $COUNT -gt 0 ]]; then
find "$dir" -type f -name "*.log" -mtime +${RETENTION_DAYS} -delete
echo "已清理 ${dir} 中 ${COUNT} 个过期日志文件"
fi
# 压缩7天前的日志
find "$dir" -type f -name "*.log" -mtime +7 ! -name "*.gz" -exec gzip {} \;
fi
done
# 清理系统日志
journalctl --vacuum-time=30d 2>/dev/null
echo "日志清理完成: $(date)"
六、脚本管理最佳实践
6.1 脚本版本管理
- 使用Git管理脚本:在服务器上用Git仓库管理所有运维脚本
- 添加版本标识:每个脚本头部注明版本号和修改记录
- 代码审核:重要脚本修改需经过同事Review
- FinalShell同步:通过FinalShell的SFTP功能保持本地和远程脚本同步
6.2 脚本安全规范
- 最小权限原则:脚本只申请必要的执行权限
- 敏感信息保护:密码和密钥不硬编码在脚本中,使用环境变量或配置文件
- 操作确认机制:危险操作(如删除、重启)增加确认提示
- 详细日志记录:每个关键操作都记录日志,便于问题追溯
- 错误处理:使用set -euo pipefail确保错误能被捕获
总结
自动化运维是现代运维工程师的核心能力。通过FinalShell强大的终端能力和命令片段管理功能,结合本文介绍的各类实战脚本模板,您可以快速构建起一套完整的自动化运维体系。从日常巡检到应用部署,从日志分析到异常告警,自动化脚本可以显著提升运维效率,减少人为错误,让您从繁琐的重复劳动中解放出来,专注于更有价值的架构设计和技术创新。
立即下载最新版FinalShell,开始您的自动化运维之旅!