Podman Stats 错误问题完整解决方案

一、问题描述

错误信息

Error: unable to obtain cgroup stats: strconv.ParseUint: parsing "7038456085": value out of range

错误原因

  1. cgroup v2 数值溢出:cgroup v2 返回的数值超出了 uint64 类型范围
  2. 版本兼容性问题:Podman 3.0.1 对 cgroup v2 的支持不完善
  3. ARM 架构特定问题:在 ARMv7 架构上更为常见
  4. 内核版本较旧:5.4.65 内核与新版 cgroup v2 的兼容性问题

环境信息

系统:Armbian (定制系统)
架构:armv7l (ARM 32位)
内核:5.4.65-sunxi
Podman:3.0.1
Cgroup:cgroup v2

二、Cgroup 基础知识

什么是 Cgroup

Cgroup (Control Groups) 是 Linux 内核的核心功能,用于限制、记录和隔离进程组使用的资源

主要功能

功能说明
资源限制限制 CPU、内存、磁盘 I/O、网络带宽等
资源统计监控和记录资源使用情况
优先级控制设置资源分配优先级
进程隔离容器之间、服务之间的资源隔离

Cgroup v1 vs Cgroup v2

特性Cgroup v1Cgroup v2
树结构多个独立树(cpu、memory 分开)统一单树结构
管理复杂度较复杂更简单统一
资源控制分散控制统一控制
Podman 支持成熟稳定3.0+ 开始支持(早期版本有 bug)

查看 Cgroup 信息

# 查看 cgroup 版本
mount | grep cgroup

# 查看 cgroup 文件系统
ls -la /sys/fs/cgroup/

# 查看容器 cgroup 路径
find /sys/fs/cgroup -name "*container*" -type d

三、解决方案汇总

方案一:配置 Podman 使用 Cgroupfs(推荐)

原理:绕过 systemd cgroup 管理器,直接使用 cgroupfs

# 1. 创建配置文件
mkdir -p /etc/containers

cat > /etc/containers/containers.conf << 'EOF'
[engine]
cgroup_manager = "cgroupfs"

[containers]
cgroupns = "host"
EOF

# 2. 设置环境变量
export CONTAINERS_CGROUP_MANAGER=cgroupfs
echo 'export CONTAINERS_CGROUP_MANAGER=cgroupfs' >> /root/.bashrc

# 3. 重启服务
systemctl restart podman

# 4. 测试
podman stats --no-stream

方案二:降级到 Cgroup v1

原理:系统级切换到 cgroup v1,获得更好的兼容性

# 1. 编辑启动参数(Armbian)
echo "extraargs=systemd.unified_cgroup_hierarchy=0" >> /boot/armbianEnv.txt

# 2. 或者修改 extlinux 配置
vi /boot/extlinux/extlinux.conf
# 在 APPEND 行添加: systemd.unified_cgroup_hierarchy=0

# 3. 重启
reboot

# 4. 验证
mount | grep cgroup
# 应该显示多个 cgroup 挂载点

方案三:升级 Podman 版本

方法 A:使用 APT 源

# 添加官方源
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/ /" > /etc/apt/sources.list.d/podman.list

# 添加 GPG 密钥
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/Release.key | apt-key add -

# 更新并安装
apt update
apt install podman

方法 B:使用国内镜像(解决网络问题)

# 清华镜像
deb https://mirrors.tuna.tsinghua.edu.cn/opensuse/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/ /

# 阿里云镜像
deb https://mirrors.aliyun.com/opensuse/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/ /

方法 C:静态编译版本(最可靠)

# 下载
cd /tmp
wget https://github.com/containers/podman/releases/download/v4.9.0/podman-remote-static-linux_arm.tar.gz

# 安装
tar -xzf podman-remote-static-linux_arm.tar.gz
mv /usr/bin/podman /usr/bin/podman.backup
cp podman-remote-static-linux_arm/podman-remote-static-linux_arm /usr/bin/podman
chmod 755 /usr/bin/podman

# 验证
podman version

