ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux单网卡绑定多个IP:配置详解与路由排障指南

Linux单网卡绑定多个IP:配置详解与路由排障指南 前一阵有个刚转运维的同事问我服务器只剩一个空闲网口了但机房分配了3个公网IP业务方说要分别部署在不同IP上是不是得再买块网卡我说这个问题问得挺典型——在Linux下一张物理网卡绑定多个IP地址不是魔法反而是运维老鸟最常用的一项基本功。今天就把这个话题一次性讲透从临时绑定的ip命令到CentOS、Ubuntu下永久生效的各种配置姿势再到绑定之后最容易踩的路由、ARP、反向路径过滤这几个大坑最后用一个真实故障案例把排查思路完整走一遍。内容适合刚入门做运维和网络调试的读者也适合想彻底搞懂多IP机制的老手快速查漏补缺。1. 为什么好好的一个网卡非要绑一堆IP1.1 最常见的几个真实场景先说说业务场景不然单纯讲命令就是空中楼阁。我这些年遇到单网卡多IP的需求绝大多数是下面这几种情况。服务器只有一块物理网卡但机房分配了多个IP。比如一台双路服务器管理口和业务口各占用一个剩下的业务网口就一个结果IDC分配了两个公网IP。这时候再加一块PCIe网卡当然可以但有些服务器没有空闲插槽或者加卡要重启、要走工单流程显然不如直接绑IP方便。同一台机器上要跑多个HTTPS站点且每个站点要求独立IP。有的第三方接口、银行回调、苹果推送这类服务会要求固定来源IP一张网卡只绑一个IP的话就没办法同时对接多个这类服务。把多个IP绑到一张卡上配合Nginx或Apache监听不同IP的80/443端口是最省事的做法。测试环境模拟多台主机。我以前搭网络实验环境需要验证交换机策略、防火墙规则或者做集群通信测试但手头只有一两台物理机。那就给每台机器的网卡绑上10.0.0.1、10.0.0.2、10.0.0.3这种连续IP一台机器就能冒充三五个节点调试起来非常方便。还有一类场景是高可用VIP。Keepalived的VRRP实例起来之后会在网卡上生成一个虚拟IP本质上也是绑定额外IP的一种形式。虽然那套机制是单独设计的但底层原理和手动绑定是相通的理解了多IP绑定看Keepalived的IP漂移日志会轻松很多。1.2 绑定前必须想清楚的三件事动手之前先想清楚IP掩码。同一个网卡上绑的多个IP是同一个网段还是跨网段配置思路完全不同。如果几个IP都在同一个网段比如192.168.1.10、192.168.1.11绑在eth0上那默认路由通常只有一条网关也只有一个配置很省事。麻烦的是跨网段场景比如一张网卡同时绑了192.168.1.10/24和10.0.0.10/24这时候默认路由只能选其中一个网关另一个网段的包出去之后回程怎么走就得靠策略路由来处理否则大概率不通。这个我在后面的第4章专门讲。还要想清楚IP用途。是临时调试用还是长期业务要跑临时用的话一条ip addr add就够重启机器就没了长期用必须写进系统配置文件否则哪天重启网卡业务直接断开非常尴尬。最后是网卡命名和网络管理方式。现在的Linux发行版普遍使用enp0s3、ens33这种可预测命名而且CentOS 8之后NetworkManager成了默认网络管理工具Ubuntu 18.04之后默认是netplan。不同体系的配置方式差异挺大第3章我会按体系分别给方案。1.3 一个容易忽视的原理primary地址和secondary地址用ip命令在同一张网卡上添加多个IP时内核只把其中一个当作primary地址其余的都标成secondary。你可以通过ip addr show验证secondary地址旁边会有secondary字样。primary地址负责决定该接口的默认源地址行为很多出方向的连接默认会优先选用它作为源IP。secondary地址通常不会生成独立的广播地址也不会影响主地址的链路状态。如果primary地址因为DHCP续租或者手动删除而消失内核会从secondary里再选一个新的补上。这个特性最容易被忽略的地方是跨网段访问时源地址选错了对面的ACL策略就有可能把请求拒掉。比如你明明绑了10.0.0.10这个IP但往外访问时系统默认用了192.168.1.10作为源IP对方一看来源不对直接拒绝。解决办法就是配置策略路由或者在发起连接时显式指定源地址。2. 临时绑IPip addr add 与 ifconfig 哪个更靠谱2.1 ip addr add的正确用法临时添加一个IP我最推荐的就是ip命令语法清晰没有历史包袱。假设网卡叫eth0要添加192.168.1.10/24ip addr add 192.168.1.10/24 dev eth0想同时绑第二个、第三个继续执行同样的命令就行不需要额外的子接口名ip addr add 192.168.1.11/24 dev eth0 ip addr add 192.168.1.12/24 dev eth0查看绑定结果ip addr show dev eth0输出里能看到多个inet条目分别对应192.168.1.10/24、192.168.1.11/24、192.168.1.12/24。删除的话使用del子命令ip addr del 192.168.1.11/24 dev eth0这里有几个细节务必注意。一是IP后面的掩码一定要写对写成/16或/24会导致路由计算完全不同很容易出现IP绑上了但网络不通的怪现象。二是在某些老旧内核或特殊环境里可能需要显式指定广播地址ip addr add 192.168.1.10/24 brd dev eth0brd后面的加号表示让内核根据掩码自动计算广播地址一般不需要写死。三是不要在一条命令里同时写多个IP比如ip addr add 192.168.1.10/24 192.168.1.11/24 dev eth0这种写法是不合法的内核不接受。一次一个地址重复执行就行。2.2 ifconfig的旧式写法为什么还能用但别长期依赖早年用ifconfig做多IP绑定标准操作是建立虚拟子接口比如eth0:0、eth0:1ifconfig eth0:0 192.168.1.10 netmask 255.255.255.0 up ifconfig eth0:1 192.168.1.11 netmask 255.255.255.0 up这种方式现在依然可以用尤其是在一些老系统或应急环境下但我不建议新项目再依赖它。最直接的原因是ifconfig命令在CentOS 8、Ubuntu 20.04及之后版本里不再默认安装需要额外安装net-tools包。而且虚拟子接口本质上是内核里的另一个逻辑接口很多新版NetworkManager和systemd-networkd对这类alias接口的兼容性和路由行为处理得并不好容易出现配置了但网卡重启后interface没了这种局面。现在的主流做法是统一使用ip addr它添加的多个地址都归属同一个物理接口语义清晰和NetworkManager等工具配合也更顺畅。ifconfig那套就当历史知识了解碰到老机器老脚本能看懂就行新环境就别再写了。2.3 绑定完成后如何快速验证绑完IP别急着走先做一轮快速验证很多时候问题都是这步发现并提前解决的。第一步先看IP是否真的生效ip addr show dev eth0 ip -4 addr show dev eth0第二步测试本机到网关的连通性并且强制指定源IPping -I 192.168.1.10 192.168.1.1 ping -I 192.168.1.11 192.168.1.1-I参数指定源地址能直接验证某个IP是否能正常发包和收包。如果不带-I系统默认会用primary地址去pingsecondary地址的问题就测不出来。第三步验证服务是否能监听在指定IP上比如用curl指定来源或目标curl --interface 192.168.1.11 http://example.com如果跑的是Nginx还可以检查监听情况ss -lntp | grep 192.168.1.11这一步能确认服务绑定的是不是目标IP而不是默认的0.0.0.0或127.0.0.1。3. 永久生效三大主流Linux体系的配置姿势3.1 CentOS/RHEL系ifcfg文件与NetworkManagerCentOS 6和CentOS 7时代最常见的做法是编辑网卡配置文件。第一种方式是在ifcfg-eth0里直接写多个地址# /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICEeth0 BOOTPROTOstatic ONBOOTyes IPADDR0192.168.1.10 PREFIX024 IPADDR1192.168.1.11 PREFIX124 GATEWAY0192.168.1.1 DNS1114.114.114.114改完重启网络服务systemctl restart networkCentOS 6则是service network restart。第二种方式是创建子接口配置文件# /etc/sysconfig/network-scripts/ifcfg-eth0:0 DEVICEeth0:0 BOOTPROTOstatic ONBOOTyes IPADDR192.168.1.11 PREFIX24这种方式相当于把第2章里ifconfig eth0:0的做法固化到配置文件里。CentOS 7上如果NetworkManager在管理这个连接建议直接用nmcli更稳妥。CentOS 8和CentOS 9之后我基本都是用nmcli来操作因为默认网络服务就是NetworkManager改ifcfg文件后还需要nmcli connection reload、nmcli connection up才能生效不如直接用nmcli来得干净。# 查看连接名一般是网卡名如ens160 nmcli connection show # 给连接追加一个IP nmcli connection modify ens160 ipv4.addresses 192.168.1.11/24 # 重新激活连接 nmcli connection up ens160再看一下有没有生效nmcli connection show ens160 | grep ipv4.addresses注意这里的加号很关键。如果忘了写加号ipv4.addresses会把原有IP列表全部覆盖成新IP那就把主IP干掉了连接直接断掉。我见过不止一次这种低级事故所以每次都要强调一下。3.2 Ubuntu/Debian系netplan与老式interfacesUbuntu 18.04及以后默认使用netplan管理网络配置。配置文件在/etc/netplan/下面通常是01-netcfg.yaml或00-installer-config.yaml。多IP配置写在addresses列表里# /etc/netplan/01-netcfg.yaml network: version: 2 ethernets: ens33: addresses: - 192.168.1.10/24 - 192.168.1.11/24 - 192.168.1.12/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [114.114.114.114]然后应用sudo netplan applynetplan会生成后端配置给systemd-networkd或NetworkManager使用。这里有两个坑一是YAML文件对缩进极其敏感地址列表少两个空格就会解析失败二是如果服务器上跑着老旧的/etc/network/interfaces配置netplan apply之后有可能被覆盖或冲突同一套网络配置不要同时出现在两个体系里。对于还没迁移到netplan的Ubuntu 16.04或者某些仍然使用ifupdown的Debian系统配置写在/etc/network/interfacesauto eth0 iface eth0 inet static address 192.168.1.10 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 114.114.114.114 auto eth0:0 iface eth0:0 inet static address 192.168.1.11 netmask 255.255.255.0重启网络sudo systemctl restart networking这种写法本质上是把ifconfig eth0:0的别名思想固化到配置文件里在旧系统上跑得很稳但新环境不推荐了。3.3 systemd-networkd轻量配置思路如果你的系统没有NetworkManager也没有netplan而是用systemd-networkd管理网络配置也简单。在/etc/systemd/network/下创建一个.network文件# /etc/systemd/network/20-wired.network [Match] Nameeth0 [Network] Address192.168.1.10/24 Address192.168.1.11/24 Address192.168.1.12/24 Gateway192.168.1.1 DNS114.114.114.114启动并设置开机自启systemctl enable --now systemd-networkd systemctl restart systemd-networkd这是我在一些精简安装的容器宿主机上比较喜欢的方式配置直白没有YAML缩进问题也没有ifcfg那套复杂变量。但要确保NetworkManager没有同时管理这个网卡否则两个服务抢接口结果不可预期。3.4 配置完成后必须做的生效自检无论用哪种方式配置完都不要直接交差。我建议至少过一遍下面的自检清单。确认IP地址生效ip addr show dev eth0看多个IP是否都在UP状态。确认默认路由正确ip route show看default路由是否指向预期网关。确认服务正常监听ss -lntp | grep 你绑的IP对应端口是否监听在目标IP上。确认重启之后还在有条件就reboot或者至少systemctl restart networking/network/systemd-networkd再执行ip addr检查。这一步能提前暴露配置文件没写对或两个管理工具互相打架的问题。确认外网访问没问题从另一台机器分别ping和curl各个IP。有一年我在客户现场处理一个问题配置网卡绑定IP后当时一切正常结果隔天服务器重启后网卡起不来检查半天发现是ifcfg-eth0里同时写了IPADDR和IPADDR0两种计数方式混用导致NetworkManager解析错乱。自检里加上重启验证这一条能避免很多返工。4. 绑完不通八成是路由、ARP和rp_filter的问题4.1 同一网卡多个网段IP的默认路由走向这是单网卡多IP场景里最深的坑。同一网卡上的多个IP如果属于不同网段默认路由怎么办内核的规则很简单默认路由通常只会有一个而且会优先分配给primary地址所在网段对应的网关。举个例子eth0上绑了192.168.1.10/24和10.0.0.10/24两个IP两个网段各有网关分别是192.168.1.1和10.0.0.1。系统启动后默认路由大概率长这样default via 192.168.1.1 dev eth0那么从10.0.0.10这个源IP发出的、发往公网的包会先查路由表匹配到默认路由后从192.168.1.1出去。对端回包时因为目标地址是10.0.0.10它可能会尝试路由回10.0.0.0/24网段结果发现回程路径不通。表现就是192.168.1.10能上网10.0.0.10死活不通。解决办法是给不同源IP配置独立路由表也就是策略路由。我在4.4小节给具体写法。4.2 ARP响应问题与sysctl参数ARP层面的坑相对隐蔽但在多网卡多IP、单网卡多网段的场景里非常致命。Linux内核在响应ARP请求时默认行为有些宽松。如果一张网卡绑了多个IP收到针对其中一个IP的ARP请求时内核可能直接用该网卡上任意一个IP对应的MAC去回复。听起来好像没问题问题在于如果这些IP分布在多个网段各自通过不同的三层网关访问网关设备在二层学习的ARP表项就可能串掉。举个实际例子。eth0绑了192.168.1.10/24和10.0.0.10/24上游是同一台交换机但属于不同VLAN。VLAN 10的网关发送ARP请求询问谁是192.168.1.10内核收到后可能用10.0.0.10对应的ARP表项去回复或者回复时机不对VLAN 10的网关学到的MAC和VLAN 20的网关学到的MAC不一致导致部分方向通信异常。针对这类场景Linux提供了两个关键参数net.ipv4.conf.all.arp_ignore 1 net.ipv4.conf.all.arp_announce 2arp_ignore 1只回答目标IP属于本接口地址的ARP请求避免用其他接口或别名IP乱响应。arp_announce 2发送ARP请求时总是使用最合适的本地地址避免源IP选择不当。修改方式可以临时执行sysctl -w永久生效则写入/etc/sysctl.conf或/etc/sysctl.d/99-arp.confecho net.ipv4.conf.all.arp_ignore 1 /etc/sysctl.d/99-arp.conf echo net.ipv4.conf.all.arp_announce 2 /etc/sysctl.d/99-arp.conf sysctl -p /etc/sysctl.d/99-arp.conf这两个参数在配置了多个VIP、多个公网IP或做LVS负载均衡时尤其重要很多IP时通时不通的问题就是这个参数没调好。4.3 rp_filter导致丢包的判断方法反向路径过滤Reverse Path Filtering是一个经常被忽略却影响巨大的内核特性。它的作用是检查入站数据包的源IP是否与路由表相符如果不相符直接丢弃。在单网卡多网段的场景里rp_filter可能带来这样的问题eth0绑了192.168.1.10/24和10.0.0.10/24某个业务数据包从10.0.0.10这个IP发出经过了10.0.0.1网关再从另一条链路绕回来后进入eth0时源IP是10.0.0.1但内核判断这个源IP不在任何接口的直连路由里因为10.0.0.0/24虽然是直连网段但当前主路由或rp_filter的strict模式判定不匹配于是一口咬定这是伪造IP直接丢包。检查当前rp_filter配置sysctl net.ipv4.conf.all.rp_filter sysctl net.ipv4.conf.eth0.rp_filter如果输出为1说明启用了严格模式。在有非对称路由需求的环境里可以把某个接口或全局的rp_filter设置为0sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.eth0.rp_filter0但这里我要提醒一句rp_filter是Linux抵御IP欺骗攻击的重要机制生产环境把它关掉要评估安全风险最好只对出问题的接口单独关闭而不是全局一刀切。我的习惯是先确认丢包确实和rp_filter有关再动手改。4.4 策略路由的推荐写法解决多网段多IP的默认路由冲突标准方案是策略路由。以eth0绑了两个网段IP为例假设网卡上绑了192.168.1.10/24主地址和10.0.0.10/24两个网段的网关分别是192.168.1.1和10.0.0.1期望的行为是源IP为10.0.0.10的出口流量走10.0.0.1源IP为192.168.1.10的流量走192.168.1.1。先创建两张独立路由表可以写在/etc/iproute2/rt_tables里echo 100 net_wan1 /etc/iproute2/rt_tables echo 200 net_wan2 /etc/iproute2/rt_tables然后添加策略路由规则ip rule add from 10.0.0.10 lookup 100 ip rule add from 192.168.1.10 lookup 200 ip route add default via 10.0.0.1 dev eth0 table 100 ip route add default via 192.168.1.1 dev eth0 table 200 ip route flush cache验证一下ip route get 223.5.5.5 from 10.0.0.10 ip route get 223.5.5.5 from 192.168.1.10输出里应该能看到分别走了10.0.0.1和192.168.1.1。要把这些规则做成永久生效可以在/etc/rc.local里追加systemd系统需要启用rc-local.service或者用NetworkManager的dispatcher脚本、netplan的post-up命令。不同发行版做法略有差异但核心的ip rule和ip route命令是通用的。5. 一次单网卡双IP故障的完整排查过程5.1 故障现象去年我处理过一个真实故障很典型。一台Ubuntu 20.04服务器网卡ens33通过netplan配置绑了两个IP192.168.1.10/24和10.0.0.10/24。配置完成后从公司内网能ping通192.168.1.10业务服务也正常但另一个网段的同事反馈怎么都ping不通10.0.0.10。我登录服务器先用ip addr确认IP状态ip addr show dev ens33输出显示两个IP都在状态是UP看起来没有任何异常。5.2 排查链路第一步检查服务监听。ping不通可能和服务无关但为了排除干扰我先确认没有防火墙拦截ICMPiptables -L -n | grep icmp # 没有相关规则然后验证源IP到网关的连通性ping -I 192.168.1.10 192.168.1.1 # 通 ping -I 10.0.0.10 10.0.0.1 # 不通这就是关键线索。两个IP在同一张网卡上一个能通一个不能通说明问题不在网卡物理链路而在路由或ARP。查看路由表ip route show输出里只有一条默认路由default via 192.168.1.1 dev ens33问题浮出水面了。10.0.0.10这个IP的流量回包时对端会尝试路由到10.0.0.0/24网段但本机默认路由走的是192.168.1.1源和路由完全不匹配。接着检查ARP和rp_filter状态sysctl net.ipv4.conf.all.rp_filter # 输出1启用了严格模式 sysctl net.ipv4.conf.all.arp_ignore # 输出0表示默认宽松到这里基本确定了三层因素叠加默认路由缺失导致10.0.0.10的包出不去或者回不来rp_filter严格模式可能进一步丢弃了非对称路径的包ARP响应策略宽松可能导致网关学到的ARP表项不稳定。5.3 修复与验证我做了三件事。第一配置策略路由给10.0.0.10单独一张路由表走10.0.0.1网关ip rule add from 10.0.0.10 lookup 100 ip route add default via 10.0.0.1 dev ens33 table 100 ip route flush cache第二调整ARP参数避免跨网段响应混乱sysctl -w net.ipv4.conf.all.arp_ignore1 sysctl -w net.ipv4.conf.all.arp_announce2第三由于这台机器的网络拓扑里确实存在非对称回程路径我把ens33的rp_filter临时调成0观察一段时间后确认没有安全异常再写入sysctl配置永久保留sysctl -w net.ipv4.conf.ens33.rp_filter0再次验证ping -I 10.0.0.10 10.0.0.1 # 通了同事那边再ping 10.0.0.10也通了。整个排查链路下来耗时大概半小时核心结论就是要同时关注IP是否生效、默认路由是否匹配源地址、ARP和rp_filter是否干扰了双向通行。这个案例给我最大的启示是单网卡多IP看着是个配置问题实际上是个路由问题。大部分绑了IP但不通的故障都可以从源地址出得去、回包进得来这个角度去拆解而不是反复怀疑网卡坏了。最后再分享一个我自己的小习惯。每次给网卡添加新的IP之前我都会先把现有配置完整备份一遍无论是netplan的yaml文件还是ifcfg文件都随手复制一份带时间戳的备份。操作完以后执行ip addr和ip route get验证并且在心里过一遍如果重启这些配置还在吗这个问题。这些看起来很基础的动作真的能帮你省掉大量不必要的深夜排障时间。
返回列表