#!/bin/bash # 统一磁盘瘦身脚本 # 用途:整合所有清理功能,定时执行 # 执行时间:每日凌晨2点 set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } separator() { echo "======================================================================" } # 记录日志 LOG_DIR="/var/log/system-maintenance" mkdir -p "$LOG_DIR" LOG_FILE="$LOG_DIR/daily-cleanup-$(date +%Y%m%d_%H%M%S).log" exec > >(tee -a "$LOG_FILE") 2>&1 separator echo "统一磁盘瘦身脚本" echo "执行时间: $(date)" separator # 记录初始状态 INITIAL_DISK=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//') INITIAL_USED=$(df -h / | awk 'NR==2 {print $3}') INITIAL_AVAIL=$(df -h / | awk 'NR==2 {print $4}') log_info "初始磁盘状态:" log_info " 使用率: $INITIAL_DISK%" log_info " 已使用: $INITIAL_USED" log_info " 可用: $INITIAL_AVAIL" echo "" # ========== 1. Docker清理 ========== separator log_info "步骤1: Docker清理" separator # 清理悬空镜像 DANGLING=$(docker images -f "dangling=true" -q | wc -l) if [ "$DANGLING" -gt 0 ]; then log_info "清理 $DANGLING 个悬空镜像" docker image prune -f fi # 清理未使用的镜像(保留最近3个版本) UNUSED_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "novalon-website:[0-9]" | sort -r | tail -n +4) if [ -n "$UNUSED_IMAGES" ]; then log_info "清理旧版本镜像:" echo "$UNUSED_IMAGES" echo "$UNUSED_IMAGES" | xargs docker rmi -f 2>/dev/null || true fi # 清理构建缓存 log_info "清理Docker构建缓存" docker builder prune -a -f # 清理已停止容器 STOPPED=$(docker ps -f "status=exited" -q | wc -l) if [ "$STOPPED" -gt 0 ]; then log_info "清理 $STOPPED 个已停止容器" docker container prune -f fi # 清理未使用卷 UNUSED_VOLS=$(docker volume ls -q --filter "dangling=true" | wc -l) if [ "$UNUSED_VOLS" -gt 0 ]; then log_info "清理 $UNUSED_VOLS 个未使用卷" docker volume prune -f fi log_success "Docker清理完成" # ========== 2. 系统日志清理 ========== separator log_info "步骤2: 系统日志清理" separator # 清理journal日志(保留7天) if command -v journalctl &> /dev/null; then JOURNAL_SIZE=$(journalctl --disk-usage 2>/dev/null | grep -oE '[0-9.]+[MG]' || echo "0B") log_info "系统日志大小: $JOURNAL_SIZE" journalctl --vacuum-time=7d log_success "Journal日志清理完成" fi # 清理syslog等日志(保留7天) if [ -d "/var/log" ]; then log_info "清理旧日志文件..." find /var/log -type f -name "*.log.*" -mtime +7 -delete 2>/dev/null || true find /var/log -type f -name "*.gz" -mtime +7 -delete 2>/dev/null || true find /var/log -type f -name "*.1" -mtime +7 -delete 2>/dev/null || true # 压缩大日志 find /var/log -type f -name "*.log" -size +10M -exec gzip {} \; 2>/dev/null || true log_success "日志文件清理完成" fi # ========== 3. 包管理器缓存清理 ========== separator log_info "步骤3: 包管理器缓存清理" separator if command -v apt-get &> /dev/null; then log_info "清理APT缓存..." apt-get clean > /dev/null 2>&1 apt-get autoclean > /dev/null 2>&1 apt-get autoremove -y > /dev/null 2>&1 # 清理APT缓存目录 rm -rf /var/cache/apt/archives/*.deb 2>/dev/null || true rm -rf /var/cache/apt/archives/partial/* 2>/dev/null || true log_success "APT缓存清理完成" elif command -v yum &> /dev/null; then log_info "清理YUM缓存..." yum clean all > /dev/null 2>&1 rm -rf /var/cache/yum/* 2>/dev/null || true log_success "YUM缓存清理完成" fi # ========== 4. 临时文件清理 ========== separator log_info "步骤4: 临时文件清理" separator # 清理/tmp目录(超过7天) TMP_FILES=$(find /tmp -type f -mtime +7 2>/dev/null | wc -l) if [ "$TMP_FILES" -gt 0 ]; then log_info "清理 $TMP_FILES 个临时文件(>7天)" find /tmp -type f -mtime +7 -delete 2>/dev/null || true find /tmp -type d -empty -delete 2>/dev/null || true fi # 清理/var/tmp if [ -d "/var/tmp" ]; then find /var/tmp -type f -mtime +30 -delete 2>/dev/null || true fi log_success "临时文件清理完成" # ========== 5. 应用构建产物清理 ========== separator log_info "步骤5: 应用构建产物清理" separator # 清理novalon-website构建产物 if [ -d "/home/novalon/docker-app/novalon-website" ]; then log_info "清理novalon-website构建产物..." # 清理dist目录中的tar.gz文件 find /home/novalon/docker-app/novalon-website -name "*.tar.gz" -type f -delete 2>/dev/null || true # 清理.next缓存 find /home/novalon/docker-app/novalon-website -name ".next" -type d -exec rm -rf {} + 2>/dev/null || true log_success "应用构建产物清理完成" fi # 清理旧的备份文件 log_info "清理旧备份文件..." find /home/novalon -name "*.backup.*" -mtime +30 -delete 2>/dev/null || true find /home/novalon -name "*.bak" -mtime +30 -delete 2>/dev/null || true # ========== 6. 安装包清理 ========== separator log_info "步骤6: 安装包清理" separator # 清理/root下的安装包 if [ -d "/root" ]; then log_info "清理/root下的安装包..." # 查找并删除安装包目录(保留当前使用的) find /root -maxdepth 1 -type d -name "*panel*" -mtime +30 -exec rm -rf {} + 2>/dev/null || true find /root -maxdepth 1 -type f -name "*.tar.gz" -mtime +30 -delete 2>/dev/null || true find /root -maxdepth 1 -type f -name "*.zip" -mtime +30 -delete 2>/dev/null || true log_success "安装包清理完成" fi # ========== 7. 系统缓存清理 ========== separator log_info "步骤7: 系统缓存清理" separator # 清理用户缓存 if [ -d "/home" ]; then log_info "清理用户缓存..." find /home -type d -name ".cache" -exec rm -rf {} + 2>/dev/null || true fi # 清理root用户缓存 if [ -d "/root/.cache" ]; then rm -rf /root/.cache/* 2>/dev/null || true fi # 清理pip缓存 if command -v pip &> /dev/null; then pip cache purge 2>/dev/null || true fi if command -v pip3 &> /dev/null; then pip3 cache purge 2>/dev/null || true fi # 清理npm缓存 if command -v npm &> /dev/null; then npm cache clean --force 2>/dev/null || true fi log_success "系统缓存清理完成" # ========== 8. 容器健康检查 ========== separator log_info "步骤8: 容器健康检查" separator # 检查关键容器状态 CRITICAL_CONTAINERS=( "woodpecker-server" "woodpecker-agent" "novalon-nginx" "novalon-website" "forgejo" "postgresql" "registry" ) UNHEALTHY_COUNT=0 for container in "${CRITICAL_CONTAINERS[@]}"; do if docker ps -a --format "{{.Names}}" | grep -q "^${container}$"; then STATUS=$(docker inspect --format='{{.State.Status}}' "$container" 2>/dev/null) HEALTH=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null) if [ "$STATUS" != "running" ]; then log_warning "容器 $container 状态异常: $STATUS" UNHEALTHY_COUNT=$((UNHEALTHY_COUNT + 1)) elif [ -n "$HEALTH" ] && [ "$HEALTH" != "healthy" ]; then log_warning "容器 $container 健康状态异常: $HEALTH" UNHEALTHY_COUNT=$((UNHEALTHY_COUNT + 1)) else log_success "容器 $container 状态正常" fi fi done if [ $UNHEALTHY_COUNT -gt 0 ]; then log_warning "发现 $UNHEALTHY_COUNT 个异常容器" else log_success "所有容器状态正常" fi # ========== 显示清理结果 ========== separator log_info "清理结果" separator # 记录最终状态 FINAL_DISK=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//') FINAL_USED=$(df -h / | awk 'NR==2 {print $3}') FINAL_AVAIL=$(df -h / | awk 'NR==2 {print $4}') echo "" log_info "磁盘使用情况对比:" echo " 清理前: $INITIAL_USED / 20G ($INITIAL_DISK%)" echo " 清理后: $FINAL_USED / 20G ($FINAL_DISK%)" echo " 改善: 使用率降低 $((INITIAL_DISK - FINAL_DISK))%" echo "" log_info "磁盘空间统计:" echo " Docker: $(du -sh /var/lib/docker 2>/dev/null | awk '{print $1}')" echo " 日志: $(du -sh /var/log 2>/dev/null | awk '{print $1}')" echo " Home: $(du -sh /home 2>/dev/null | awk '{print $1}')" echo " Root: $(du -sh /root 2>/dev/null | awk '{print $1}')" echo "" log_info "Docker资源使用:" docker system df separator log_success "统一磁盘瘦身完成" separator echo "" log_info "清理摘要:" echo " ✅ Docker悬空镜像已清理" echo " ✅ Docker旧版本镜像已清理" echo " ✅ Docker构建缓存已清理" echo " ✅ 已停止容器已清理" echo " ✅ 未使用卷已清理" echo " ✅ 系统日志已清理" echo " ✅ 包管理器缓存已清理" echo " ✅ 临时文件已清理" echo " ✅ 应用构建产物已清理" echo " ✅ 安装包已清理" echo " ✅ 系统缓存已清理" echo " ✅ 容器健康检查已完成" echo "" log_info "详细日志已保存到: $LOG_FILE" # 清理旧日志文件(保留30天) find "$LOG_DIR" -name "daily-cleanup-*.log" -mtime +30 -delete 2>/dev/null || true separator