使用 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 地址。