WSL2 两个独立的 Centos 发行版具有相同的 eth0 inet 地址

WSL2 两个独立的 Centos 发行版具有相同的 eth0 inet 地址

使用 Windows Subsystem for Linux 2,我想运行两个单独的 Centos 7 实例,但当我这样做时,两个实例都具有相同的 eth0 inet 地址。这是我所做的...

我为我的基础创建了一个基本的 Centos 7 tarball,然后创建了两个独立的发行版,并且一切看起来和运行起来都如我预期的那样;

    > wsl --import centos7-1 centos7-1 centos7.tar.gz --version 2
    > wsl --import centos7-2 centos7-2 centos7.tar.gz --version 2
    > wsl -l -v
      NAME                   STATE           VERSION
    * centos7-1              Stopped         2
      centos7-2              Stopped         2
    > ls
        Directory: C:\Users\me\centos
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    d-----          4/8/2022  11:28 AM                centos7-1
    d-----          4/8/2022  11:29 AM                centos7-2
    -a----          4/8/2022  11:24 AM      174323670 centos7.tar.gz

除了当我在单独的 PS 窗口中打开并运行每个发行版并ifconfig eth0在每个窗口中运行时,它们都显示相同的 eth0 inet 地址。

那么,我遗漏了什么?如何让它们拥有独立的 IP 地址?

自从我第一次发布帖子以来,我注意到,即使不同 Linux 发行版(例如 Ubuntu)的实例与 Centos 同时运行,也都会获得相同的 IP 地址。

答案1

@DanielB 的回答很好地解释了为什么所有 WSL2 发行版(我喜欢称它们为“实例”)共享相同的地址。

每个 WSL2 实例都有一个单独的:

  • PID 命名空间
  • 挂载命名空间
  • IPC 命名空间
  • UTS 命名空间
  • WSLg 系统分布

但是,它们都与父 WSL2 VM 共享以下内容(因此彼此也共享):

  • 用户命名空间
  • (我们真正关心的唯一一个)网络命名空间
  • Cgroup 命名空间
  • 设备树(除 以外/dev/pts
  • CPU/内核/内存/交换(显然)
  • /init二进制(但不是进程)

有趣的是,我们可以使用相同的技术,命名空间,来“假装”为每个实例创建一个单独的 IP 地址。

对于您在评论中提到的“n 层测试”场景,希望这足够了。我们可以为每个实例编写命名空间的创建脚本,并(可选)通过命令wsl行自动输入它。

虽然我预感到这会奏效,但在尝试之前我从未尝试过网络命名空间。别担心 - 这对我来说是一个值得学习的练习。这篇博文帮我完成了 90%。

话虽如此,这是第一次(或第二次,或第三次......)传递脚本来配置网络命名空间,以允许每个实例中的每个命名空间拥有不同的 IP。

创建如下内容/usr/local/sbin/wsl-netns.sh

#!/usr/bin/env bash
instance_num=$1
#if [ -e /run/netns/]

# Create the bridge that will be common to all instances.
# Only a `wsl --shutdown` will terminate the bridge, unless
# otherwise manually removed.
if [ ! -e /sys/devices/virtual/net/br1 ]
then
    ip link add name br1 type bridge
    ip addr add 10.0.0.253/24 brd + dev br1
    ip link set br1 up
fi

# Add namespace for this instance
if [ ! -e /run/netns/vnet${instance_num} ]
then
    ip netns add vnet${instance_num}
fi

# Adds a veth pair.  The vethX
# side will reside # inside the namespace 
# and be the primary NIC inside that namespace.
# The br-vethX  end will reside in the primary
# namespace.
ip link add veth${instance_num} type veth peer name br-veth${instance_num}
ip link set veth${instance_num} netns vnet${instance_num}
# Give it a unique IP based on the instance number
ip netns exec vnet${instance_num} \
    ip addr add 10.0.0.${instance_num}/24 dev veth${instance_num}
ip link set br-veth${instance_num} up
# Add the bridged end of the veth pair
# to br1
ip link set br-veth${instance_num} master br1
ip netns exec vnet${instance_num} \
    ip link set veth${instance_num} up

# Set the default route in the namespace
ip netns exec vnet${instance_num} \
    ip route add default via 10.0.0.253
# Enable loopback fort he namespace
ip netns exec vnet${instance_num} \
    ip link set up dev lo
# Set up NAT for return traffic
iptables \
    -t nat \
    -A POSTROUTING \
    -s 10.0.0.0/24 \
    -j MASQUERADE
# Enable forwarding
sysctl -w net.ipv4.ip_forward=1

# Optional - Start a namespace for the 
# default WSL user (UID 1000).
# You can exit this namespace normally
# via the `exit` comamnd or Ctrl+D.
default_username=$(getent passwd 1000 | cut -d: -f1)
nsenter -n/var/run/netns/vnet${instance_num} su - $default_username

目前没有太多的错误处理,但它相当简单。将其设置为可执行文件并从实例中运行它:

/usr/local/sbin/wsl-netns.sh 1 # replace with the instance number

或者通过以下方式直接启动 WSL:

wsl ~ -d centos7-1 -u root -e sh -c "/usr/local/sbin/wsl-netns.sh 1"

只需确保每个实例使用唯一的实例编号即可。每个实例/命名空间的地址将是10.0.0.<instance_number>,您可以从任何其他 WSL2 实例访问它。

要进行测试,请在其中一个命名空间内启动一个简单的服务。例如,如果您处于脚本带您进入的命名空间中,您可以运行:

python3 -m http.server

然后您可以从另一个实例访问该服务器10.0.0.1:8000。您将无法通过任何其他 IP 访问该服务。

或者,你不必使用nsenter放入命名空间。你可以直接通过以下方式在其中启动服务:

sudo ip netns exec vnet<num> \
    service xyz start

或者无论您的启动命令是什么。

附加奖励:

  • 由于您没有离开内部 WSL2 网络,因此 IPv6 可以正常工作。

限制:

  • 在 Ubuntu 上测试 - 可能需要针对 CentOS 进行小幅调整。
  • 您无法从 Windows 访问这些 IP 地址,只能从其他 WSL2 实例访问。您需要添加其他转发规则来处理此问题。
  • 目前,所有通信都是通过地址进行的。如果您想分配主机名,则需要覆盖 WSL 的自动/etc/hosts生成并定义自己的主机名。或者当然通过 DNS 进行设置。

答案2

WSL 2 发行版都位于同一个网络命名空间中。

您可能熟悉 Docker,也可能不熟悉。WSL 2 的内部工作原理非常相似。WSL 2 在虚拟机中运行,运行在真实的 Linux 内核上。所有 WSL 发行版都共享同一个虚拟机。这通过使用不同的容器每一个都是独立的。它们在各个方面都是独立的:每个发行版对进程 ID 和文件系统都有不同的看法。但它们对网络接口的看法相同。

您不能让它们拥有不同的 IP 地址。这也是(大部分情况下)无关紧要的,因为您只能在本地计算机上分辨出差异。在外部,它们是NAT编辑为您的 PC 的 IP 地址。

相关内容