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

CAB*_*CAB 12 windows-subsystem-for-linux wsl2

使用 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
Run Code Online (Sandbox Code Playgroud)

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

那么,我错过了什么?如何让他们拥有独立的IP地址?

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

Not*_*1ds 12

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

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

  • PID命名空间
  • 挂载命名空间
  • IPC命名空间
  • 悉尼科技大学命名空间
  • 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
Run Code Online (Sandbox Code Playgroud)

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

/usr/local/sbin/wsl-netns.sh 1 # replace with the instance number
Run Code Online (Sandbox Code Playgroud)

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

wsl ~ -d centos7-1 -u root -e sh -c "/usr/local/sbin/wsl-netns.sh 1"
Run Code Online (Sandbox Code Playgroud)

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

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

python3 -m http.server
Run Code Online (Sandbox Code Playgroud)

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

或者,您不必使用nsenterdrop into 命名空间。您可以通过以下方式直接启动其中的服务:

sudo ip netns exec vnet<num> \
    service xyz start
Run Code Online (Sandbox Code Playgroud)

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

额外奖励:

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

限制:

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


Dan*_*l B 8

WSL 2 发行版都驻留在同一网络命名空间中。

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

您不能让它们具有不同的 IP 地址。它(大部分)也是无关紧要的,因为您只能在本地计算机上分辨出差异。在外部,它们通过NAT连接到您 PC 的 IP 地址。

  • 我认为这与Docker不同。在 Docker 中,每个容器都有自己的内部 IP 地址。这非常重要,因为您需要能够在容器之间进行通信。 (3认同)