Cilium 环境下端口分配失败(EADDRINUSE)问题定位笔记
📌 背景概述
业务程序(例如某 CLI 工具,sqlcmd)在执行 TCP 连接时失败,通过 strace 观察发现:
export LD_LIBRARY_PATH=/app
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16)
= -1 EADDRINUSE (Address already in use)
同时,使用 Python 简单脚本模拟端口动态分配,也出现:
socket.error: [Errno 98] Address already in use
说明 系统无法分配 ephemeral port(临时端口)。
此问题在运行 Cilium 的 Kubernetes 节点上出现,怀疑可能与 eBPF NAT / sockmap 相关。
1. 关键现象汇总
✔ 1.1 动态分配端口失败
无论程序还是 Python,都无法通过下列方式分配随机端口:
s.bind(('0.0.0.0', 0))
报错均为:
EADDRINUSE (Address already in use)
说明 操作系统认为所有可用源端口都已被占用。
✔ 1.2 IPv6 bind 也失败
即使换成 IPv6:
s = socket.socket(AF_INET6)
s.bind(('::', 0))
仍然返回:
Address already in use
说明问题与 IPv4/IPv6 无关,并非单协议栈问题。
✔ 1.3 Cilium BPF Maps 缺失
尝试查看 Cilium 的 sockops map:
bpftool map dump pinned /sys/fs/bpf/tc/globals/cilium_sock_ops_v4
结果:
No such file or directory
说明当前节点未加载此 bpf map —— 可能是 Cilium 配置或版本差异导致。
✔ 1.4 Cilium BPF 文件系统正常挂载
mount | grep bpf
输出正常:
/sys/fs/bpf on /sys/fs/bpf type bpf (rw,relatime)
且 Cilium 也能探测到:
cilium bpf fs show
2. 潜在原因分析
🔎 2.1 系统 ephemeral port 耗尽
当所有可分配端口被占用后,就会出现:
bind(..., port=0) → EADDRINUSE
可能原因包括:
- 大量 TIME_WAIT 端口未回收
- 程序长时间占用大量短连接
- Cilium NAT eBPF 重写导致端口池异常
端口范围可检查:
cat /proc/sys/net/ipv4/ip_local_port_range
🔎 2.2 Cilium NAT / CT 表异常
Cilium 依赖 eBPF 的 conntrack(CT)和 NAT 映射维护端口分配。
一旦此表膨胀或泄漏,可能导致端口被“认为已占用”。
可查询 NAT 状态:
cilium bpf nat list
cilium bpf ct list global
若 NAT/CT 表巨大或不断增长,则可能存在 Cilium NAT 泄漏。
🔎 2.3 sockmap 未加载(非根因,但说明版本差异)
节点上不存在:
/sys/fs/bpf/tc/globals/cilium_sock_ops_v4
说明:
- 该节点上 Cilium 未启用 socket-level eBPF(sockops)
- 不影响 NAT,但说明 Cilium 功能集不完整
- 原因可能是版本差异(节点间版本 1.10.x vs 1.12.x)
3. 定位思路与验证
✔ 3.1 Python 端口扫描验证
Python 测试脚本在 Pod 内执行:
import socket
for i in range(10):
s = socket.socket(socket.AF_INET)
try:
s.bind(('0.0.0.0', 0))
print("Port OK:", s.getsockname()[1])
except:
print("Port FAILED")
finally:
s.close()
结果:
可用端口数量: 0
占用端口: 全部
确认 操作系统认为所有端口都已经被占用。
✔ 3.2 Cilium NAT / CT Failure 判断依据
若以下命令输出为空,则 Cilium NAT 功能没有正常生效:
bpftool map dump pinned /sys/fs/bpf/tc/globals/cilium_snat_v4_external
或
bpftool map dump pinned /sys/fs/bpf/tc/globals/cilium_sock_v4_*
如果全都不存在,则 Cilium 使用的 BPF 程序可能受版本冲突影响 未加载。
4. 结论
从当前症状判断:
✔ 问题根因:节点上可用的 ephemeral ports 被耗尽
来源可能是:
- Cilium NAT/CT 表泄漏(常见)
- Docker 或大量 TIME_WAIT 连接造成端口不释放
- 某进程持续建立 TCP outbound,端口不回收
✔ Cilium BPF map 缺失属于信号,但非直接根因
5. 建议的修复方案
方案 A:重启 Cilium(清理 NAT/CT 表)
systemctl restart cilium
或:
kubectl rollout restart ds cilium -n kube-system
方案 B:清理 netfilter conntrack
conntrack -F
方案 C:扩展主机可分配端口范围
echo "1024 65000" > /proc/sys/net/ipv4/ip_local_port_range
方案 D:排查 TIME_WAIT 是否过多
ss -ant | grep TIME_WAIT | wc -l
6. 后续建议
为避免再次发生建议:
✔ 监控 Cilium NAT / CT 表大小
cilium bpf nat list | wc -l
cilium bpf ct list global | wc -l
✔ 确认节点上 Cilium 版本一致
混合版本(如 1.10 + 1.12)会导致 BPF 程序加载不一致。
1549

被折叠的 条评论
为什么被折叠?



