#!/usr/bin/env bash # ============================================================ # 容器日志兜底截断 # # 为什么需要它(2026-09-14 实测事故): # novalon-cicd/docker-compose.yml 里明明配了 # logging: { driver: json-file, options: { max-size: 10m, max-file: 3 } } # 但运行中容器的 HostConfig.LogConfig 实测为 {"Type":"json-file","Config":{}} # —— 配置从未生效,Gitea 单份日志涨到 849MB,占掉整盘 4%。 # # 根因:logging 驱动参数在**容器创建时**固化,事后改 compose 不重建则不生效。 # # 本脚本是**临时兜底**,不是终态。 # 终态:用 infra/cicd/docker-compose.gitea.yml 重建容器(含正确 logging 配置), # 之后本脚本可退化为纯监控用途。 # # 用法: # ./truncate-container-logs.sh # 截断超过阈值的日志 # ./truncate-container-logs.sh --check # 只报告,不截断 # ./truncate-container-logs.sh --threshold 50 # 自定义阈值(MB) # ============================================================ set -uo pipefail THRESHOLD_MB=100 CHECK_ONLY=0 # 用 while 而非 for 解析:for 迭代的是展开后的固定列表, # 循环内 shift 不会改变已排定的迭代序列,导致 `--check --threshold 50` 取错值 while [[ $# -gt 0 ]]; do case "$1" in --check) CHECK_ONLY=1; shift ;; --threshold) THRESHOLD_MB="${2:-100}"; shift 2 ;; -h|--help) sed -n '2,22p' "$0"; exit 0 ;; *) echo "未知参数: $1" >&2; exit 2 ;; esac done LOG_ROOT="${LOG_ROOT:-/var/lib/docker/containers}" ts() { date "+%Y-%m-%d %H:%M:%S"; } echo "[$(ts)] 容器日志检查(阈值 ${THRESHOLD_MB}MB,模式 $([[ $CHECK_ONLY == 1 ]] && echo 只读 || echo 截断))" TOTAL_BEFORE=0 TOTAL_AFTER=0 HIT=0 while IFS= read -r f; do [[ -f "$f" ]] || continue size_mb=$(( $(stat -c %s "$f") / 1048576 )) [[ $size_mb -lt $THRESHOLD_MB ]] && continue HIT=$((HIT + 1)) TOTAL_BEFORE=$((TOTAL_BEFORE + size_mb)) cid=$(basename "$(dirname "$f")") cname=$(docker inspect -f '{{.Name}}' "$cid" 2>/dev/null | sed 's|^/||' || echo "$cid") echo " ⚠️ ${cname}: ${size_mb}MB ($f)" if (( CHECK_ONLY == 0 )); then # truncate 对运行中的容器安全:Docker 以 O_APPEND 写,截断后继续追加 truncate -s 0 "$f" && echo " → 已截断" TOTAL_AFTER=$((TOTAL_AFTER + $(stat -c %s "$f") / 1048576)) fi done < <(find "$LOG_ROOT" -maxdepth 2 -name '*-json.log' 2>/dev/null) if (( HIT == 0 )); then echo " ✅ 无日志超过 ${THRESHOLD_MB}MB" else echo " 命中 $HIT 个" if (( CHECK_ONLY == 0 )); then echo " 释放约 $((TOTAL_BEFORE - TOTAL_AFTER))MB" df -h / | awk 'NR==2{print " 磁盘: 已用 "$5", 可用 "$4}' fi fi # 提醒:若命中说明 logging 配置仍未生效,需要重建容器才是终态修复 if (( HIT > 0 )); then echo " ℹ️ 命中的容器说明其 logging 轮转未生效 —— 请用带 logging 配置的 compose 重建容器(终态修复)" fi