先确认是否真为IP耗尽:查云平台子网“可用IP数”是否接近0,或用CLI命令验证;再检查K8s节点PodCIDR分配及CNI日志中是否有“exhaust”“no available”等提示,避免误判后盲目扩容。
确认是否真为IP耗尽
不要一看到“Failed to allocate IP”就直接扩容。先验证是不是真的没IP了。
查子网剩余地址:在云平台控制台找到对应子网,看“可用IP数”是否接近0;或用CLI命令,如AWS:aws ec2 describe-subnets --subnet-ids subnet-xxx --query 'Subnets[0].AvailableIpAddressCount';阿里云:aliyun vpc DescribeSubnetAttribute --SubnetId subnet-xxx --RegionId cn-shanghai --query AvailableIpAddressCount。
查容器网络插件状态:如果是K8s集群,运行kubectl get nodes -o wide看各节点分配的PodCIDR;再执行kubectl logs -l k8s-app=calico-node -n kube-system -c calico-node | grep -i "exhaust|no available",确认CNI日志里是否有明确的地址池枯竭提示。
快速缓解:释放僵尸IP与回收闲置资源
很多“IP不足”其实是假性耗尽——有IP被分配但未真正使用,或Pod已删而IP未归还。
- 清理终止态Pod:运行kubectl get pods --all-namespaces --field-selector status.phase!=Running -o wide,删除所有Succeeded/Failed/Pending状态且长期无更新的Pod
- 重启CNI组件:对Calico可删掉calico-node Pod(DaemonSet会自动重建),强制刷新节点本地IPAM缓存;Flannel则需重启flanneld服务并检查/run/flannel/subnet.env是否仍指向旧网段
- 检查宿主机ARP表和邻居缓存:执行ip neigh show nud failed或arp -a | grep incomplete,清除大量失效条目,避免IP被错误标记为占用
中长期扩容:调整子网与地址池配置
临时救火之后,必须结构性扩容,否则一周内大概率复现。
- 子网CIDR升级:若当前是/24(256个IP),至少扩到/22(1024个);注意云平台通常不支持直接修改已有子网CIDR,需新建子网+迁移节点,建议用Terraform做灰度切换
- 重设CNI地址池:以Flannel为例,编辑ConfigMapkube-flannel-cfg,将Network字段从10.244.0.0/16改为10.244.0.0/14,再滚动重启flannel DaemonSet
- 启用IPv6双栈:Docker和主流CNI(Calico/Cilium)均已支持。只需在daemon.json中添加{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"},重启Docker;K8s则开启IPv6DualStack特性门,并配置podSubnet含IPv6段
预防机制:建立IP使用监控与预警
靠人工盯日志太被动。把IP余量变成可观测指标,才能提前干预。
在Prometheus中采集以下数据源:
- 子网可用IP数(通过云厂商Exporter或自定义脚本调OpenAPI)
- CNI插件暴露的felix_ipam_pool_usage(Calico)、flannel_network_usage(Flannel)等指标
- K8s节点上node_network_ipv4_cidr_addresses与实际分配Pod数的比值
设置告警规则:当任意子网或节点IP使用率 > 85% 持续5分钟,立即触发企业微信/钉钉通知;> 95% 时自动暂停新Deployment创建(可通过Admission Webhook拦截)。