Files
novalon-website/scripts/optimization/unified-daily-cleanup.sh
T
张翔 ec33aedd79
ci/woodpecker/push/woodpecker Pipeline failed
fix(docker): adapt Dockerfile.prod for Next.js 16 standalone output structure
- Fix standalone path: dist/standalone/novalon-website/
- Update static files path: dist/static
- Replace curl with wget in health checks (Alpine compatibility)
- Add monitoring and optimization scripts
- Configure external network for docker-compose

This resolves the deployment failure caused by Next.js 16's new standalone output structure.
2026-03-30 09:04:51 +08:00

332 lines
9.2 KiB
Bash
Executable File

#!/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