TLDR

  1. 裸金属服务器 链路聚合 配置
  2. 裸金属服务器 链路聚合+VLAN 配置
  3. 裸金属服务器 链路聚合+VLAN+Bridge 配置
  4. 裸金属服务器 衍生实践推荐

前言

我已很久没写博客。

迟迟不想动笔,原因有二。 其一,技术类的很多问题 OpenAI 的 ChatGPT 都有完美的回答,我再重复略显多余。 其二,疲惫让我无法静心思考,我不知道我应分享什么,因此也找不到动笔的动力。

坐在书店里,避开了回乡的人来人往,咖啡、音乐、落日(即将到来)。麻木之后重新感受到的片刻美好,让我重拾了动力。 我想就记录一点工作遇到的问题吧,或许有人也会遇到呢也说不定。

内网带宽瓶颈

公司有基于开源文生文(图)模型的服务,这些服务的模型数据少的有 60G、多的有 100+G。 模型存储在另外一个服务器上,通过 NFS 同时为内网多台 GPU 服务器提供模型数据。如果按千兆交换机的速率计算, 100G 的数据需要 13.5 分钟才能完成一次完整的模型数据读取,10 个 GPU 服务全部启动完毕,需 135 分钟(2个多小时)。

为了避免 NFS 服务瓶颈导致的启动慢问题,可使用链路聚合(LACP)来解决。链路聚合可将两个网卡合并成一个,从而获得两个累加后的带宽。比如 NFS 服务器上有两个千兆的网口,通过配置链路聚合, 可让该服务器具备两千兆的内网带宽,在多服务同时启动时实现总启动时间减少一半的效果(这里只是举例说明,裸金属服务器实际上是单口 25G)。

下面给出具体的 systemd networkd 配置,假设两个物理网口是 eth0、eth1。

# /etc/systemd/network/1-eth0.network
[Match]
Name=eth0

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/1-eth1.network
[Match]
Name=eth1

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/5-bond0.netdev
[NetDev]
Name=bond0
Kind=bond

[Bond]
Mode=802.3ad
TransmitHashPolicy=layer3+4
MIIMonitorSec=0.1s
LACPTransmitRate=fast
UpDelaySec=0.2s
DownDelaySec=0.2s
# /etc/systemd/network/5-bond0.network
[Match]
Name=bond0

[Link]
MTUBytes=9000

[DHCPv4]
UseDNS=false

[DHCPv6]
UseDNS=false

[IPv6AcceptRA]
UseDNS=false

[Network]
BindCarrier=eth0 eth1
Gateway=172.16.160.254
Domains=jinmiaoluo.com.
DNS=223.5.5.5#dns.alidns.com
DNS=223.6.6.6#dns.alidns.com
DNSOverTLS=true

[Address]
Address=172.16.160.12/24

经过上面的配置,这台服务器就具备了两倍的内网并发带宽了。

内网隔离

继续展开。我们的服务器是跟裸金属服务器提供商直接整台租赁的,机房侧为了避免内网风险,通过 VLAN 隔离了不同公司的裸金属服务器。因此在配置链路聚合的同时我们还需要配置 VLAN。下面给出具体的配置:

# /etc/systemd/network/1-eth0.network
[Match]
Name=eth0

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/1-eth1.network
[Match]
Name=eth1

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/5-bond0.netdev
[NetDev]
Name=bond0
Kind=bond

[Bond]
Mode=802.3ad
TransmitHashPolicy=layer3+4
MIIMonitorSec=0.1s
LACPTransmitRate=fast
UpDelaySec=0.2s
DownDelaySec=0.2s
# /etc/systemd/network/5-bond0.network
[Match]
Name=bond0

[Link]
MTUBytes=9000

[Network]
VLAN=vlan500
BindCarrier=eth0 eth1
# /etc/systemd/network/10-vlan500.netdev
[NetDev]
Name=vlan500
Kind=vlan

[VLAN]
Id=500
# /etc/systemd/network/10-vlan500.network
[Match]
Name=vlan500

[Link]
MTUBytes=9000

[DHCPv4]
UseDNS=false

[DHCPv6]
UseDNS=false

[IPv6AcceptRA]
UseDNS=false

[Network]
Gateway=172.16.160.254
Domains=jinmiaoluo.com.
DNS=223.5.5.5#dns.alidns.com
DNS=223.6.6.6#dns.alidns.com
DNSOverTLS=true

[Address]
Address=172.16.160.12/24

经过上面的配置,当前服务器就可以正常与内网其他服务器通信了。

虚拟化网桥

继续展开。配置好了链路聚合和 VLAN 后,为了避免裸金属服务器资源浪费,这里部署虚拟化(参考这篇文章)。为了让虚拟机获得裸金属服务器所在局域网网段的 IP,这里要配置网桥。配置如下:

