如何在 Docker 容器内使用 LTE 接口?

如何在 Docker 容器内使用 LTE 接口?

对于我的客户,我必须在单独的机器上设置 docker 容器,这些机器在不同的物理链路上运行不同的服务。

我无法对我的 Docker 容器使用“主机”模式。

到目前为止,我很高兴使用 macvlan 驱动程序在我的容器中生成新的网络接口。

例如:

networks:
  good_net:
    driver: macvlan
    driver_opts:
      parent: eno0
  slow_net:
    driver: macvlan
    driver_opts:
      parent: eno0
  high_latency_net:
    driver: macvlan
    driver_opts:
      parent: eno0

我在容器启动时有一个脚本,它执行以下操作:

  • 给出唯一的 mac 地址
  • 培养
  • dhcp 或静态地址
  • 应用 tc 过滤器来调整每个网络的流量

运行良好:我可以在各个链接上运行 ping 和 iperf3 来测试它们是否按预期工作。

问题:现在真正的接口正在出现,它们破坏了我的设置。

其中一个链接现在是 LTE。

lte_net:
  driver: macvlan
  driver_opts:
    parent: lte0

在 PC1(主机,不是容器)上:

4: lte0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
   link/ether 7e:c4:d2:6a:e3:07 brd ff:ff:ff:ff:ff:ff
   inet 10.0.250.1/30 brd 10.0.250.3 scope global noprefixroute lte0
      valid_lft forever preferred_lft forever

在 PC2(主机,不是容器)上:

4: lte0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
   link/ether b6:30:cb:12:31:16 brd ff:ff:ff:ff:ff:ff
   inet 10.0.250.5/30 brd 10.0.250.7 scope global noprefixroute lte0
      valid_lft forever preferred_lft forever

主机可以通过 LTE 链路顺利地 ping 和 iperf3 彼此。

但是:在容器中使用 macvlan 方法,它们不能:

  • 我给每个容器中的接口分配一个位于同一子网的 IP 地址:10.100.10.1/24 和 10.100.10.2/24
  • 我已经关闭了所有其他接口,所以只剩下一条路由:10.100.10.0/24 dev lte0 proto kernel scope link src 10.100.10.1
  • 从 pc1 上的容器,我尝试 ping pc2 上容器中 LTE 接口的 IP
  • 使用主机上的 tcpdump,我可以看到 lte 接口上的 ARP 数据包: 02:2d:6d:ad:63:62 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has 10.100.10.2 tell 10.100.10.1, length 28

但是我看不到它们到达 pc2,甚至没有到达主机级别。

原因很可能是来自 LTE 调制解调器无法识别的 MAC 地址的数据包被丢弃。这与 WLAN 的情况类似。

因此我尝试使用 ipvlan l2,正如有时看到的建议:

lte_net:
  driver: ipvlan
  driver_opts:
    ipvlan_mode: l2
    parent: lte0

容器中的 lte0 接口和主机上的父接口具有相同的 MAC 地址。但是没有变化:仍然无法跨越 LTE...

ipvlan l3 甚至没有出现,但无论如何我认为这不是我需要的。

所以我的问题是:我做错了什么? 如何正确访问我的物理 LTE 作为 Docker 容器中 IP 流量的网络接口?

对于 3G 标记,我感到抱歉:我没有足够的声誉来创建 LTE 标记......

谢谢 !

答案1

我终于找到了一个可行的解决方案......但我却遭受了痛苦......并且学到了......

我现在有一个围绕“docker-compose up -d”的包装脚本和一个万能的docker-compose.yml,可以启动4个(我不需要更多)默认docker网络。

它看起来像这样:

network:
  test_net0:
  test_net1:
  test_net2:
  test_net3:

当启动时,这将为每个 test_netX 创建:

  • 一个 veth 对:一个在容器命名空间中,一个在默认主机命名空间中
  • 一座桥:奴役了主机端的 veth

对于主机上的标准 eth 接口,没有问题:只需将其奴役到您选择的桥接器即可。我可以用同样的方式奴役几个 USB 以太网适配器,没有任何问题。这是在 bash 中完成的(现在我真的希望我们从 python 开始),奴役是在使用 netns 的 iproute2 命令“up”之后完成的。

对于 LTE,事情变得更加复杂。首先,LTE 接口不会让自己被正确奴役。其次,虽然我们找不到有关它的文档,但经过大量实验后,我们发现在 2 个主机上看到的 LTE 接口之间存在一些丢弃操作:

  • 任何源 IP 或目标 IP 不在“LTE 网络”中的数据包
  • (不确定,但怀疑)任何源或目标 MAC 地址与我们的 LTE 接口不同的数据包(顺便说一下,这些地址似乎是由驱动程序动态分配的,以使事情变得更有趣)

基本上,我们的 LTE 设置仅从 LTE 接口传输数据包或向 LTE 接口传输数据包。

因此,我们有了一个绝妙的想法:让我们直接通过 LTE 隧道传输我们的流量。我们从 ipip 隧道开始,但很快意识到我们邀请了一头大象来参加野餐,因为我们需要通过 LTE 在容器之间进行多播,如果你有一百年的空闲时间,这可能是可行的……

然后,当我们在 LTE 链路上设置 GRETAP 而不是 ipip 隧道时,事情终于有了转机。这样做的一大优势是 GRETAP 接口可以被控制,并且其行为就像标准以太网接口一样。

一旦我们修复了多播数据包上过低的 TTL,我们就可以通过 LTE 链路在容器之间顺利运行所有类型的流量。

现在看起来非常简单而且合乎逻辑...

Linux、iproute2、docker,你们愿意嫁给我吗?

相关内容