方案四:替代脚本方案

原理:直接从 cgroup 文件系统读取数据,绕过 Podman stats 的解析问题

#!/bin/bash
# 保存为 /usr/local/bin/podman-stats-fix

cat > /usr/local/bin/podman-stats-fix << 'EOF'
#!/bin/bash

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo -e "${GREEN}=== Container Stats Viewer ===${NC}"
printf "%-12s %-20s %-8s %-15s %-10s\n" "CONTAINER" "NAME" "CPU%" "MEM USAGE" "MEM%"
echo "--------------------------------------------------------------------------"

for container in $(podman ps -q); do
    name=$(podman inspect $container --format '{{.Name}}' 2>/dev/null | sed 's/^\///')
    
    # 查找 cgroup 路径
    cgpath=$(find /sys/fs/cgroup -name "*$container*" -type d 2>/dev/null | head -1)
    
    if [ -n "$cgpath" ]; then
        # 读取 CPU 使用率
        if [ -f "$cgpath/cpu.stat" ]; then
            cpu_usec=$(grep "usage_usec" $cgpath/cpu.stat 2>/dev/null | awk '{print $2}' | head -1)
            cpu_percent=$((cpu_usec / 1000000 / 10))
            [ $cpu_percent -gt 100 ] && cpu_percent=100
        else
            cpu_percent="N/A"
        fi
        
        # 读取内存使用
        if [ -f "$cgpath/memory.current" ]; then
            mem_bytes=$(cat $cgpath/memory.current 2>/dev/null)
            mem_mb=$((mem_bytes / 1024 / 1024))
        elif [ -f "$cgpath/memory.usage_in_bytes" ]; then
            mem_bytes=$(cat $cgpath/memory.usage_in_bytes 2>/dev/null)
            mem_mb=$((mem_bytes / 1024 / 1024))
        else
            mem_mb="N/A"
        fi
        
        # 读取内存限制
        if [ -f "$cgpath/memory.max" ]; then
            mem_limit=$(cat $cgpath/memory.max 2>/dev/null)
            if [ "$mem_limit" = "max" ]; then
                mem_limit_mb="unlimited"
                mem_percent="N/A"
            else
                mem_limit_mb=$((mem_limit / 1024 / 1024))
                mem_percent=$((mem_bytes * 100 / mem_limit))
            fi
        else
            mem_limit_mb="?"
            mem_percent="?"
        fi
        
        printf "%-12s %-20s %-8s %-15s %-10s\n" \
            "${container:0:12}" \
            "${name:0:20}" \
            "${cpu_percent}%" \
            "${mem_mb}MiB/${mem_limit_mb}" \
            "${mem_percent}%"
    else
        printf "%-12s %-20s %-8s %-15s %-10s\n" \
            "${container:0:12}" "${name:0:20}" "N/A" "N/A" "N/A"
    fi
done
EOF

chmod +x /usr/local/bin/podman-stats-fix

# 创建别名
echo "alias stats='/usr/local/bin/podman-stats-fix'" >> /root/.bashrc
source /root/.bashrc

# 使用
podman-stats-fix

方案五:使用系统命令替代

# 使用 podman top 查看进程
podman top <container_id> -eo pid,comm,pcpu,pmem

# 使用系统命令
ps aux | grep conmon
top -b -n 1 | grep container

# 查看容器详细信息
podman inspect <container_id> | jq '.[].State'

# 直接查看 cgroup 文件
cat /sys/fs/cgroup/system.slice/container-*/cpu.stat
cat /sys/fs/cgroup/system.slice/container-*/memory.current

四、网络问题解决方案

APT 下载超时问题

E: Failed to fetch ... Connection timed out

解决方法

  1. 更换国内镜像源
  2. 配置 APT 代理
  3. 手动下载 deb 包
  4. 使用静态编译版本

手动下载 DEB 包

# 在其他机器下载
mkdir podman-debs && cd podman-debs
wget https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/armhf/podman_3.4.2-4_armhf.deb
wget https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/armhf/conmon_2.0.25-2_armhf.deb
wget https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/armhf/runc_1.1.4-2_armhf.deb