# /etc/systemd/network/1-eth0.network
[Match]
Name=eth0

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/1-eth1.network
[Match]
Name=eth1

[Link]
MTUBytes=9000

[Network]
Bond=bond0
# /etc/systemd/network/5-bond0.netdev
[NetDev]
Name=bond0
Kind=bond

[Bond]
Mode=802.3ad
TransmitHashPolicy=layer3+4
MIIMonitorSec=0.1s
LACPTransmitRate=fast
UpDelaySec=0.2s
DownDelaySec=0.2s
# /etc/systemd/network/5-bond0.network
[Match]
Name=bond0

[Link]
MTUBytes=9000

[Network]
VLAN=vlan500
BindCarrier=eth0 eth1
# /etc/systemd/network/10-vlan500.netdev
[NetDev]
Name=vlan500
Kind=vlan

[VLAN]
Id=500
# /etc/systemd/network/10-vlan500.network
[Match]
Name=vlan500

[Network]
Bridge=virbr0
# /etc/systemd/network/15-virbr0.netdev
[NetDev]
Name=virbr0
Kind=bridge

[Bridge]
STP=yes
# /etc/systemd/network/15-virbr0.network
[Match]
Name=virbr0

[Network]
Gateway=172.16.160.254
Domains=jinmiaoluo.com.
DNS=223.5.5.5#dns.alidns.com
DNS=223.6.6.6#dns.alidns.com
DNSOverTLS=true

[Address]
Address=172.16.160.12/24

经过上面的调整,我们就可以在链路聚合和 VLAN 的基础上创建多台具备内网 IP 的虚拟机了(虚拟机网络模式选择 bridge 模式即可)。

成为云服务器

虚拟化就绪后,为了让虚拟机成为一台“云服务器”(具备公网 IP 的虚拟机),只需在 NAT 设备上配置好映射即可。

NAT 设备会将特定公网 IP 的流量全部映射到内网 IP,这也是为什么需要通过网桥,给虚拟机分配内网 IP(裸金属服务器所在局域网网段)的原因。

为什么虚拟化

裸金属服务器的性能是普通的云服务器很多倍。比如我们的测试服:

CPU: Intel Xeon Platinum 8352V * 2 (72 个物理核心、144 个虚拟核心)
MEM:512G
GPU:4090 * 8
NET: 25G * 2(LACP)

直接作为单一服务器使用,会造成资源浪费。通过虚拟化,一来,提高资源利用率(考虑到多数服务平时没有负载)。二来,通过虚拟化隔离资源,避免单一进程造成的资源分配不均(比如显卡,通过显卡直通,将显卡隔离在独立的虚拟机中)。

衍生实践

结合旧文:

即可满足如下场景的需求:

  1. 私有化部署一些开源大语言模型。因为物理服务器有很多显卡,所以可以私有化部署来提升本地的开发效率,比如:

    1. 通过 open-webui 实现 UI 访问
    2. 通过 continue(一个 vscode 插件)实现代码分析
    3. 通过 沉浸式翻译(一个浏览器插件)实现高效的翻译体验
  2. 公有云服务下云。租赁物理服务器后基于虚拟化和 NAT,可自行创建具备公网 IP 的虚拟机(类似云服务器)。

  3. 跨城办公组网。虚拟化为常见的服务(比如:GitLab、K8s)提供运行环境后,WireGuard 则用于打通局域网,常见的场景比如:

    1. 前后端跨城联调。基于 WireGuard 组 VPN 网络。
    2. 开发者访问 K8s SVC IP。局域网互通,基于 Linux 封包转发 + 静态路由。
    3. 内部服务的部署与公网隔离。将服务部署到虚拟机中,然后通过防火墙服务(比如:GitLab,Ollama Server)只有连接了 VPN 用户,即只有公司内部用户才能访问。
  4. 透明代理服务。开发环境免不了访问国外的站点,外网访问慢会影响开发效率。

    常见的问题:

    • 大语言模型下载慢问题
    • docker 镜像拉取慢问题
    • npm/pip/go 依赖包下载慢的问题

    解决思路:

    • 基于虚拟化创建虚拟机
    • 部署 xray(基于透明代理方案)作为内网的旁路由网关(假设该虚拟机内网 IP 为 x.x.x.x )
    • 其他的虚拟机和裸金属服务器通过静态 IP 的方式配置网关地址为 x.x.x.x,这些虚拟机和裸金属服务器即可实现外网加速

总结

这是一篇通过 systemd networkd 配置裸金属服务器网络的文章,并在此基础上提供了部署虚拟化所需的网桥的相关配置。除了结合衍生部分的内容,相信你还可以发现更多有趣的实践(比如:NatMap,让你在异地能以家庭带宽峰值,直连家庭局域网中的任何设备,这个就留给主动的你自己去探索了)。

大年初二,于广州 1200bookshop。斜阳好美,新年快乐。