本文目录导读:

在Shell脚本中配置容器日志归档,主要涉及日志的收集、切割、压缩和清理,以下是几种常见的实现方案,包括原生Shell脚本、结合logrotate以及针对Docker容器的特定处理方法。
基础Shell脚本实现日志归档
一个基础的日志归档脚本通常包含以下步骤:
#!/bin/bash
# 日志归档配置
LOG_DIR="/var/log/myapp" # 日志目录
ARCHIVE_DIR="/var/log/archive" # 归档目录
RETENTION_DAYS=30 # 保留天数
MAX_LOG_SIZE=100M # 触发归档的日志大小
# 创建归档目录
mkdir -p "$ARCHIVE_DIR"
# 获取当前时间戳
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
# 遍历所有日志文件
for LOG_FILE in "$LOG_DIR"/*.log; do
# 检查文件是否存在
[ -f "$LOG_FILE" ] || continue
# 获取文件大小
FILE_SIZE=$(stat -c%s "$LOG_FILE")
MAX_SIZE=$((100 * 1024 * 1024)) # 转换为字节
# 检查是否需要归档
if [ "$FILE_SIZE" -ge "$MAX_SIZE" ]; then
# 获取文件名(不包含路径)
BASENAME=$(basename "$LOG_FILE")
# 压缩并归档
gzip -c "$LOG_FILE" > "${ARCHIVE_DIR}/${BASENAME}.${TIMESTAMP}.gz"
# 清空原日志文件(不清除文件,保持文件句柄)
> "$LOG_FILE"
echo "[$(date)] 归档成功: ${BASENAME} -> ${ARCHIVE_DIR}/${BASENAME}.${TIMESTAMP}.gz"
fi
done
# 清理过期归档文件
find "$ARCHIVE_DIR" -name "*.gz" -type f -mtime +$RETENTION_DAYS -delete
echo "[$(date)] 清理完成: 删除 ${RETENTION_DAYS} 天前的归档文件"
使用 logrotate 工具(推荐)
logrotate 是Linux系统上管理日志文件的专用工具,配置简单且功能强大。
安装 logrotate
# CentOS/RHEL yum install logrotate -y # Ubuntu/Debian apt-get install logrotate -y
创建 logrotate 配置文件
sudo vim /etc/logrotate.d/docker-logs
/var/lib/docker/containers/*/*.log {
daily # 每天轮转
rotate 30 # 保留30个轮转文件
compress # 压缩轮转的日志
delaycompress # 延迟压缩(下次轮转时压缩)
missingok # 忽略缺少的文件
notifempty # 日志为空则不轮转
copytruncate # 复制并截断原日志(适合Docker)
size 100M # 当日志达到100M时触发轮转
dateext # 使用日期作为扩展名
dateformat -%Y%m%d # 日期格式
postrotate
# 可选:通知应用重新打开日志文件
# kill -USR1 $(cat /var/run/myapp.pid)
endscript
}
测试配置
# 手动测试轮转 sudo logrotate -d /etc/logrotate.d/docker-logs # 强制执行 sudo logrotate -f /etc/logrotate.d/docker-logs
Docker 容器日志管理
1 配置 Docker 日志驱动限制
在 Docker 启动配置中设置日志轮转:
# 创建或编辑 /etc/docker/daemon.json sudo vim /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
}
}
重启 Docker 服务:
sudo systemctl restart docker
2 Shell 脚本清理 Docker 日志
#!/bin/bash
# docker-log-cleanup.sh
# 配置
MAX_LOG_COUNT=5
MAX_LOG_SIZE=100000000 # 100MB in bytes
# 获取所有容器的日志路径
for CONTAINER_ID in $(docker ps -aq); do
LOG_DIR="/var/lib/docker/containers/$CONTAINER_ID"
LOG_FILE="$LOG_DIR/${CONTAINER_ID}-json.log"
if [ -f "$LOG_FILE" ]; then
FILE_SIZE=$(stat -c%s "$LOG_FILE")
# 如果超过大小限制,截断文件
if [ "$FILE_SIZE" -gt "$MAX_LOG_SIZE" ]; then
# 备份保留最近的N行
tail -n 1000 "$LOG_FILE" > "${LOG_FILE}.tmp"
mv "${LOG_FILE}.tmp" "$LOG_FILE"
echo "[$(date)] 已清理容器 $CONTAINER_ID 的日志"
# 清理历史归档文件
find "$LOG_DIR" -name "*-json.log.*" -type f | sort -r | \
tail -n +$((MAX_LOG_COUNT + 1)) | xargs -r rm -f
fi
fi
done
高级归档方案:按时间和内容分类
#!/bin/bash
# advanced-log-archive.sh
CONFIG=(
["app1"]="/var/log/app1:debug,info,warn,error"
["app2"]="/var/log/app2:all"
)
ARCHIVE_BASE="/data/archive"
RETENTION_DAYS=60
archive_logs() {
local APP_NAME=$1
local LOG_PATH=$2
local LOG_LEVELS=$3
# 创建归档目录
local DATE_DIR="${ARCHIVE_BASE}/${APP_NAME}/$(date +%Y/%m/%d)"
mkdir -p "$DATE_DIR"
# 遍历日志级别
IFS=',' read -ra LEVELS <<< "$LOG_LEVELS"
for LEVEL in "${LEVELS[@]}"; do
# 根据级别提取日志
local ARCHIVE_FILE="${DATE_DIR}/${LEVEL}_$(date +%H%M%S).log"
case $LEVEL in
"all")
cat "$LOG_PATH"/*.log > "$ARCHIVE_FILE"
;;
"error")
grep -i "ERROR\|FATAL\|CRITICAL" "$LOG_PATH"/*.log > "$ARCHIVE_FILE"
;;
"warn")
grep -i "WARN\|WARNING" "$LOG_PATH"/*.log > "$ARCHIVE_FILE"
;;
"info")
grep -i "INFO" "$LOG_PATH"/*.log > "$ARCHIVE_FILE"
;;
"debug")
grep -i "DEBUG" "$LOG_PATH"/*.log > "$ARCHIVE_FILE"
;;
esac
# 压缩归档
gzip -f "$ARCHIVE_FILE"
done
# 清空日志
> "$LOG_PATH"/app.log
}
# 主循环
for APP in "${!CONFIG[@]}"; do
IFS=':' read -r PATH LEVELS <<< "${CONFIG[$APP]}"
archive_logs "$APP" "$PATH" "$LEVELS"
done
# 清理过期归档
find "$ARCHIVE_BASE" -type f -name "*.gz" -mtime +$RETENTION_DAYS -delete
定时执行(Cron配置)
使用 crontab 定期执行归档脚本:
# 编辑当前用户crontab crontab -e # 每天凌晨2点执行 0 2 * * * /usr/local/bin/log-archive.sh # 每6小时执行一次 0 */6 * * * /usr/local/bin/log-archive.sh # 每小时执行一次(用于高负载系统) 0 * * * * /usr/local/bin/log-archive.sh
最佳实践建议
- 使用 copytruncate:Docker 容器日志推荐使用
copytruncate模式,避免影响容器的文件句柄 - 保留足够的日志:建议保留至少 30 天的日志用于问题诊断
- 监控磁盘空间:在脚本中加入磁盘使用率检查
- 错误处理:添加日志归档失败的告警机制
- 日志压缩:使用 gzip 压缩可减少 80-90% 的存储空间
- 权限管理:确保脚本有足够的权限读取和写入日志文件
根据你的具体需求(日志量、保留策略、系统资源等),可以选择适合的方案或组合使用。