# 打包传输
tar -czf podman-update.tar.gz *.deb
scp podman-update.tar.gz root@target:/tmp/

# 在目标机器安装
cd /tmp
tar -xzf podman-update.tar.gz
dpkg -i *.deb
apt --fix-broken install -y

五、诊断工具

完整诊断脚本

#!/bin/bash
# 保存为 diagnose-podman.sh

echo "=== Podman Stats 诊断报告 ==="
echo ""

echo "1. 系统信息"
echo "-------------------"
uname -a
echo ""

echo "2. Podman 版本"
echo "-------------------"
podman version 2>&1 | head -5
echo ""

echo "3. Cgroup 信息"
echo "-------------------"
mount | grep cgroup
echo ""

echo "4. Podman 配置"
echo "-------------------"
cat /etc/containers/containers.conf 2>/dev/null || echo "配置文件不存在"
echo ""

echo "5. 环境变量"
echo "-------------------"
env | grep -i container
echo ""

echo "6. 运行中的容器"
echo "-------------------"
podman ps -a
echo ""

echo "7. Cgroup 路径"
echo "-------------------"
find /sys/fs/cgroup -name "*container*" -type d 2>/dev/null | head -10
echo ""

echo "8. 测试 stats 命令"
echo "-------------------"
timeout 2 podman stats --no-stream 2>&1 || echo "命令执行失败"
echo ""

echo "9. 系统日志"
echo "-------------------"
journalctl -u podman --no-pager | tail -20
echo ""

echo "=== 诊断完成 ==="

六、最佳实践建议

推荐操作顺序

  1. 首选:方案一(配置 cgroupfs)- 最简单,无风险
  2. 备选:方案四(替代脚本)- 绕开问题
  3. ⚠️ 谨慎:方案二(降级 cgroup v1)- 需要重启
  4. ⚠️ 谨慎:方案三(升级 Podman)- 可能影响现有容器

环境特定建议

ARMv7 + Podman 3.0.1

  • 优先使用:方案一 + 方案四组合
  • 避免:升级到 4.x 版本(可能不兼容)
  • 长期:考虑迁移到 Docker

生产环境

  • 先在测试环境验证
  • 备份重要容器配置
  • 保留旧内核作为回退选项

监控替代方案

# 使用 Docker 兼容命令
podman stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# 使用 Prometheus 监控
# 部署 node_exporter + cadvisor

七、常见问题 FAQ

Q1: 为什么会出现数值溢出?

A: cgroup v2 返回的数值(如 7038456085)超出了 32 位系统的处理范围,Podman 3.0.1 的解析代码存在缺陷。

Q2: 升级内核能解决问题吗?

A: 能部分解决,但主要问题在 Podman 版本。升级到 6.1+ 内核配合 Podman 4.x 效果最好。

Q3: 配置 cgroupfs 有风险吗?

A: 没有风险,只是改变资源管理方式,不影响容器运行。

Q4: 替代脚本的 CPU 百分比准确吗?

A: 是简化计算,仅供参考。精确监控建议使用 Prometheus 等专业工具。

Q5: 如何永久生效配置?

A: 配置文件 /etc/containers/containers.conf 和环境变量 /root/.bashrc 都会永久生效。


八、总结

核心要点

  1. 根本原因:Podman 3.0.1 + cgroup v2 + ARM 架构的兼容性问题
  2. 最快解决:配置 cgroupfs 或使用替代脚本
  3. 根本解决:升级 Podman 到 4.x 或使用 Docker
  4. 临时方案:替代脚本绕过 stats 解析问题

关键命令速查

# 配置 cgroupfs
mkdir -p /etc/containers
echo '[engine]
cgroup_manager = "cgroupfs"' > /etc/containers/containers.conf

# 测试
podman stats --no-stream

# 重启服务
systemctl restart podman

# 查看配置
cat /etc/containers/containers.conf

参考资料

标签: none

添加新评论