Loki 容器持续重启(ExitCode 137)排障与修复手册

适用场景:

  • Loki 容器持续 Restarting
  • docker ps 显示:
Restarting (137)
  • 宿主机:

    • CPU 正常
    • 内存正常
    • 磁盘 IO 很高
  • Loki 日志无明显 panic/OOM


一、问题现象

容器状态

查看 Loki 容器:

# 查看 Loki 容器运行状态
docker ps -a |grep loki

异常现象:

Restarting (137)

二、ExitCode 137 含义

137 = 128 + 9

表示:

SIGKILL (kill -9)

即:

  • 容器不是正常退出
  • 而是被系统/docker 强制杀死

常见原因:

  • OOM
  • docker healthcheck 超时
  • 磁盘 IO hang
  • overlay2 卡死
  • docker daemon 无响应

三、首次排查流程


1. 查看 Loki 日志

# 查看 Loki 最近 200 行日志
docker logs --tail 200 loki

作用:

  • 判断是否为 Loki 自身崩溃
  • 查看 WAL/TSDB/Chunk 是否异常

重点关注:

panic
OOM
corruption
wal
checkpoint
no space left
context deadline exceeded

2. 判断是否 OOMKilled

# 查看容器是否因为 OOM 被系统杀死
docker inspect loki |grep -i -A 20 oom

重点:

"OOMKilled": false

说明:

  • 不是内存问题

3. 查看容器详细状态

# 查看容器退出状态
docker inspect loki --format='{{json .State}}'

作用:

  • 查看 ExitCode
  • 查看 Error
  • 查看 FinishedAt
  • 查看是否被 kill

4. 查看宿主机 IO 状态

安装工具:

# 安装 IO 分析工具
apt install -y sysstat iotop

查看磁盘 IO

# 实时查看磁盘 IO 使用率
iostat -x 1

重点指标:

指标含义
%util磁盘利用率
awaitIO 等待时间

异常判断:

%util 接近 100%
await > 50ms

说明:

  • 磁盘已经被打满

查看哪个进程刷盘

# 查看实时 IO 占用进程
iotop -oPa

作用:

  • 定位 IO 风暴来源

重点关注:

  • dockerd
  • loki
  • promtail
  • journald

四、关键定位(本次事故根因)


1. 查看 Docker 总体存储

# 查看 Docker 存储占用
docker system df

本次异常:

Containers 169GB
Images     508GB

说明:

  • 容器可写层异常膨胀

2. 查看容器写层大小(关键)

# 查看各容器 writable layer 大小
docker ps -s --format "table {{.Names}}\t{{.Size}}"

本次关键异常:

loki 168GB (virtual 168GB)

五、根因分析

正常情况下:

Loki writable layer 应只有几十MB

因为:

  • WAL
  • chunks
  • tsdb index

应该写入:

Docker Volume / 宿主机目录

但本次:

loki = 168GB

说明:

Loki 数据写进了 overlay2 容器层

导致:

Loki 大量写盘
    ↓
overlay2 IO 爆炸
    ↓
dockerd 卡顿
    ↓
healthcheck 超时
    ↓
docker kill -9
    ↓
ExitCode 137
    ↓
无限重启

六、根因细节


错误挂载方式

启动命令:

docker run --name=loki \
    --user=10001 \
    --volume /srv/loki/loki-config.yaml:/mnt/config/loki-config.yaml \
    --volume /srv/loki/data:/tmp/loki \
    ...

问题在于:

Loki 配置文件中的:

common:
  path_prefix: /loki

而 docker volume:

/tmp/loki

路径不一致。

导致:

  • 一部分数据写 volume
  • 一部分数据写 overlay2

最终:

overlay2 = 168GB

七、修复方案


1. 停止 Loki

# 停止异常 Loki 容器
docker stop loki

作用:

  • 防止继续刷爆 IO

2. 备份配置

# 备份 Loki 配置
cp /srv/loki/loki-config.yaml /root/loki-config.yaml.bak

3. 修正 Loki 配置路径

确保:

common:
  path_prefix: /tmp/loki

storage_config:
  filesystem:
    directory: /tmp/loki/chunks

compactor:
  working_directory: /tmp/loki/compactor

ingester:
  wal:
    dir: /tmp/loki/wal

核心原则:

配置路径必须与 Docker Volume 挂载路径一致

4. 修正宿主机目录权限

因为:

--user=10001

所以:

# 修改宿主机目录权限
chown -R 10001:10001 /srv/loki/data

作用:

  • 防止 Loki 因权限问题 fallback 到临时目录

5. 删除旧容器(释放 overlay2)

# 删除旧容器
docker rm loki

注意:

仅 stop 不会释放 overlay2 空间
rm 后才会释放

6. 正确重新创建 Loki

# 正确启动 Loki
docker run --name=loki \
    --user=10001 \
    --volume /srv/loki/loki-config.yaml:/mnt/config/loki-config.yaml \
    --volume /srv/loki/data:/tmp/loki \
    --restart=always \
    --network ilad-network \
    -p 3100:3100 \
    -d \
    grafana/loki:3.4.1 \
    -config.file=/mnt/config/loki-config.yaml

八、验证修复结果


1. 查看容器 writable layer

# 查看 Loki writable layer
docker ps -s |grep loki

正常应为:

几十MB

异常:

几十GB / 上百GB

2. 查看宿主机数据目录

# 查看 Loki 数据目录
du -sh /srv/loki/data/*

正常应看到:

wal
chunks
compactor
index

说明:

  • 数据已真正写入宿主机 volume

3. 查看磁盘 IO 是否恢复

# 查看磁盘 IO
iostat -x 1

重点:

%util 降低
await 恢复正常

九、生产环境最佳实践


1. Loki 必须使用持久化 Volume

推荐:

-v /srv/loki/data:/tmp/loki

禁止:

直接写容器层

2. 配置路径必须与 Volume 一致

例如:

Docker MountLoki 配置
/tmp/lokipath_prefix=/tmp/loki

必须完全一致。


3. 必须限制 Docker 日志大小

编辑:

# Docker 日志配置
vim /etc/docker/daemon.json

加入:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

重启 Docker:

# 重启 Docker
systemctl restart docker

作用:

  • 防止 json.log 无限增长

4. 定期清理无用镜像

查看:

# 查看 Docker 空间
docker system df

清理:

# 清理无用镜像
docker image prune -a

十、快速排障命令清单

# 查看 Loki 状态
docker ps -a |grep loki

# 查看 Loki 日志
docker logs --tail 200 loki

# 查看是否 OOM
docker inspect loki |grep -i oom -A 20

# 查看容器写层大小
docker ps -s --format "table {{.Names}}\t{{.Size}}"

# 查看 Docker 总空间
docker system df

# 查看 IO
iostat -x 1

# 查看实时 IO 进程
iotop -oPa

# 查看 overlay2 大小
du -sh /var/lib/docker/overlay2

# 查看 Loki volume 数据
du -sh /srv/loki/data/*

# 查看 Docker 日志文件
find /var/lib/docker/containers/ -name "*-json.log" -exec du -h {} + |sort -hr |head

更多推荐