Shell脚本如何配置容器日志采集

wen 实用脚本 1

Shell脚本如何配置容器日志采集:从基础到实战的完整指南

目录导读

  1. 容器日志采集的核心挑战
  2. Shell脚本在日志采集中的角色
  3. 环境准备与依赖安装
  4. 基础日志采集脚本编写
  5. 高级配置:动态采集与过滤器
  6. 日志轮转与存储优化
  7. 常见问题与问答

容器日志采集的核心挑战

在容器化环境中,Docker或Kubernetes默认的日志驱动(如json-file)会将所有输出写入宿主机特定目录,当容器数量激增时,手动管理日志变得困难,常见痛点包括:

Shell脚本如何配置容器日志采集

  • 日志文件无限增长:默认无轮转策略,磁盘容易爆满。
  • 格式混乱:不同容器输出的json、text、syslog格式需要统一解析。
  • 权限问题:采集脚本可能无法访问特定容器的日志路径。

Shell脚本的优势在于轻量、无需额外守护进程,且能直接调用Docker API或docker logs命令实现灵活采集。

Shell脚本在日志采集中的角色

Shell脚本适合作为“胶水层”,连接容器运行时与日志后端(如Elasticsearch、Splunk或本地文件),典型工作流:

容器日志 → Shell脚本采集 → 格式化 → 写入文件或发送到远程服务器

适用场景

  • 小型开发环境或边缘节点无需复杂日志平台。
  • 作为监控系统启动前的临时采集方案。
  • 对日志格式有特殊转换需求(如JSON转CSV)。

环境准备与依赖安装

在编写脚本前,确保宿主机具备以下条件:

# 检查Docker是否运行
docker ps &>/dev/null || { echo "Docker未运行"; exit 1; }
# 安装必要的工具(以Ubuntu为例)
sudo apt-get install -y jq curl  # jq用于解析JSON,curl用于发送HTTP请求

关键点

  • docker logs命令默认只显示最近日志,需添加--since--follow实现持续采集。
  • 使用docker inspect获取容器日志路径(默认位于/var/lib/docker/containers/<container_id>/<container_id>-json.log)。

基础日志采集脚本编写

以下脚本演示如何定期采集所有运行中容器的日志,并按容器名保存为独立文件:

#!/bin/bash
# 采集所有容器日志到 /var/log/container_logs/
OUTPUT_DIR="/var/log/container_logs"
mkdir -p "$OUTPUT_DIR"
# 获取所有容器ID(忽略退出状态)
docker ps -q | while read -r CID; do
    CONTAINER_NAME=$(docker inspect --format '{{.Name}}' "$CID" | sed 's/\///')
    # 使用jq提取日志内容(去除时间戳前缀,保持原始输出)
    docker logs "$CID" 2>/dev/null | jq -R '{"ts": now, "msg": .}' > "$OUTPUT_DIR/${CONTAINER_NAME}.json"
    # 每30秒轮询一次
    sleep 30 &
done
# 等待所有后台进程
wait

说明

  • 脚本通过docker logs抓取标准输出和错误(2>/dev/null隐藏Docker元数据)。
  • 使用jq将每行日志转换为JSON格式,并添加时间戳(now是jq内置函数)。
  • 每个容器独立文件,避免混写。

高级配置:动态采集与过滤器

实际生产环境中,往往需要按需采集特定容器或过滤敏感信息,以下脚本实现:

  • 基于标签(log_collect=true)筛选容器。
  • 过滤掉包含“DEBUG”且长度小于10的日志条目(节省空间)。
#!/bin/bash
# 高级日志采集:支持标签过滤与内容过滤
FILTER_LABEL="log_collect=true"
OUTPUT_DIR="/var/log/container_logs/filtered"
REGEX_IGNORE='^(DEBUG|TRACE).{0,10}$'  # 忽略以DEBUG/TRACE开头且短的日志
docker ps --filter "label=$FILTER_LABEL" -q | while read -r CID; do
    docker logs --follow "$CID" 2>/dev/null | while read -r line; do
        # 过滤条件
        if [[ "$line" =~ $REGEX_IGNORE ]]; then
            continue
        fi
        # 添加元数据
        echo "{\"container\": \"$(docker inspect --format '{{.Name}}' "$CID" | sed 's/\///')\", \"log\": $(jq -Rsa . <<<"$line")}" >> "$OUTPUT_DIR/merged.log"
    done
done

重点

  • --follow实现实时流式采集,适合监控场景。
  • 使用jq -Rsa .对特殊字符(如引号、换行)进行转义,防止JSON破坏。

日志轮转与存储优化

容器日志可能单日产生数GB,轮转策略必不可少,Shell脚本可实现logrotate风格的简单轮转:

#!/bin/bash
# 日志轮转:按文件大小分割(每100MB创建新文件)
MAX_SIZE=104857600  # 100MB
LOG_DIR="/var/log/container_logs"
rotate_file() {
    local base="$1"
    local count=${2:-1}
    if [ -f "${base}.${count}" ]; then
        rotate_file "$base" $((count+1))
    fi
    mv "${base}.json" "${base}.${count}.json" 2>/dev/null
}
cd "$LOG_DIR" || exit 1
for f in *.json; do
    if [ $(stat -c%s "$f") -gt $MAX_SIZE ]; then
        rotate_file "$(basename "$f" .json)"
    fi
done

优化建议

  • 结合cron每天凌晨执行轮转脚本。
  • 压缩旧日志:gzip -9 *.1.json
  • 设置保留天数:find . -name '*.json.gz' -mtime +30 -delete

常见问题与问答

Q1:Shell脚本采集日志与Filebeat/Logstash有什么区别?

  • 优势:Shell无需额外内存,适合资源受限的边缘设备;可快速定制,无需学习新工具。
  • 劣势:缺乏弹性、重试机制,大规模集群不稳定,生产环境建议使用Filebeat或Fluentd。

Q2:采集的日志中出现了乱码或特殊字符,如何解决?

  • 确保使用jq -Rsa .对输入进行JSON序列化。
  • 检查容器内应用编码:docker exec <container> locale,若为POSIX需设置export LC_ALL=C.UTF-8

Q3:脚本采集时磁盘I/O过高,如何限制?

  • 增加read -t 1等待时间,降低轮询频率。
  • 使用ionice -c 3降低脚本进程的I/O优先级。

Q4:如何将日志发送到远程服务器(如Elasticsearch)?

  • 在脚本中集成curlcurl -X POST "http://your-es-host:9200/logs/_doc" -H "Content-Type: application/json" -d "$(tail -1 output.log)"
  • 注意批量提交减少请求次数,可使用数组+curl --data-binary

Q5:Kubernetes环境下如何采集Pod日志?

  • Kubernetes默认使用journald,Shell脚本可通过kubectl logs代替docker logs
  • 或者直接读取Pod挂载的日志文件(如/var/log/pods/),需注意权限。

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