Podman 容器网络 IP 分配冲突问题排查与解决笔记

一、问题现象

1. 手动启动容器报错

执行 podman start clash adguardhome 时出现以下错误:

ERRO[0000] Error adding network: failed to allocate for range 0: 172.16.16.8 has been allocated to bd03adf84621... duplicate allocation is not allowed
ERRO[0000] Error while adding pod to CNI network "podman": failed to allocate for range 0: 172.16.16.8 has been allocated to ...

2. 定时任务(Cron)重启容器时同样出现 IP 分配冲突

  • 计划任务执行 podman restart clash adguardhome
  • 容器重启后网络短暂断开,但服务实际可用
  • Cron 输出被丢弃(No MTA installed, discarding output

3. 后续启动时冲突 IP 变化

  • 172.16.16.8 变为 10.88.2.6 / 10.88.2.7
  • 错误信息显示:容器自己占用了自己的 IP(自冲突)

二、环境信息

项目信息
Podman 版本3.0.1
API 版本3.0.0
架构ARM(linux/arm)
运行时配置runc(已从默认的 crun 切换)
容器镜像dreamacro/clash:devadguard/adguardhome:edge

三、问题根本原因

1. Podman 3.0.1 在 ARM 上的已知 Bug

  • CNI 网络 IP 分配记录存在竞态条件
  • 容器停止后,IP 分配文件(如 /var/lib/cni/networks/podman/10.88.2.6)未被正确删除
  • 重启时 CNI 读取残留文件,发现 IP 已被“占用”
  • 即使占用者是自己,也拒绝分配 → 死锁

2. 网络命名空间残留

  • /var/run/netns/cni-* 文件中积累了大量未被清理的网络命名空间
  • 执行 rm -rf /var/run/netns/cni-* 时出现 Device or resource busy
  • 说明有进程仍在使用这些命名空间

3. 其他潜在因素

  • 之前使用 systemctl restart podman 可能导致残留
  • 容器频繁重启但清理机制不完善
  • Cron 环境变量缺失(PATH 等)可能导致命令找不到

四、解决方案

✅ 方案一:使用 Host 网络模式(推荐,最简单)

# 删除旧容器
podman rm -f clash adguardhome

# 使用 host 网络重新创建
podman run -d \
  --name clash \
  --network host \
  --restart unless-stopped \
  docker.io/dreamacro/clash:dev

podman run -d \
  --name adguardhome \
  --network host \
  --restart unless-stopped \
  docker.io/adguard/adguardhome:edge

优点:完全绕过 CNI 网络,无 IP 分配问题,网络性能最好
缺点:容器与宿主机共享网络栈,端口不能冲突


✅ 方案二:清理 CNI 残留并重建桥接网络

# 1. 停止并删除容器
podman stop clash adguardhome
podman rm clash adguardhome

# 2. 清理 CNI 分配记录
sudo rm -rf /var/lib/cni/networks/podman/*

# 3. 清理网络命名空间(如遇 busy,需重启系统)
sudo rm -rf /var/run/netns/cni-*   # 可能报 busy
sudo umount /var/run/netns/cni-* 2>/dev/null
sudo ip netns del <namespace>      # 逐个删除

# 4. 创建新网络(不同子网)
podman network create --subnet 10.89.0.0/24 clash-net

# 5. 重建容器
podman run -d \
  --name clash \
  --network clash-net \
  --ip 10.89.0.10 \
  docker.io/dreamacro/clash:dev

✅ 方案三:彻底清理(终极方案)

# 1. 删除所有容器
podman rm -f $(podman ps -aq)

# 2. 停止 Podman 服务
systemctl --user stop podman.socket podman.service
sudo systemctl stop podman.socket podman.service

# 3. 清理所有 CNI 和网络命名空间
sudo rm -rf /var/lib/cni/networks/*
sudo rm -rf /var/run/netns/cni-*
sudo rm -rf /etc/cni/net.d/podman*

# 4. 重启系统(最彻底)
sudo reboot

五、关于 kill -HUP 1 的澄清

问题答案
是否所有容器都支持?❌ 不是,只有支持 SIGHUP 热重载的程序(如 Nginx)才有效
Clash 是否支持?❌ 不支持,会忽略信号或无反应
AdGuardHome 是否支持?❌ 不支持
对不支持的程序怎么办?使用 podman restart 或通过应用自身 API 重载

六、定时重启的正确配置

方式一:Cron(简单)

# 编辑 crontab
crontab -e

# 添加定时任务(每天凌晨 4:00 重启)
0 4 * * * /usr/bin/podman restart clash adguardhome >> /var/log/podman-restart.log 2>&1

方式二:Systemd Timer(推荐生产环境)

# 生成 service 文件
podman generate systemd --name --new --files --restart-policy=always clash

# 移动到用户目录
mv container-clash.service ~/.config/systemd/user/

# 启用服务
systemctl --user daemon-reload
systemctl --user enable container-clash.service

# 创建 timer 文件
cat > ~/.config/systemd/user/restart-clash.timer << EOF
[Unit]
Description=Timer to restart Clash daily

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true

[Install]
WantedBy=timers.target
EOF

# 启用 timer
systemctl --user enable restart-clash.timer
systemctl --user start restart-clash.timer

七、containers.conf 优化配置

文件位置:/etc/containers/containers.conf

[engine]
# 使用更稳定的 runc(代替 crun)
runtime = "runc"
cgroup_manager = "cgroupfs"

[containers]
# 共享宿主机 cgroup 命名空间,简化资源管理
cgroupns = "host"

作用

  • runc:解决老版本 Podman(3.0.1)在 ARM 上的网络资源残留问题
  • cgroupns = "host":降低容器因资源限制被异常关闭的风险

八、常见问题速查

问题解决方法
duplicate allocation清理 /var/lib/cni/networks/podman/* 或改用 host 网络
Device or resource busy重启系统,或 umountip netns del
Cron 任务不执行检查 PATH:which podman,使用绝对路径
Cron 输出丢失重定向到文件:>> /var/log/xxx.log 2>&1
容器重启后网络闪断正常现象,restart 会重建网络;如需平滑重载,使用应用 API

九、操作记录摘要

时间操作结果
首次podman start clash❌ IP 172.16.16.8 冲突
配置containers.conf 添加 runtime = "runc"部分改善
清理rm -f /var/lib/cni/networks/podman/*临时解决
重启系统 reboot✅ 彻底清理网络命名空间
最终改用 --network host✅ 完全规避问题

十、建议与总结

  1. 短期方案:使用 --network host 模式,彻底绕过 CNI 网络问题
  2. 中期方案:保持 runc + cgroupns = "host" 配置
  3. 长期方案:升级 Podman 到 4.x 或更高版本(ARM 支持更完善)
  4. 监控:定期检查 /var/run/netns/cni-* 数量,避免残留堆积
  5. 日志:为定时任务配置日志输出,便于排查问题

标签: none

添加新评论