Shell脚本如何配置容器日志归档

wen 实用脚本 1

本文目录导读:

Shell脚本如何配置容器日志归档

  1. 基础Shell脚本实现日志归档
  2. 使用 logrotate 工具(推荐)
  3. Docker 容器日志管理
  4. 高级归档方案:按时间和内容分类
  5. 定时执行(Cron配置)
  6. 最佳实践建议

在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

最佳实践建议

  1. 使用 copytruncate:Docker 容器日志推荐使用 copytruncate 模式,避免影响容器的文件句柄
  2. 保留足够的日志:建议保留至少 30 天的日志用于问题诊断
  3. 监控磁盘空间:在脚本中加入磁盘使用率检查
  4. 错误处理:添加日志归档失败的告警机制
  5. 日志压缩:使用 gzip 压缩可减少 80-90% 的存储空间
  6. 权限管理:确保脚本有足够的权限读取和写入日志文件

根据你的具体需求(日志量、保留策略、系统资源等),可以选择适合的方案或组合使用。

抱歉,评论功能暂时关闭!